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

标签 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 的旧行为 - 即静态地(不是在运行时)从 ELF 获取符号的运行时地址的值托管它。

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

最佳答案

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

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

关于c - objdump 报告的符号偏移量不再与运行时偏移量匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45369536/

相关文章:

java - 奇怪的行为在循环中重新运行java应用程序

linux - bash 脚本中的 -Ron 是什么意思?

c++ - 当我在 C++ 中使用 auto bi = 123456789 时,它是否总是分配为 int?

c - 简单C题

c - 错误 : cuda_runtime. h:没有那个文件或目录

c - 如何打印字符串的字符值?

c - open() 的区别

c - 这解析为什么?

c - 为什么在 POSIX/IEEE 标准中 pthread_mutexattr_settype() 需要 _GNU_SOURCE 宏?

c - 如何使用 DOT 运算符初始化结构类型的数组