Forum: Compiler & IDEs GNU ld - Unterschiedliches Section und File alignment für PE+ (EFI Applikation)


von Johannes (jk1983)


Lesenswert?

Hallo Community!

Wie kann man im GNU Linker Script ein unterschiedliches Section und 
Datei Alignment erzielen? Würde es für eine EFI Applikation benötigen. 
Hier wird ja das PE+ (Microsoft's Portable Executable Format) verwendet. 
Dieses kennt ja beide Alignment Typen:
1
/**
2
 * PE+: Optional header Windows-specific fields
3
 */
4
header_win:
5
    .quad 0                                 /* ImageBase */
6
    .word 0x1000                            /* SectionAlignment */
7
    .word 0x1000                            /* FileAlignment */

Folgendes simple Linker Script verwende ich derzeit:
1
OUTPUT_FORMAT(elf64-littleriscv)
2
3
ENTRY(_start)
4
5
SECTIONS {
6
    . = 0x0;
7
    _image_s = .;
8
9
    .peheader : {
10
        KEEP(*(.peheader))
11
    }
12
13
    .text : ALIGN(0x1000) {
14
        _text_s = .;
15
        *(.text)
16
        *(.text*)
17
        _text_e = .;
18
    }
19
20
    .reloc : ALIGN(0x1000) {
21
        _reloc_s = .;
22
        *(.reloc)
23
        *(.reloc*)
24
        _reloc_e = .;
25
    }
26
27
    .rodata : ALIGN(0x1000) {
28
        _rodata_s = .;
29
        *(.rodata)
30
        *(.rodata*)
31
        _rodata_e = .;
32
    }
33
34
    _image_e = .;
35
36
    /DISCARD/ : {
37
        *(.note)
38
        *(.note.*)
39
        *(.header)
40
    }
41
}

Bei großen Programmen, fällt das nicht so ins Gewicht. Aber bei einem 
simplen "Hello World!" Programm hat die Datei schon mal 12KiB an Größe. 
Hier für RISC-V:
1
.set EFI_SUCCESS, 0
2
3
/**
4
 * .text Section
5
 */
6
.text
7
8
/**
9
 * Main entry point of the application
10
 *
11
 * Simple outputs the string "Hello World!" on the EFI console
12
 * and exists.
13
 */
14
.global _start
15
.func _start
16
.type _start,%function
17
_start:
18
    addi sp, sp, -16
19
    sd ra, 8(sp)
20
    sd fp, 0(sp)
21
    addi fp, sp, 16
22
23
    /**
24
     * Save address of EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL from
25
     * EFI_SYSTEM_TABLE to register A0.
26
     */
27
    ld a0, 64(a1)
28
29
    /**
30
     * Save address of EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL->OutputString()
31
     * to register T0.
32
     */
33
    ld t0, 8(a0)
34
35
    /**
36
     * Load address of string 'string_hello' into register A1.
37
     */
38
    la a1, string_hello
39
40
    /**
41
     * Call/Invoke EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL->OutputString()
42
     */
43
    jalr t0
44
45
    li a0, EFI_SUCCESS
46
47
    ld ra, 8(sp)
48
    ld fp, 0(sp)
49
    addi sp, sp, 16
50
    ret
51
.endfunc
52
53
/**
54
 * .rodata Section
55
 */
56
.section .rodata
57
58
/* UTF-16LE (CHAR16) encoded output string */
59
string_hello:
60
.byte 'H'
61
.byte 0
62
.byte 'e'
63
.byte 0
64
.byte 'l'
65
.byte 0
66
.byte 'l'
67
.byte 0
68
.byte 'o'
69
.byte 0
70
.byte ' '
71
.byte 0
72
.byte 'W'
73
.byte 0
74
.byte 'o'
75
.byte 0
76
.byte 'r'
77
.byte 0
78
.byte 'l'
79
.byte 0
80
.byte 'd'
81
.byte 0
82
.byte '!'
83
.byte 0
84
.byte '\r'
85
.byte 0
86
.byte '\n'
87
.byte 0
88
.byte 0
89
.byte 0

Then vollen Code findet man unter meinen GitHub repo:

https://github.com/Krotti83/EFI-bare-metal-riscv64
von Manuel H. (Firma: Universität Tartu) (xenos1984)


Lesenswert?

Ohne es ausprobiert zu haben: ld hat Kommandozeilen-Optionen 
--file-alignment und --section-alignment, die genau das tun sollten:

http://sourceware.org/binutils/docs/ld/Options.html

Im Linker Script ist mir nichts in der Richtung bekannt.
von Johannes (jk1983)


Lesenswert?

Danke für die Information!

Manuel H. schrieb:
> Ohne es ausprobiert zu haben: ld hat Kommandozeilen-Optionen
> --file-alignment und --section-alignment, die genau das tun sollten:

Hab es mal kurz ausprobiert, aber leider kennt die RISC-V Variante 
(riscv64-unknown-linux-gnu-) the beiden CLI Argumente nicht. :(
1
$ make
2
   [LD]        hello.elf
3
/cross/gnu/riscv/bin/riscv64-unknown-linux-gnu-ld: unrecognized option '--file-alignment'
4
/cross/gnu/riscv/bin/riscv64-unknown-linux-gnu-ld: use the --help option for usage information
5
make: *** [Makefile:63: efiapp] Error 1

In deinem Link (Doku von GNU ld) steht leider nur was von i386 PE's:

> 2.1.1 Options Specific to i386 PE Targets
von Manuel H. (Firma: Universität Tartu) (xenos1984)


Lesenswert?

Ach richtig, RISC-V, das hatte ich übersehen. Aber dein ld ist ja auch 
für ELF Target (riscv64-unknown-linux-gnu-), das versteht doch ohnehin 
nichts von den PE-spezifischen Optionen und vom PE+ Header, den du 
manuell in Assembler erzeugst? Deinem Makefile nach erzeugst du ja das 
PE+ mittels objcopy als reine Binärdatei, und in dem Fall wird der 
gesamte Inhalt (inkl. Alignment) durch den Inhalt der Sektionen und 
deren Startadressen bestimmt.

Ich habe PE bisher nur für i386 / x86_64 benutzt und dann binutils mit 
entsprechendem -pe Target kompiliert. Für RISC-V bräuchte man wohl sowas 
wie riscv64-w64-mingw32. Aber ob das dann die genannten i386 PE Optionen 
versteht, ist zweifelhaft. Könnte sein, dass es inzwischen implementiert 
wurde und die Dokumentation hinterherhinkt, oder auch nicht. Im 
letzteren Fall bleibt dann eben nur dein bisheriger Weg, den Header 
manuell zu erzeugen, aber da helfen ld Optionen dann nur sehr begrenzt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.