Search code examples
linkerarmelfbinutils

Why does arm-none-eabi-ld align program headers to 64KiB when linking? How do I change it?


Consider the following program and the corresponding linker script:

// file: foo.c

int foo = 42;
/* file: link.x */

SECTIONS {
    .data : { *(.data) }

    /DISCARD/ : { *(*) }
}

Now I build and link as follows:

$ arm-none-eabi-gcc -c foo.c
$ arm-none-eabi-ld -T link.x foo.o -o foo

The problem that I am having is that the linker generates a huge file:

$ ls -lh
total 20K
-rwxr-xr-x 1 admin admin 65K Mar 20 12:29 foo
-rw-r--r-- 1 admin admin  14 Mar 20 12:18 foo.c
-rw-r--r-- 1 admin admin 724 Mar 20 12:19 foo.o
-rw-r--r-- 1 admin admin  64 Mar 20 12:18 link.x

The foo.o object is only 724 bytes, but the linked foo executable is 65KiB!

readelf quickly reveals the issue:

$ readelf -l foo

Elf file type is EXEC (Executable file)
Entry point 0x0
There is 1 program header, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x00000000 0x00000000 0x00004 0x00004 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .data 

The program header has an alignment of 0x10000, this can be confirmed with hexdump:

$ hexdump foo
0000000 457f 464c 0101 0001 0000 0000 0000 0000
0000010 0002 0028 0001 0000 0000 0000 0034 0000
0000020 0084 0001 0200 0500 0034 0020 0001 0028
0000030 0005 0004 0001 0000 0000 0001 0000 0000
0000040 0000 0000 0004 0000 0004 0000 0006 0000
0000050 0000 0001 0000 0000 0000 0000 0000 0000
0000060 0000 0000 0000 0000 0000 0000 0000 0000
*
0010000 002a 0000 0000 0000 0000 0000 0000 0000
0010010 0000 0000 0000 0000 0000 0000 0000 0000
0010020 0003 0001 0001 0000 0000 0000 0000 0000
0010030 0004 fff1 0007 0000 0000 0000 0000 0000
0010040 0000 0001 000a 0000 0000 0000 0004 0000
0010050 0011 0001 6600 6f6f 632e 2400 0064 6f66
0010060 006f 2e00 7973 746d 6261 2e00 7473 7472
0010070 6261 2e00 6873 7473 7472 6261 2e00 6164
0010080 6174 0000 0000 0000 0000 0000 0000 0000
0010090 0000 0000 0000 0000 0000 0000 0000 0000
00100a0 0000 0000 0000 0000 0000 0000 001b 0000
00100b0 0001 0000 0003 0000 0000 0000 0000 0001
00100c0 0004 0000 0000 0000 0000 0000 0004 0000
00100d0 0000 0000 0001 0000 0002 0000 0000 0000
00100e0 0000 0000 0004 0001 0050 0000 0003 0000
00100f0 0004 0000 0004 0000 0010 0000 0009 0000
0010100 0003 0000 0000 0000 0000 0000 0054 0001
0010110 000e 0000 0000 0000 0000 0000 0001 0000
0010120 0000 0000 0011 0000 0003 0000 0000 0000
0010130 0000 0000 0062 0001 0021 0000 0000 0000
0010140 0000 0000 0001 0000 0000 0000          
001014c

So essentially there is a small header followed by about 64KiB of alignment, followed by a small suffix.

Where does this alignment come from? How can I make this alignment go away?

If I go though the same process with my regular toolchain, this doesn't happen:

$ gcc -c foo.c
$ ld -T link.x foo.o -o foo
$ ls -lh
total 20K
-rwxr-xr-x 1 admin admin 4.5K Mar 20 13:01 foo
-rw-r--r-- 1 admin admin   30 Mar 20 13:00 foo.c
-rw-r--r-- 1 admin admin  952 Mar 20 13:01 foo.o
-rw-r--r-- 1 admin admin   84 Mar 20 13:01 link.x

So this seems to be ARM related?


Solution

  • Just writing the question made me figure out the answer, the linker is trying to align the .data section to a page boundary which seems to be 64KiB by default. (That seems really large, that might be unintended?)

    Anyways, as suggested in a comment in this blog post, the linker option --nmagic turns this off:

    -n
    --nmagic
        Turn off page alignment of sections, and disable linking
        against shared libraries.  If the output format supports Unix
        style magic numbers, mark the output as "NMAGIC".
    

    ld(1) man page

    With this change the binary is now 416 bytes instead of 65KiB:

    $ arm-none-eabi-gcc -c foo.c
    $ arm-none-eabi-ld -T link.x foo.o -o foo --nmagic
    $ ls -lh
    total 16K
    -rwxr-xr-x 1 admin admin 416 Mar 20 13:17 foo
    -rw-r--r-- 1 admin admin  30 Mar 20 13:17 foo.c
    -rw-r--r-- 1 admin admin 724 Mar 20 13:17 foo.o
    -rw-r--r-- 1 admin admin  84 Mar 20 13:17 link.x