c - Printf 符号解析

标签 c elf ptrace objdump readelf

我正在编写一个小程序,它使用 ptrace(单步、getregs、pick_text、操作码比较等)跟踪二进制文件 (elf) 的所有系统调用和调用。

到目前为止,我已经成功跟踪系统调用和用户定义函数等简单调用。

但由于 ptrace,我未能从我选择的地址中获取 printf 符号的名称。

我的问题是:对于 printf、strlen 等动态链接函数,如何在 elf 文件中从地址中检索符号的名称?

通过简单的调用,这很容易,我运行 .strtab 部分,本地址匹配时,我返回相应的 str。

但对于 printf,符号在 .strtab 中是已知的,但地址为“0”。

objdump -d 以某种方式成功地将对 printf 的调用与其地址链接起来。

你有什么想法吗?

最佳答案

我认为您可能需要阅读更多有关动态链接的内容。让我们以 strlen 作为示例符号,因为 printf 有点特殊(防御工事)。

你的问题是(我认为)你想要获取符号的地址并将其转换回地址。您正在尝试通过解析正在调试的程序的 ELF 文件来执行此操作。这适用于程序中的符号,但不适用于动态链接的符号,例如 strlen。你想知道如何解决这个问题。

原因是 strlen 等符号的地址未保存在您的 ELF 程序中。它们是未解析的引用,在程序加载时动态解析。事实上,现代 Linux 将(我相信)以随机顺序和随机地址加载动态库(其中包含可重定位又名位置无关代码),因此在程序加载之前不会知道这些符号的位置。

对于您使用 dlopen() 打开的库(即您在程序中自己进行加载的位置),您可以使用 dlsym()< 检索此类符号的地址;如果它们在编译/链接时链接到程序中,那就不太好了。

在 gcc 上,一般要解析符号的位置,请使用 gcc 扩展 dladdr()。从手册页:

   The function dladdr() takes a function pointer and tries to
   resolve name and file where it is located.   Information  is
   stored in the Dl_info structure:

       typedef struct {
           const char *dli_fname;  /* Pathname of shared object that
                                      contains address */
           void       *dli_fbase;  /* Address at which shared object
                                      is loaded */
           const char *dli_sname;  /* Name of nearest symbol with address
                                      lower than addr */
           void       *dli_saddr;  /* Exact address of symbol named
                                      in dli_sname */
       } Dl_info;

   If no symbol matching addr could be found, then dli_sname and
   dli_saddr are set to NULL.

   dladdr() returns 0 on error, and nonzero on success.

我相信这对你有用。

有关更多信息,我建议您查看 sourceltrace 跟踪库调用,以及如何 backtrace_symbols (和 here )有效;请注意,特别是对于非全局符号,这将是不可靠的,并注意将 -r dynamic 添加到链接行的注释。

您可能还想看看 addr2line及其 source .

关于c - Printf 符号解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31362411/

相关文章:

c - 在 Rust 中声明一个结构或变量的正确方法是什么,它可以传递给需要指针的 C 代码?

linux-kernel - 什么是 CPU 内核/特权模式,操作系统如何保护它?

linux - 访问进程的内存区域

c++ - Linux:通过 ptrace() 执行系统调用

c - 为什么 SIGINT 被发送到子进程并且什么都不做?

c - 段错误(malloc 结构)

c - 尝试用 C 语言运行程序

通过循环计算无法正常工作的行数

c++ - 程序加载/执行

c++ - 强制一个符号到 ELF 文件的顶部