1

我真的在为链接器脚本苦苦挣扎,所以我决定从一个最小的测试开始并开始调整。但是,即使在我的目标文件中也没有为部分删除默认链接描述文件的行,可能会导致可执行文件急剧增长!


程序: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 文件,我真的很难理解它们。似乎没有什么与文档相匹配,并且默认链接描述文件似乎缺少各种重要信息。

4

0 回答 0