为什么链接器不从可执行文件中剥离主例程?

why linker does not strip main routine from executable?

我测试了两个成功退出的小程序,第一个使用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 程序编译后获取目标文件的链接器。

why linker does not strip main routine from executable?

因为链接器通常不会从给定的目标文件中删除 任何 例程。他们根本不在那个行业。

链接器不对例程进行操作,它们对进行操作。一些链接器可以有限地删除 unreferenced 部分,例如GNU BFD ld 和 Gold 有 --gc-sections 标志,但在您的示例中没有未引用的部分,因此无论如何都不会进行 GC。

现在,您的两个程序之间的区别在于,在 C 运行时启动时带有 main 链接的程序(通常为 crt0.o),并设置 argcargv 参数 main 被定义为期望它们的方式。

您的 main 不关心这个,但需要一个非常聪明的链接器才能推断出这一点。此外,您的 main 确实 关心返回后调用 sys_exit,因此它实际上需要 crt0.o 才能正常关闭。

Is is that argc/argv setting-up process, that takes up few kilobytes?

如果您使用的是 GNU ld,您可以要求链接器 确切地告诉您 什么使用了多少 space 以及链接器 --print-map 参数。

在 ELF 平台上,您还可以使用 nm main 查看最终二进制文件中哪些符号占用 space,并使用 ld -y <symbol> ... 查看这些符号在哪里链接来自.