我测试了两个成功退出最小程序,第一个使用libc
,第二个不使用libc
。
首先:
segment .text
global main
main:
xor eax, eax
ret
构建并检查大小:
yasm -f elf64 main.s; clang -o main main.o; stat ./main
...
Size: 8552
...
第二
segment .text
global _start
_start:
mov eax, 60
xor edi, edi
syscall
构建并检查大小:
yasm -f elf64 main.s; ld -o main main.o; stat ./main
...
Size: 704
---
显然,使用 main 的程序规模较大。 为什么链接器不会从二进制文件中删除 main 例程来优化大小?我的意思是在编译C程序后得到目标文件的链接器。
答案 0 :(得分:1)
为什么链接器不会从可执行文件中删除主例程?
因为链接器通常不会从给定的对象文件中删除任何例程。他们根本就不在那个行业。
链接器不在例程上运行,它们在部分上运行。一些链接器可以有限地删除未引用的部分,例如GNU BFD ld和Gold有--gc-sections
标志,但在你的例子中没有未引用的部分,所以无论如何都没有GC。
现在,两个程序之间的区别在于C运行时启动时main
链接的那个(通常为crt0.o
),并设置了argc
和argv
个参数main
被定义为期望它们的方式。
你的main
并不关心这一点,但需要一个非常聪明的链接器来推断它。此外,您的main
确实关心在返回后调用sys_exit
,因此实际需要crt0.o
才能正常关闭。
这是argc / argv建立过程,占用几千字节?
如果您正在使用GNU ld,您可以要求链接器告诉您完全使用链接器--print-map
参数占用多少空间。
在ELF平台上,您还可以使用nm main
查看哪些符号占用最终二进制文件中的空格,并使用ld -y <symbol> ...
查看这些符号的链接位置。