1

I am trying to craft a linker-command script to be bootable by legacy grub (using multiboot). I am having difficulty getting the multiboot header in the required location (within the first 8192 bytes). My script looks something like:

SECTIONS
{
    .multiboot :
    {
        __multiboot_header = .;
        *(.multiboot)
    }

    .text 0x00100000 :
    {
        *(.text*)
        *(.rodata)
    }

    /* ... remainder of script ... */
}

Overall, my objective is to have my custom executable loaded by the bootloader after the first 1MiB of physical memory; the address as part of the .text section declaration seems to have done this as I expected. Reading the ELF header gives the entry point as:

$ readelf -h kernel.elf | grep Entry
  Entry point address:               0x100000

However, in doing so I seem to have also increased the file by this much.

$ ls -l file.elf
-rwxr-xr-x 1 user user 1049960 May 13 02:20 file.elf

The area between the ELF header and the .text section is initialized to zeros.

$ hexdump -C file.elf
00000000  7f 45 4c 46 01 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  02 00 03 00 01 00 00 00  00 00 10 00 34 00 00 00  |............4...|
00000020  00 04 10 00 00 00 00 00  34 00 20 00 02 00 28 00  |........4. ...(.|
00000030  09 00 08 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 f8 00 10 00  f8 f0 4e 00 07 00 00 00  |..........N.....|
00000050  00 00 20 00 51 e5 74 64  00 00 00 00 00 00 00 00  |.. .Q.td........|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 07 00 00 00  |................|
00000070  10 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000  8b 25 f8 f0 4e 00 50 53  e8 66 00 00 00 fa f4 eb  |.%..N.PS.f......|
00100010  fc 55 89 e5 53 83 ec 10  c7 45 f8 00 00 00 00 eb  |.U..S....E......|
00100020  38 a1 f4 00 10 00 8b 55  f8 01 d2 01 d0 8b 15 f4  |8......U........|

Also, although readelf -s reports that __multiboot_header has a value of 0x0 (which should be the address of the structure since it was defined at the same point it was mentioned in the linker file, right?):

$ readelf -s kernel.elf | grep multiboot
    22: 00000000     0 NOTYPE  GLOBAL DEFAULT    1 __multiboot_header

The output of readelf -S seems to conflict:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 1] .multiboot        PROGBITS        00000000 1000f8 00000c 00      0   0  1
  [ 2] .text             PROGBITS        00100000 100000 000096 00  AX  0   0  1

Which implies that the .multiboot section is actually inside the .text section.

If I offset into the file by 0x1000f8 then I can find the structure, however, I am not sure where the offset came from.

tl;dr

1) How can I ensure a specific data structure is within the first 8192 bytes of the output file?

2) How can I specify the load address without inflating the output binary with large gaps of zero-initialized blocks?

sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • I do not follow your conclusion "Which implies that the .multiboot section is actually inside the .text section.". According to the Addr values, _.multiboot_ starts at `00000000` with size `00000c`, and _.text_ starts at `00100000`, so the former is not inside the latter... – falstaff May 13 '17 at 21:45
  • @falstaff, I concluded this based on the `Off` field; `.multiboot` is `0xf8` bytes past `.text`. Since multiboot was defined first I expected it to be earlier in the file. I understand `Off`set refers to the ELF file, but was confused as to why it was placed after the text section. – sherrellbc May 15 '17 at 21:22

1 Answers1

1

The elf file format is generated by its own rules, how it stores the information is not directly influenced by the linker file (e.g. at what offsets the sections are stored must not correlate with their location at lifetime in memory). It's the memory layout which is described by the SECTIONS command in your linker file, and the elf file format describes this layout... You need a elf capable loader to load the individual sections into the target locations.

To get a flat binary file which can be loaded 1:1 into memory, use objcopy (e.g. something like objcopy -O binary myfile.elf myfile.bin). The layout of that file is directly influenced by your linker script, and the content of the .multiboot section should be really at offset 0.

falstaff
  • 3,413
  • 2
  • 25
  • 26
  • According to [this](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Header-magic-fields) grub reference, loading ELFs is supported. Actually, additional fields in the multiboot header (like load address) need not be specified if the loaded image is a proper ELF file. – sherrellbc May 15 '17 at 21:25
  • Given your comments, how would physical memory be laid out given a proper ELF loader? Would the multiboot header be placed at physical address 0x00, and the first byte of the `.text` section be at `0x00100000`? – sherrellbc May 15 '17 at 21:29
  • I was considering the `objcopy` route, but I would necessarily have to complete all the fields of the multiboot header. I may still do this, but the linker/ELF relationship was something I wanted to iron out first. I understand your comments above, but am not understanding where the 1MiB of additional zero-initialized memory is coming from (that is, after moving the location counter with `. = 0x00100000`, why did the size of the resulting ELF file increase by this much?). These bytes are not part of any section. My goal was to simply specify the load address of the first byte of `.text`. – sherrellbc May 15 '17 at 22:03