// foo.c
int main() { return 0; }
当我编译上面的代码时,我注意到*ABS*
中有一些符号:
$ gcc foo.c
$ objdump -t a.out | grep ABS
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000 foo.c
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000
看起来它们是一些调试符号,但是调试信息不是存储在.debug_info
节之类的地方吗?
根据man objdump
:
* ABS *,如果该部分是绝对的(即未与任何部分连接)
我不明白,因为这里没有给出示例。
问题here显示了一种有趣的方式,可以通过*ABS*
在--defsym
中传递一些额外的符号。但是我认为通过传递宏可能会更容易。
那么*ABS*
部分是什么,有人何时使用它?
编辑:
绝对符号不会被重定位,它们的虚拟地址(在您给出的示例中为0000000000000000)是固定的。
我写了一个演示,但似乎可以修改绝对符号的地址。
// foo.c
#include <stdio.h>
extern char foo;
int main()
{
printf("%p\n", &foo);
return 0;
}
$ gcc foo.c -Wl,--defsym,foo=0xbeef -g
$ objdump -t a.out | grep ABS
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000 foo.c
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000
000000000000beef g *ABS* 0000000000000000 foo
# the addresses are not fixed
$ ./a.out
0x556e06629eef
$ ./a.out
0x564f0d7aeeef
$ ./a.out
0x55c2608dceef
# gdb shows that before entering main(), &foo == 0xbeef
$ gdb a.out
(gdb) p &foo
$1 = 0xbeef <error: Cannot access memory at address 0xbeef>
(gdb) br main
Breakpoint 1 at 0x6b4: file foo.c, line 7.
(gdb) r
Starting program: /home/user/a.out
Breakpoint 1, main () at foo.c:7
7 printf("%p", &foo);
(gdb) p &foo
$2 = 0x55555555feef <error: Cannot access memory at address 0x55555555feef>
答案 0 :(得分:1)
如果您查看其他符号,可能会找到一个索引(如果读者为您进行映射,则可能会找到部分名称)来代替*ABS*
。这是节标题表中的节索引。它指向在其中定义符号的节的节标题(如果您正在查看的对象中未定义,则指向SHN_UNDEF
(零)。因此,符号的值(虚拟地址)将使用相同的值进行调整,该值在加载过程中会调整其包含部分。 (此过程称为 relocation 。)对于绝对符号(具有特殊值SHN_ABS
作为其st_shndx
)不是这样。绝对符号不会重定位,它们的虚拟地址(在您给出的示例中为0000000000000000
)是固定的。
这种绝对符号有时用于存储一些元信息。特别是,编译器可以创建符号名称与其编译的翻译单元名称相同的符号。此类符号不是链接或运行程序所必需的,它们仅适用于人类和二进制处理工具。
对于您的问题,没有将其存储在.debug_info
节中的原因(以及即使未指定调试开关也发出此信息的原因),答案是这是一回事;它只是符号表(.symtab
)。当然,调试也需要它,但是它的主要目的是链接对象(.o
)文件。默认情况下,它保留在链接的可执行文件/库中。您可以使用strip
摆脱它。
我在这里写的大部分内容都在man 5 elf
中。
我认为不支持/不应将您正在做的事情(使用--defsym
用于动态链接。查看编译器输出(gcc -S -masm=intel
),我看到了
lea rsi, foo[rip]
或者,如果我们查看objdump -M intel -rD a.out
(与-q
链接以保留重定位),则会看到同一件事:rip
相对寻址用于获取{{ 1}}。
foo
编译器不知道它将成为一个绝对符号,因此它会生成它所执行的代码(与普通符号一样)。 113d: 48 8d 35 ab ad 00 00 lea rsi,[rip+0xadab] # beef <foo>
1140: R_X86_64_PC32 foo-0x4
是指令指针,因此在rip
将程序映射到内存之后,它取决于包含.text
的段的基址。
我发现answer可以说明绝对符号的正确用例。