从问题看来,您正在分析一个库函数。
要了解正在测量的功能是什么,您有 2 个选项:
1运行使用下面库的程序gdb
并停在main
. 此时,获取pid
程序PID=...
并执行“cat /proc/$PID/maps”。在那里你应该看到这样的东西:
➜ ~ ps
PID TTY TIME CMD
18533 pts/4 00:00:00 zsh
18664 pts/4 00:00:00 ps
➜ ~ PID=18533
➜ ~ cat /proc/$PID/maps
00400000-004a2000 r-xp 00000000 08:01 3670052 /bin/zsh5
006a1000-006a2000 r--p 000a1000 08:01 3670052 /bin/zsh5
006a2000-006a8000 rw-p 000a2000 08:01 3670052 /bin/zsh5
006a8000-006bc000 rw-p 00000000 00:00 0
...
7fa174cc9000-7fa174ccd000 r-xp 00000000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ccd000-7fa174ecc000 ---p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecc000-7fa174ecd000 r--p 00003000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecd000-7fa174ece000 rw-p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
...
这7fa174cc9000
是/lib/x86_64-linux-gnu/libcap.so.2.22
图书馆的基址。因此,您获得的所有地址都readelf -s
将被该值抵消。知道基地址,您可以计算出文件中的原始偏移量。
即,如果您获得了7fa174206370
库的值和基地址,7fa1741cf000
则偏移量为7fa174206370 - 7fa1741cf000 = 37370
. 在我的示例中,它sigsuspend
来自 GLIBC:
94: 0000000000037370 132 FUNC WEAK DEFAULT 12 sigsuspend@@GLIBC_2.2.5
2gdb
在使用这些库的程序上运行。它要么立即在内存中找到加载的库,要么需要指向.text
库的部分。
> gdb
(gdb) attach YOUR_PID
(a lot of output about symbols)
(gdb) x/i 0x00007fa174206386
=> 0x7fa174206386 <sigsuspend+22>: cmp $0xfffffffffffff000,%rax
这样你就知道0x7fa174206386
里面了sigsuspend
。
如果gdb
自己不加载任何符号(附加后没有输出),您可以像选项1Reading symbols from ... Loading symbols for ...
一样查找库的基地址,然后添加部分的偏移量.text
➜ ~ readelf -S /lib/x86_64-linux-gnu/libcap.so.2.22 | grep '.text.'
[11] .text PROGBITS 0000000000001620 00001620
7fa174cc9000 + 0000000000001620
以十六进制给出7FA174CCA620
,然后gdb
按上述方式附加并执行
(gdb) add-symbol-file /lib/x86_64-linux-gnu/libcap.so.2.22 7FA174CCA620
然后,即使不自行加载符号,您也应该能够找到符号(通过x/i ADDRESS
选项1 )。gdb
请询问是否有任何不清楚的地方,我会尽力解释。
澄清为什么会这样:
观察到的行为是由于库被编译为Position-Independent Code。它使我们能够轻松地支持动态库。PIC 本质上意味着库的 ELF 具有.plt
和.got
部分,并且可以在任何基地址加载。PLT 是过程链接表,它包含对位于其他模块中的函数调用的陷阱,这些陷阱首先进入程序解释器以允许它重新定位被调用的函数,然后在第一次调用后跳转到该函数。它之所以起作用,是因为程序解释器更新了 GOT(全局偏移表),其中包含要调用的函数的地址。最初,GOT 被初始化,以便在第一次函数调用时跳转到程序解释器的函数,该函数执行当前调用函数的解析。
在 x86-64 上,PLT 条目通常如下所示:
0000000000001430 <free@plt>:
1430: ff 25 e2 2b 20 00 jmpq *0x202be2(%rip) # 204018 <_fini+0x201264>
1436: 68 00 00 00 00 pushq $0x0
143b: e9 e0 ff ff ff jmpq 1420 <_init+0x28>
第一个jmpq
是跳转到地址,存储在 GOT 的 location 中%rip + 0x202be2
:
[20] .got PROGBITS 0000000000203fd0 00003fd0
0000000000000030 0000000000000008 WA 0 0 8
%rip + 0x202be2
将是0x204012
,并将其添加到库的基地址以生成与实际加载库的位置相关的绝对地址。即如果它是在 加载的0x7f66dfc03000
,那么相应 GOT 条目的结果地址将是0x7F66DFE07012
。存储在该位置的地址是(在此示例中)free
函数的地址。它由程序解释器维护以指向实际free
的libc
.
更多信息可以在这里找到。