只是为了给您一些背景信息,以下是我正在努力实现的目标: 我在共享对象文件中嵌入了一个 const char*,以便在 .so 文件本身中有一个版本字符串。我正在做数据分析,这个字符串使我能够让数据知道是哪个版本的软件产生的。这一切都很好。
我遇到的问题是当我尝试直接从 .so 库中读取字符串时。我试着用
nm libSMPselection.so | grep _version_info
得到
000000000003d968 D __SMPselection_version_info
一切正常,符合预期(char* 称为 _SMPselection_version_info)。 然而,我原本希望现在能够打开文件,查找 0x3d968 并开始读取我的字符串,但我得到的只是垃圾。
当我打开 .so 文件并简单地搜索字符串的内容时(我知道它是如何开始的),我可以在地址 0x2e0b4 找到它。在这个地址它在那里,零终止并且如预期的那样。 (我目前使用的是这种方法。)
我不是计算机科学家。有人可以向我解释为什么 nm 显示的符号值不正确,或者换句话说,如果不是符号的地址,符号值是什么?
(顺便说一下,我正在使用 OSX 10.7 的 Mac 工作)
最佳答案
假设它是一个 ELF 或类似结构的二进制文件,您必须考虑加载内容的地址,这受 ELF header 中内容的影响。
在您的二进制文件上使用 objdump -Fd
,您可以让反汇编器还显示符号的确切文件偏移量。
使用 objdump -x
你可以找到这个加载器地址,标准 linux 可执行文件通常是 0x400000。
接下来您需要注意的是查看它是否是间接字符串,您可以使用 objdump -g
轻松完成此操作。当发现字符串是间接字符串时,在objdump -Fd
输出的位置你不会找到字符串,而是地址。您需要从中再次减去加载程序地址。让我向您展示我的一个二进制文件的示例:
objdump -Fd BIN | grep VersionString
45152f: 48 8b 1d 9a df 87 00 mov 0x87df9a(%rip),%rbx # ccf4d0 <acVersionString> (File Offset: 0x8cf4d0)
objdump -x BIN
...
LOAD off 0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12
...
所以我们查看文件中的0x8cf4d0,在十六进制编辑器中找到:
008C:F4D0 D8 C1 89 00 00 00 00 00 01 00 00 00 FF FF FF FF
所以我们在那里取 0x89C1D8,减去 0x400000 得到 0x49c1d8,当我们在十六进制编辑器中查看时,我们发现:
0049:C1D0 FF FF 7F 7F FF FF 7F FF 74 72 75 6E 6B 5F 38 30
0049:C1E0 34 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00
意思是“trunk_8043”。
YMMV,尤其是当它是一些其他文件格式时,但这是这些东西的结构的一般方式,有很多缺点和特殊情况下偏离的细节。
关于c++ - nm 符号值的偏移量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10430655/