所有asm标签都成为可执行文件中的符号

Bee*_*ope 6 x86 assembly linker nasm elf

使用时组装对象时nasm,我发现所有标签都包含在结果.o文件中的符号中,以及最终的二进制文件中.

这对于我已经声明的函数入口点GLOBAL和段开始部分(例如,对于该.text部分)是有意义的,但是标签简单地用作循环入口点并且所有这些都接近出现在输出文件中似乎很奇怪.除了泄漏内部实现细节之外,它还浪费了符号表中的空间.

例如,鉴于这个简短的装配程序:

GLOBAL _start
_start:
    xor eax, eax
normal_label:
    xor eax, eax
.local_label:
    xor eax, eax
    xor edi, edi
    mov eax, 231    ;  exit(0)
    syscall
Run Code Online (Sandbox Code Playgroud)

...建造使用:

nasm -f elf64 label-test.s
ld label-test.o -o label-test
Run Code Online (Sandbox Code Playgroud)

l对象文件和链接的可执行文件中生成(即本地)符号:

objdump --syms label-test.o

label-test.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 label-test.s
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000002 l       .text  0000000000000000 normal_label
0000000000000004 l       .text  0000000000000000 normal_label.local_label
0000000000000000 g       .text  0000000000000000 _start
Run Code Online (Sandbox Code Playgroud)

请注意,两者normal_label和本地标签local_label最终都在符号表中.所有这些都最终都在可执行文件的符号表中.

我不想将这些符号发送到最终的可执行文件.我可以告诉他们不要包含它们吗?我可以传递一些选项ld,例如--strip-all,将删除这些符号,但也删除可执行文件中的所有其他符号.这使得它成为了一个重点:它消除了我真正想要保留的符号,用于可读的堆栈跟踪,调试等.


正如Peter Cordes所提到的那样,FWIW yasm没有完全相同的问题.使用.o与上面完全相同的方式构建的elf64 文件(但yasm替换后nasm,我们得到:

objdump --syms label-test-yasm.o 

label-test-yasm.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 label-test.s
0000000000000004 l       .text  0000000000000000 
0000000000000002 l       .text  0000000000000000 
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 g       .text  0000000000000000 _start
Run Code Online (Sandbox Code Playgroud)

全局_start标签仍然包含在内,但其他两个标签未命名 - 它们仍在那里,它们是偏移4和2的未命名符号(上面列表中的第2和第3行).这可以通过添加更多标签来确认 - 生成更多未编辑的符号.

Bee*_*ope 6

据我所知,这只是 nasm 的一个限制。例如,请参阅此论坛帖子,其中的海报具有大致相同的问题(尽管是 32 位而不是 64 位 ELF),并且除了使用剥离工具之外没有提供任何解决方案。

就我而言,似乎剥离了目标文件,如:

strip --discard-all label-test.o 
Run Code Online (Sandbox Code Playgroud)

应该做的伎俩。尽管有这个--discard-all选项的名称,但它只去除局部符号而单独留下全局符号。这是剥离文件之前的符号表:

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 label-test.s
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000002 l       .text  0000000000000000 normal_label
0000000000000004 l       .text  0000000000000000 normal_label.local_label
0000000000000000 g       .text  0000000000000000 _start
Run Code Online (Sandbox Code Playgroud)

之后:

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 label-test.s
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 g       .text  0000000000000000 _start
Run Code Online (Sandbox Code Playgroud)

特别要注意的是,.text尽管它是本地的,但单独保留部分符号是足够聪明的。当然,这个 strip 选项不能真正区分无用(循环标签)和潜在有用的符号,例如使用各种工具提供正确堆栈跟踪所需的本地函数入口点。

如果您想更聪明一点,您可以.使用--wildcard--strip-symbol选项选择性地仅去除带有嵌入..

如果有人潜伏在那里,我仍在寻找更好的答案。