什么是 *ABS* 部分以及何时使用?
What is *ABS* section and when to use?
// 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* if the section is absolute (ie not connected with any section)
这里没有举例,没看懂
问题 展示了 --defsym
在 *ABS*
中传递一些额外符号的有趣方式。但我认为传递宏会更容易。
那么这个 *ABS*
部分是什么,什么时候会有人使用它?
编辑:
Absolute symbols don't get relocated, their virtual addresses (0000000000000000 in the example you gave) are fixed.
我写了一个demo,但是好像可以修改绝对符号的地址。
// 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
= 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
= 0x55555555feef <error: Cannot access memory at address 0x55555555feef>
如果您查看其他符号,您可能会找到一个索引(或部分名称,如果 reader 为您进行映射)代替 *ABS*
。这是 headers table 节中的节索引。它指向该符号定义的部分的 header 部分(如果它在您正在查看的 object 中未定义,则指向 SHN_UNDEF
(零))。因此,符号的值(虚拟地址)将根据加载期间调整其包含部分的相同值进行调整。 (此过程称为 重定位 。)绝对符号并非如此(具有特殊值 SHN_ABS
作为它们的 st_shndx
)。绝对符号不会重新定位,它们的虚拟地址(0000000000000000
在你给出的例子中)是固定的。
这样的绝对符号有时用来存储一些元信息。特别是,编译器可以创建符号名称等同于它编译的翻译单元名称的符号。链接或 运行 程序不需要此类符号,它们仅供人类和二进制处理工具使用。
至于你的问题 w.r.t 这没有存储在 .debug_info
部分的原因(以及为什么即使没有指定调试开关也会发出这个信息),答案是一个单独的东西;它只是符号 table (.symtab
)。当然,调试也需要它,但它的主要目的是链接 object (.o
) 文件。默认情况下,它保存在链接 executables/libraries 中。你可以用 strip
.
摆脱它
我在这里写的大部分内容都在 man 5 elf
.
我不认为你正在做的事情(使用 --defsym
)supported/supposed 可以使用动态链接。查看编译器输出 (gcc -S -masm=intel
),我看到了这个
lea rsi, foo[rip]
或者,如果我们查看 objdump -M intel -rD a.out
(与 -q
链接以保留重定位),我们会看到同样的事情:rip
-相对寻址用于获取地址foo
.
113d: 48 8d 35 ab ad 00 00 lea rsi,[rip+0xadab] # beef <foo>
1140: R_X86_64_PC32 foo-0x4
编译器不知道它会成为一个绝对符号,所以它会生成它所做的代码(对于普通符号)。 rip
是指令指针,所以它依赖于ld.so
.
程序映射到内存后包含.text
的段的基地址
我发现这个 answer 阐明了绝对符号的正确 use-case。
// 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* if the section is absolute (ie not connected with any section)
这里没有举例,没看懂
问题 --defsym
在 *ABS*
中传递一些额外符号的有趣方式。但我认为传递宏会更容易。
那么这个 *ABS*
部分是什么,什么时候会有人使用它?
编辑:
Absolute symbols don't get relocated, their virtual addresses (0000000000000000 in the example you gave) are fixed.
我写了一个demo,但是好像可以修改绝对符号的地址。
// 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
= 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
= 0x55555555feef <error: Cannot access memory at address 0x55555555feef>
如果您查看其他符号,您可能会找到一个索引(或部分名称,如果 reader 为您进行映射)代替 *ABS*
。这是 headers table 节中的节索引。它指向该符号定义的部分的 header 部分(如果它在您正在查看的 object 中未定义,则指向 SHN_UNDEF
(零))。因此,符号的值(虚拟地址)将根据加载期间调整其包含部分的相同值进行调整。 (此过程称为 重定位 。)绝对符号并非如此(具有特殊值 SHN_ABS
作为它们的 st_shndx
)。绝对符号不会重新定位,它们的虚拟地址(0000000000000000
在你给出的例子中)是固定的。
这样的绝对符号有时用来存储一些元信息。特别是,编译器可以创建符号名称等同于它编译的翻译单元名称的符号。链接或 运行 程序不需要此类符号,它们仅供人类和二进制处理工具使用。
至于你的问题 w.r.t 这没有存储在 .debug_info
部分的原因(以及为什么即使没有指定调试开关也会发出这个信息),答案是一个单独的东西;它只是符号 table (.symtab
)。当然,调试也需要它,但它的主要目的是链接 object (.o
) 文件。默认情况下,它保存在链接 executables/libraries 中。你可以用 strip
.
我在这里写的大部分内容都在 man 5 elf
.
我不认为你正在做的事情(使用 --defsym
)supported/supposed 可以使用动态链接。查看编译器输出 (gcc -S -masm=intel
),我看到了这个
lea rsi, foo[rip]
或者,如果我们查看 objdump -M intel -rD a.out
(与 -q
链接以保留重定位),我们会看到同样的事情:rip
-相对寻址用于获取地址foo
.
113d: 48 8d 35 ab ad 00 00 lea rsi,[rip+0xadab] # beef <foo>
1140: R_X86_64_PC32 foo-0x4
编译器不知道它会成为一个绝对符号,所以它会生成它所做的代码(对于普通符号)。 rip
是指令指针,所以它依赖于ld.so
.
.text
的段的基地址
我发现这个 answer 阐明了绝对符号的正确 use-case。