如何使用汇编制作小二进制文件?

时间:2019-07-09 16:32:38

标签: assembly linker ld elf binutils

我正在为我的某个项目编写一些汇编代码,我看到了一些有趣的东西。链接时二进制文件的大小太大。因此我进行了测试,即使使用最小的代码行,输出的Elf二进制文件也是如此。例如:

.section .text
.global _start
_start:
    movl $1,%eax
    movl $0,%ebx
    int $0x80

在汇编并链接以上代码后,结果二进制文件超过4kb ! 有趣的是,大多数二进制文件都用零填充。
我尝试了很多事情以找出导致失败的原因。
有人可以给我解释一下这是什么问题吗?

我只是汇编并链接文件:

as -o <OBJ_NAME> <SOURCE NAME>
ld -o <ELF_NAME> <OBJ_NAME>

推荐任何形式的资源以供进一步阅读会很好。

您可能会猜到,我使用的是64位GNU / Linux

谢谢。

1 个答案:

答案 0 :(得分:4)

这与对齐有关。参见readelf -eW <ELF_NAME>。有趣的是

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000401000 001000 00000c 00  AX  0   0  1

请注意Off列。这是文件中的偏移量,.text部分以0x1000开头,为4K。

如果查看程序头文件,则显示相同的图片。填充零的空间在ELF标头的末尾和0x1000之间。

这是为什么?

首先,因为ELF标准规定

  

可加载过程段的p_vaddr和p_offset必须具有一致的值,以页面大小为模。

(请参阅man elf)。系统上的页面大小(也是我的页面大小)为4K。这是您在p_align中看到的值。

第二,链接程序分配给“文本”段开头的虚拟地址(与此处的.text相同,因为这就是该段所包含的全部地址)是0x0000000000401000。因此,文件中“文本”段的偏移量的十六进制表示必须以000结尾。但是包含ELF标头(文件的最开始)的只读段已经采用了0。第二个选择是0x1000

为什么链接器选择0x401000作为文本部分的虚拟地址?我不知道。我认为,只要稍微调整链接描述文件,就可以使用较小的可重编译可执行文件。


正如Peter和其他人指出的那样,可以使用-n链接器选项来禁用页面大小对齐:

'-n'
'--nmagic'
    Turn off page alignment of sections, and disable linking against
    shared libraries[…]

那样我就得到

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 1] .text             PROGBITS        0000000000400078 000078 00000c 00  AX  0   0  1

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x000078 0x0000000000400078 0x0000000000400078 0x00000c 0x00000c R E 0x1

,可执行文件的大小减少到664字节(strip ping后为344)。


使用GNU ld,您可以使用链接器脚本精细控制链接器输出文件的布局。如果用户未指定默认链接描述文件,则ld.bfd(通常也称为ld)将解释默认的链接描述文件。可以使用ld --verbose获得。然后,您可以对其进行编辑并提供您的版本,而不是使用-T <your-script>提供默认版本。

我删除了

的第一次出现
. = ALIGN(CONSTANT (MAXPAGESIZE));

(在.text之前),得到720个字节(strip时为400个)字节。这与使用-n选项的结果不同。您仍然会获得2个可加载的段,而它们的p_align仍然是0x1000

我不完全了解p_align <MAX_PAGE_SIZE对效率的影响。 (由于地址计算难度较大,因此页面加载速度不会很快?我认为应该有一个更好的解释。)如果您对此答案有更多了解或在何处进行解释,请随时编辑答案。