在 ELF 文件中查找使用某个符号的人

6
我有一个包含符号的大二进制文件,我可以在 `nm` 或 `objdump` 中看到这个符号。
我知道这个符号被使用了,否则链接器不会把它包含进去(更准确地说,我知道同一源文件中的某个符号被使用了)。
我正在尝试找到它具体是如何被使用的。
如果引用是通过函数(例如函数调用函数、函数使用全局变量)实现的,我可以使用 `objdump -rd` 来反汇编文件并找到引用点。
但如果是通过变量(例如初始化为指向某个变量的全局指针)来引用,那么反汇编就无法展示它。
我没能找到任何方法来解决这个问题。
下面是一个演示它的例子。在这个例子中,很明显谁使用了 `x`,但我不知道如何检查生成的二进制文件并找到它。
// x.c
int x = 3;

// main.c
extern int x;
static int *y = &x;
int main() { 
    return *y;
}

// Build process
gcc -o x.o -c x.c
ar r libx.a x.o
gcc -o main.o -c main.c
gcc -o main main.o -L. -lx

"main.o" 在数据段中将有一个关于 x 的重定位条目。让我复制并展示确切的措辞。 - Ajay Brahmakshatriya
2个回答

2
我编译了相同的代码(使用相同的命令),并运行了objdump -x main.o。有一个部分:
RELOCATION RECORDS FOR [.data]:
OFFSET           TYPE              VALUE
0000000000000000 R_X86_64_64       x

这意味着这是一个64位的重定位记录(R_X86_64_64),它位于数据段的偏移量0处(即y在数据段中的偏移量)。需要重定位的值是x(实际上是变量x的地址,因为它是标签)。为了更好地理解这个概念,我添加了另一个变量-
extern int ** z = &y;

现在符号表如下所示 -
0000000000000000 l     O .data  0000000000000008 y
0000000000000008 l     O .data  0000000000000008 z

第一个数字显示了数据段中两个变量的偏移量,第二个数字是它们的大小。
重定位表现在也看起来像 -
0000000000000000 R_X86_64_64       x
0000000000000008 R_X86_64_64       .data

你可以看到现在有两个条目。一个是将 x 的地址存储在 y 中(偏移量为 0),另一个是将 y 的地址存储在 z 中(偏移量为 8)。你看到的不是 y,而是 .data,因为数据段的地址与 y 的地址相同,因为 y 在偏移量 0 处。
因此,通过查看重定位表,您可以找到所有变量(或函数)的绝对引用。

谢谢。但是仅通过检查二进制文件“main”是否可能找到它?重新创建中间文件并不总是简单的。 - ugoren
@ugoren 可执行文件也存在相同的重定位表。由于这些是 64 位引用。 - Ajay Brahmakshatriya
尽管在剥离二进制文件时可能会消失一些名称 - Ajay Brahmakshatriya
重定位条目在“main”中不存在。我没有剥离它 - 我编译的方式与我的问题完全相同。 - ugoren
如果您无法控制二进制文件的链接方式,除了搜索变量的地址(就像您的答案中所做的那样),就没有太多可以做的了。但是,正如您所猜测的那样,这并不总是有效的。 - Ajay Brahmakshatriya
显示剩余3条评论

0

这是我找到的方法。它适用于这个简单的例子,但不幸的是对于我的实际情况并不适用。我不确定区别在哪里。

我正在寻找二进制文件 main 中符号 x 的用户:

$ objdump -t main | grep -w x
0000000000000000 l    df *ABS*  0000000000000000              x.c
0000000000601040 g     O .data  0000000000000004              x

所以x在偏移量00601040。我查找这个地址,反转它(因为字节序的原因,我猜):

$ objdump -s main | egrep '^Contents of section|40106000'
... omitted irrelevant sections ...
Contents of section .data:
 601028 00000000 00000000 40106000 00000000  ........@.`.....

因此,在.data中,偏移量为601030的符号包含了这个地址。

$ objdump -t main | grep 601030
0000000000601030 g     O .data  0000000000000008              y

因此,引用是来自y

在我的实际情况中,地址可以在.dynsym部分找到,而objdump -t在那里找不到任何符号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接