我真的在为链接器脚本苦苦挣扎,所以我决定从一个最小的测试开始并开始调整。但是,即使在我的目标文件中也没有为部分删除默认链接描述文件的行,可能会导致可执行文件急剧增长!
程序:wait_input.S
.intel_syntax noprefix
#include <sys/syscall.h>
.text
.globl _start
_start:
# read(0,rsp,1)
xor edi,edi
mov rsi,rsp
mov edx,1
mov eax,SYS_read
syscall
# exit(0)
xor edi,edi
mov eax,SYS_exit
syscall
超小,但足以看到它做某事。现在构建它并从详细输出中获取默认链接器脚本(由 ==== 行描述)。
$ gcc -c wait_input.S
$ gcc -o wait_input -nostdlib wait_input.o -Wl,--verbose | awk '!/==/ && p; \
/==/ {p=1-p};' > defaultlinker.x
看一看,我们看到目标文件中只有三个部分(其中只有一个有任何数据),并且生成的可执行文件很小(此时它的 ELF 标头比代码多)。
$ objdump -h wait_input.o
wait_input.o: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000001a 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 0000000000000000 0000000000000000 0000005a 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 0000000000000000 0000000000000000 0000005a 2**0
ALLOC
$ wc --bytes wait_input
880 wait_input
默认链接描述文件引用了我的目标文件中没有的所有类型的部分,因此我尝试将其缩减,但随后可执行文件的大小突然膨胀。玩了一下,我最终发现只是删除了两行(对于我的目标文件甚至没有的部分!),导致它:
$ sed -i -e "/build-id/d" defaultlinker.x
$ gcc -nostdlib -o wait_input wait_input.S -Wl,-T defaultlinker.x
$ wc --bytes wait_input
880 wait_input
$ sed -i -e "/interp/d" defaultlinker.x
$ gcc -nostdlib -o wait_input wait_input.S -Wl,-T defaultlinker.x
$ wc --bytes wait_input
2098048 wait_input
什么!?
有人可以解释一下吗?
我之前使用过微控制器的链接器脚本,它们非常简单。对于 ELF 文件,我真的很难理解它们。似乎没有什么与文档相匹配,并且默认链接描述文件似乎缺少各种重要信息。