2017-10-19 116 views
1

为了调试我的程序,我需要查看加载共享库后发生了什么。我使用GDB的catch load命令停止共享库事件。在GDB的catchpoint停下来之后走出去

我对共享库的理解告诉了以下几点:最初,PLT入口指向一些加载该库的代码。当它被调用时,库被加载,并且PLT条目开始指向实际加载的库代码,以便下一次调用lib时,我们只是跳到它的代码而不重新加载。考虑到这一点,我期望该入口点位于从PLT调用的某个系统函数中,并且我希望我的代码能够在堆栈中更高的位置。

然而,堆在捕获点看起来是这样的:

(gdb) bt #0 0x00007ffff7df0632 in ??() from /lib64/ld-linux-x86-64.so.2 #1 0x00007ffff7dd8c2a in ??() from /lib64/ld-linux-x86-64.so.2 #2 0x00007ffff7dd7c38 in ??() from /lib64/ld-linux-x86-64.so.2 #3 0x000000000000000a in ??() #4 0x00007fffffffde1e in ??() // several frames without location info

在这一点上,我想继续从点执行我的代码,它开始加载共享库。但是,我无法在堆栈中看到我的代码。此外,我不明白框架#3的含义。由于GDB无法在堆栈中找到有效的返回地址(这很明显是因为0xa肯定不是有效的返回地址),所以我无法走出比这一帧更远的地方。

什么是0xa和它为什么在堆栈上? 是否有一种方法可以在加载共享库之后在代码中完全停止GDB?

回答

0

我对共享库的理解告诉了以下几点:最初,PLT入口指向一些加载lib的代码。当它被调用时,库被加载,并且PLT条目开始指向实际加载的库代码,以便下一次调用lib时,我们只是跳到它的代码而不重新加载。

这种理解是不正确的。

有两种情况需要考虑,它们都不涉及在调用函数时加载库。

案例#1:你的二进制文件对共享库直接相连,就像这样:

gcc main.c -lc # links against libc.so.6 

你可以看到的一组二进制文件直接针对与readelf -d a.out | grep NEEDED链接库。

在这种情况下,在可执行文件开始运行之前,所有库都由动态加载器加载。

案例2:您通过dlopen动态添加一个新库。

在这种情况下,该库从dlopen实现中加载。

你可能会困惑的是懒惰的PLT决议(它有没有什么与图书馆加载)。你可以阅读关于它here