That's going to be a long one, so grab some coffee / tea / yerba.
How to tell / force GNU ld to put a section/symbol in a specific part of the output ELF file?
Specifically, I'm not asking about the physical/load address of the symbol but about the offset within the file.
I'm trying to take a real world BSD kernel and make it compatible with
Multiboot and bootable by GRUB.
In order to make an ELF image compatible with Multiboot and identifiable
by GRUB one needs to embed a magic number (0x1BADB002
) into the first
8KiB of the file.
I'm referring to Multiboot 0.6.96.
As the original kernel is quite a big piece of code,
I'm going to use examples based on the Bare Bones kernel from OSDev wiki.
As that kernel already is Multiboot compliant, I'm going to use an
extra_symbol
with value 0xCAFEBABE
as the example for my question.
boot.s
contains:
.set CAFEBABE, 0xCAFEBABE
; ... snip ...
.section .extras
extra_symbol:
.long CAFEBABE
.text
The easiest option would be to put a symbol with that value into .text
section just before anything else:
.text BLOCK(4K) : ALIGN(4K)
{
*(.extras)
*(.multiboot)
*(.text)
}
That's fine for the example, but in case of the real BSD kernel .text
starts way after 0x2000 (8KiB) in the file. This approach is not an option.
.text
?Another option is to put the whole .extras
section before .text
.
In my naivety, I hoped that putting such a section before .text
in the
linker script would also make it appear earlier in the output ELF:
SECTIONS
{
// ... some stuff ...
.extras : { *(.extras) }
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
// ... more stuff ...
}
That's not the case, though:
$ i586-elf-readelf -S myos.bin
There are 10 section headers, starting at offset 0x6078:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .extras PROGBITS 00100000 006010 000004 00 0 0 1
[ 2] .comment PROGBITS 00000000 006014 000011 01 MS 0 0 1
[ 3] .text PROGBITS 00001000 001000 0001e4 00 AX 0 0 4096
[ 4] .rodata.str1.1 PROGBITS 000011e4 0011e4 000016 01 AMS 0 0 1
[ 5] .eh_frame PROGBITS 000011fc 0011fc 000104 00 A 0 0 4
[ 6] .bss PROGBITS 00002000 002000 004010 00 WA 0 0 4096
[ 7] .shstrtab STRTAB 00000000 006025 000050 00 0 0 1
[ 8] .symtab SYMTAB 00000000 006208 000210 10 9 19 4
[ 9] .strtab STRTAB 00000000 006418 000130 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
In fact, the section comes first in the section header table, but its
offset in the file (0x6010
) is way after .text
. In fact, it comes even
after .bss
.
The ELF specification explicitly states that:
Although the figure shows the program header table immediately after the ELF header, and the section header table following the sections, actual files may differ. Moreover, sections and segments have no specified order. Only the ELF header has a fixed position in the file.
How do I make use of that and tell GNU ld to place my extra_symbol
(probably the whole .extras
section) before any other section in the file,
preferably just after the ELF header?
In order to put the section before .text
, have you already tried to make it allocated (A
) and executable (X
)?
If the .interp
hack works, then that's fine as well, of course.