Linux:一起使用 backtrace()、/proc/self/maps 和 addr2line 会导致无效结果

Linux: using backtrace(), /proc/self/maps and addr2line together results in invalid result

我正在尝试实现一种方法来将我的程序的调用堆栈记录到一个文件中,然后稍后显示它。 以下是步骤:

问题是如果地址在共享对象中,那么绝对地址将不起作用,而减去的偏移量将起作用。

为什么主可执行文件和共享对象的地址映射方式如此不同?或者这可能是 backtrace 实现特定的,这样它总是 returns 主可执行文件中函数的绝对地址?

Why is there such a difference in the way the addresses are mapped for the main executable and the shared objects?

共享库通常链接到地址 0 并重新定位。非位置可执行文件通常链接在 x86_64 Linux 上的地址 0x400000 并且必须 not 重新定位(否则它不会工作)。

要找出给定的 ELF 二进制文件的链接位置,请查看第一个 PT_LOAD 段的 p_vaddr 地址(readelf -Wl foo 会告诉您)。此外,只有 ET_DYN 个 ELF 二进制文件可以重定位,而 ET_EXEC 个二进制文件不能。

请注意,存在与位置无关的可执行文件,您需要为它们做减法。

请注意,共享库通常链接在地址 0(因此减法有效),但它们 不必 。 运行 prelink 在共享库上将导致共享库链接到非 0 地址,然后你使用的减法将不起作用 或者 .

实际上,您需要做的是从链接地址中减去运行时加载地址以获得重定位(对于非 PIE 可执行文件为 0,对于共享库为非 0),然后减去从backtrace记录的程序计数器重定位得到符号值。

最后,如果您使用 dl_iterate_phdr 遍历所有已加载的 ELF 图像,它提供的 dlpi_addr 正是您需要减去的 重定位。