GNU ld - Unterschiedliches Section und File alignment für PE+ (EFI Applikation)

OP #8049528
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

OP #8049603
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

(Firma: Universität Tartu) #8049815
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren