1

我想获取函数_dl_start(动态链接器的入口点)的地址。我可以使用 gdb 设置断点。我希望使用 readelf 找到符号,但我没有。如何获取地址/gdb 如何解析 _dl_start?

使用 gdb 设置断点的示例源 (main.cpp) 是

int main( int argc, char** argv, char** envp )
{

  return 0;
}

我用它编译了

 g++ main.cpp -o teststart 

运行程序时的 gdb 输出是

(gdb) b _dl_start
Function "_dl_start" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (_dl_start) pending.
(gdb) r
Starting program: /tmp/teststart 

Breakpoint 1, 0x00007fa7ee8c4fc4 in _dl_start () from /lib64/ld-linux-x86-64.so.2
4

2 回答 2

4

_dl_start符号在ld-linux-x86-64.so.2(动态加载器)中,并且该符号是ld-linux私有的。这意味着从程序内部找到它的唯一方法是执行与 GDB 相同的操作:读取 的符号表ld-linux,并在其中搜索“_dl_start”函数(按名称)。直接链接到它(正如马丁建议的那样)不能也不会起作用(正如您已经发现的那样)。

读取 ELF 符号表并不是很复杂——您只需要查找.symtab.strtab部分,并将其.symtab作为Elf64_Sym条目表读取。或使用libelf(从这里开始)。

另一个复杂的问题是ld-linux可能会被剥离(它不需要符号表来工作)。如果它被提示,GDB 和您的程序都无法找到_dl_start.

最后,您的查找尝试很可能_dl_start毫无意义:您确实意识到在执行程序的第一条指令之前很久就调用了此函数。到你打的时候main_dl_start早就打完了,再也不会叫了。

更新:

我还是想知道gdb是如何获取ld-linux中_dl_start的地址的(被剥离了)

如果ld-linux被剥离,GDB 将无法在其中找到_dl_start。既然你 GDB 确实找到了它,要么

  1. ld-linux实际上并没有被剥夺,或者
  2. 你已经安装了 glibc 的“单独的调试信息”

要验证ld-linux是否真的完全剥离,运行nm /lib64/ld-linux-x86-64.so.2 | grep _dl_startreadelf -S /lib64/ld-linux-x86-64.so.2 | grep symtab. 这两个命令都不应产生任何输出。

要查看 GDB 从哪里加载符号,可以使用set print symbol-loading on命令(在运行可执行文件之前)。

我想调用_dl_start(在准备堆栈和调整辅助向量之后)来创建已经存储在内存中的程序的可执行映像(文件表示)......

我不明白这怎么可能奏效。_dl_start在调用它之前期望某些状态(例如,将其全局变量清零),因此即使您不调整辅助向量,第二次调用它也可能导致断言失败。如果您确实以某种非平凡的方式调整辅助向量,则断言更有可能,这(显然)是您的目标。

于 2012-08-14T06:10:05.810 回答
0

_dl_start 不是程序本身的一部分,它包含在运行时加载程序中(从输出“..._dl_start () from /lib64/ld-linux-x86-64.so.2”可以看出)。GDB 最初无法设置断点,因为它不包含在您的可执行文件中。我有点不清楚,如果您想从程序内部或外部知道 _dl_start 的地址?从内部,您应该能够简单地将它分配给一个 void* 变量,如下所示:

void* address = dl_start;
于 2012-08-13T11:40:31.673 回答