【发布时间】:2019-05-08 07:23:29
【问题描述】:
// 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 展示了一种有趣的方法,可以通过--defsym 在*ABS* 中传递一些额外的符号。但我认为传递宏会更容易。
那么*ABS* 部分是什么?什么时候有人会使用它?
编辑:
绝对符号不会被重定位,它们的虚拟地址(在您给出的示例中为 0000000000000000)是固定的。
我写了一个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
$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>
【问题讨论】:
-
/a.out 0x556e06629eef-- 很好的观察。我也很好奇;现在调查它,到目前为止我已经发现了两件事。 1)你得到的不同结果是内核完成ASLR的结果。 2) 如果您静态链接程序 (gcc -static ...),您将在输出中看到未修改的0xbeef。所以 ISTM 动态加载器仍然通过基地址移动所有内容,包括绝对符号......