objdump报告的符号偏移不再与运行时偏移匹配

时间:2017-07-28 09:17:00

标签: c unix gcc objdump

在以前的GCC版本中,objdump报告的符号偏移与实际执行代码期间使用的符号偏移相匹配。例如:

$ cat example.c
#include <stdio.h>

int g_someGlobal = 0;

int main()
{
    printf("%d\n", g_someGlobal);
    return 0;
}

$ gcc-6 -v
...
gcc version 6.1.1 20160802 (Debian 6.1.1-11)


$ gcc-6 -O0 -g -o example example.c

$ objdump -x example | grep Global
...
080496f4 g     O .bss       00000004              g_someGlobal
...

实际上,在运行二进制文件时,执行期间使用的符号的实际地址与objdump报告的地址相同:

$ gdb ./example
...
(gdb) start
Temporary breakpoint 1, main () at example.c:10
10          printf("%d\n", g_someGlobal);

(gdb) p/x &g_someGlobal
$1 = 0x80496f4

不幸的是,在最近发布的Debian Stretch中重复相同的命令序列,反而发生了这种情况:

$ gcc-6 -v
...
gcc version 6.3.0 20170415 (Debian 6.3.0-14)


$ gcc-6 -O0 -g -o example example.c

$ objdump -x example | grep Global
00002020 g     O .bss   00000004              g_someGlobal

符号偏移现在似乎是一个小得多的值 - ...

$ gdb ./example
...
(gdb) start
...
Temporary breakpoint 1, main () at example.c:7
7               printf("%d\n", g_someGlobal);
(gdb) p/x &g_someGlobal
$1 = 0x80002020

...不再与运行时使用的那个匹配。

我在这里弄错了吗?在此期间,工具的使用是否发生了变化?如果没有,这种变化背后的原因是什么?

无论如何 - 理论上必须有一种方法可以获得托管变量的.bss段的“预期运行时间偏移”(objdump会报告它将放入哪个部分,所以最终可以通过添加.bss偏移量来计算运行时位置。在我的初步尝试中,我还没有找到办法解决这个问题:

$ readelf --sections example | grep bss
[26] .bss         NOBITS     0000201c 00101c 000008 00  WA  0   0  4

这似乎没有报告0x80000000的“转移”似乎发生在.bss - 此示例中的托管变量。

(即使这是这个新执行环境的“神奇常数”,这也适用于.data变量吗?说实话,我讨厌神奇的价值 - 以前,无论来了什么objdump -x中的objdump -x是准确的,无论符号位于何处......)

任何解决此问题的信息都非常受欢迎。理想情况下,我想重现.category{ height: 70px !important; width: 28% !important; margin: 0 10px 0 10px; border: 1px solid #3A94D7; border-radius: 15px; box-shadow: 0 0 15px 1px rgba(0,0,0,.75), inset 0 0 2px 0 #4293D5; } .icon-steam{ background: url(../img/steam.png) 50% 50% no-repeat; background-size: 40px; float: left; width: 40px; height: 40px; margin-right: 0.3em; } .platform{ text-shadow: none; color: #65a1bf; left:14%; top:60px; position: absolute; }的旧行为 - 即静态(不是在运行时)从承载它的ELF获取符号的运行时地址的值。

更新:我做了GCC7.1.0的自定义编译(来自源代码),这不再可重现。也许这是GCC 6.3(Debian Stretch中打包的版本)的回归......

1 个答案:

答案 0 :(得分:3)

原因是Debian的gcc包是用--enable-default-pie构建的。在PIE可执行文件中,ELF段可以以任意(只要它正确对齐)基址加载,通常由加载器随机选择。您在ELF文件中看到的符号地址是相对于其加载的基址的偏移量,而不是绝对虚拟地址。

如果您不想要/不需要PIE,可以添加-no-pie链接命令行以获取您已经习惯的链接时确定的地址。