【问题标题】:Why does arm-none-eabi-ld align program headers to 64KiB when linking? How do I change it?为什么 arm-none-eabi-ld 在链接时将程序头对齐到 64KiB?我该如何改变它?
【发布时间】:2021-03-20 20:20:31
【问题描述】:

考虑以下程序和相应的链接描述文件:

// file: foo.c

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

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

    /DISCARD/ : { *(*) }
}

现在我构建和链接如下:

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

我遇到的问题是链接器生成了一个巨大的文件:

$ 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

foo.o 对象只有 724 字节,但链接的 foo 可执行文件是 65KiB!

readelf 迅速揭示问题:

$ 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 

程序头对齐为0x10000,可以用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

所以本质上是一个小标题,然后是大约 64KiB 的对齐,然后是一个小后缀。

这种对齐方式从何而来?我怎样才能使这种对齐消失?

如果我使用常规工具链执行相同的过程,则不会发生这种情况:

$ 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

所以这似乎与 ARM 相关?

【问题讨论】:

  • elf文件大小不用担心,二进制大小更有趣
  • 二进制为4字节。
  • hmmm native readelf 适用于非本地 elf 文件。
  • 问题是我把这个文件放在微控制器的闪存中,虽然它适合,但每次我想运行程序时都必须将它复制到芯片上。因此我需要小精灵文件。
  • 我设法使用--nmagic 链接器标志来解决这个问题,这有点骇人听闻,因为链接器似乎仍然认为页面大小是 0x10000,但无论如何。 (See my answer)

标签: linker arm elf binutils


【解决方案1】:

仅仅写下这个问题就让我想出了答案,链接器正在尝试将.data 部分与默认情况下似乎为 64KiB 的页面边界对齐。 (看起来很大,可能是无意的?)

无论如何,正如a comment in this blog post 中所建议的,链接器选项--nmagic 将其关闭:

-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

通过此更改,二进制文件现在是 416 字节而不是 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

【讨论】:

  • 它可能会在这里提供帮助,但我相信链接的博客是在讨论 ld 中的一个已知错误,它会创建坏文件,但可能使用共享 elf 库(binutils 和 openocd)的工具, elf 库知道如何读取损坏的文件并使用它们。在您的情况下,您似乎出于某种原因想让 elf 文件更小。
猜你喜欢
  • 2017-03-24
  • 2017-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 2016-05-01
  • 2011-08-23
相关资源
最近更新 更多