nm命令中的"symbol value"是什么意思?

25

当您列出静态库的符号表时,比如使用命令 nm mylib.a,每个符号旁边显示的8位十六进制数是什么意思?它是每个符号在代码中的相对位置吗?

此外,多个符号是否可以具有相同的符号值?一堆不同的符号都具有符号值00000000是否有问题?


如果处理目标文件,则需要在文档中提供更多明确的信息。它返回的“Value”字段可能对某些人有用,但是对我来说,它的描述和潜在用途一样晦涩难懂。它看起来像是某种偏移量,但不幸的是,文档没有给出任何线索... - Vincent Dupaquis
3个回答

34

这是我用C语言编写的一小段代码:


#include 
#include 

void foo();

int main(int argc, char* argv[]) {
    foo();
}

void foo() {
   printf("Foo bar baz!");
}

我在代码上运行了命令gcc -c foo.c,这是nm foo.o所显示的内容:
000000000000001b T foo
0000000000000000 T main
                 U printf
在这个例子中,我使用的是Ubuntu Linux 64位系统,因此你看到的8位十六进制数在这里变成了16位。 :-)
你看到的十六进制数字是与该对象文件中的代码相关的地址,相对于.text.部分的开头。(假设我们从0x0开始寻址对象文件的各个部分) 如果你运行objdump -td foo.o,会看到下面的输出:
Disassembly of section .text:
0000000000000000 : 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 83 ec 10 sub $0x10,%rsp 8: 89 7d fc mov %edi,-0x4(%rbp) b: 48 89 75 f0 mov %rsi,-0x10(%rbp) f: b8 00 00 00 00 mov $0x0,%eax 14: e8 00 00 00 00 callq 19 19: c9 leaveq 1a: c3 retq
000000000000001b : 1b: 55 push %rbp 1c: 48 89 e5 mov %rsp,%rbp 1f: b8 00 00 00 00 mov $0x0,%eax 24: 48 89 c7 mov %rax,%rdi 27: b8 00 00 00 00 mov $0x0,%eax 2c: e8 00 00 00 00 callq 31 31: c9 leaveq 32: c3 retq
注意,这两个符号与我们在nm中看到的条目完全对齐。请记住,如果将此对象文件链接到其他对象文件,则这些地址可能会发生变化。此外,请注意,当您将该文件链接到系统提供的libc时,0x2c处的callq将发生更改,因为它当前是对printf的不完整调用(它还不知道它在哪里)。
关于你的mylib.a,这里面有更多的内容。你拥有的文件是一个存档文件;它包含了多个目标文件,每个文件都有自己的文本段。例如,在我这里针对/usr/lib/libm.a的nm输出的一部分如下所示:
e_sinh.o:
0000000000000000 r .LC0
0000000000000008 r .LC1
0000000000000010 r .LC2
0000000000000018 r .LC3
0000000000000000 r .LC4
                 U __expm1
                 U __ieee754_exp
0000000000000000 T __ieee754_sinh
e_sqrt.o: 0000000000000000 T __ieee754_sqrt
e_gamma_r.o: 0000000000000000 r .LC0 U __ieee754_exp 0000000000000000 T __ieee754_gamma_r U __ieee754_lgamma_r U __rint
你会看到多个文本段条目 - 在第二列中以T表示 - 位于地址0x0处,但每个单独的文件只有一个文本段符号位于0x0。
至于单个文件在同一地址上具有多个符号,似乎是可能的。毕竟,它只是用于确定数据块位置和大小的表中的一个条目。但我不确定。我以前从未见过多个符号引用同一部分节的情况。有比我更了解这个问题的人可以加入讨论。
希望这能帮到你。

如果您使用x86_64-w64-mingw32-g ++编译示例,则将使用nm看到多个符号引用零地址并带有“A”标记,即该地址在将来不会更改。例如,0000000000000000 A __dll__ 0000000000000000 A __dll_characteristics__。简而言之 - 我发现实际上存在 映射的有用函数。我想知道那意味着什么? - Hi-Angel

3

十六进制数是指向对象文件中符号所在内存偏移量。它实际上是对象代码中的字节数。

链接器使用该值定位并复制符号的值。如果您在nm命令后添加-S选项,可以大致了解其布局,该选项将显示每个符号的值大小。


1

nm 显示符号的值。库或对象文件中的某些符号可能会显示为零,仅因为它们尚未被赋值。它们将在链接时获得其实际值。

有些符号是代码符号,有些是数据等。在链接之前,符号值通常是它所在部分的偏移量。


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