我正在阅读uprobe tracer的文档,并且有一条指令如何计算内存中函数的偏移量。我在这里引用它。
以下示例显示了如何转储指令指针和%ax 在探测的文本地址注册。在/ bin / zsh中探测zfree函数:
# cd /sys/kernel/debug/tracing/ # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh # objdump -T /bin/zsh | grep -w zfree 0000000000446420 g DF .text 0000000000000012 Base zfree
0x46420是加载的object / bin / zsh中zfree的偏移量 0x00400000。
我不知道为什么,但他们输出0x446420并减去0x400000得到0x46420。它对我来说是错误的。为什么选择0x400000?
我尝试在我的Fedora 23上使用4.5.6-200内核执行相同的操作。
首先我关闭了内存地址随机化
echo 0 > /proc/sys/kernel/randomize_va_space
然后我弄清楚二进制文件在内存中的位置
$ cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp
555555554000-55555560f000 r-xp 00000000 fd:00 2387155 /usr/bin/zsh
取消偏移量
marko@fedora:~ $ objdump -T /bin/zsh | grep -w zfree
000000000005dc90 g DF .text 0000000000000012 Base zfree
并找出zfree通过gdb的位置
$ gdb -p 21067 --batch -ex 'p zfree'
$1 = {<text variable, no debug info>} 0x5555555b1c90 <zfree>
marko@fedora:~ $ python
Python 2.7.11 (default, Mar 31 2016, 20:46:51)
[GCC 5.3.1 20151207 (Red Hat 5.3.1-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(0x5555555b1c90-0x555555554000)
'0x5dc90'
你知道,我在objdump中得到的结果与没有减去任何东西的结果相同。
但是后来我在另一台使用SLES的机器上尝试了相同的操作,并且它与uprobe文档中的相同。
为什么会有这样的差异?我如何计算正确的偏移呢?
答案 0 :(得分:3)
据我所知,差异可能仅由检查二进制文件的构建方式引起。更准确地说 - 如果ELF有固定的加载地址。让我们做简单的实验。我们有简单的测试代码:
int main(void) { return 0; }
然后,以两种方式构建它:
$ gcc -o t1 t.c # create image with fixed load address
$ gcc -o t2 t.c -pie # create load-base independent image
现在,让我们检查这两个图像的加载基地址:
$ readelf -l --wide t1 | grep LOAD
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x00067c 0x00067c R E 0x200000
LOAD 0x000680 0x0000000000600680 0x0000000000600680 0x000228 0x000230 RW 0x200000
$ readelf -l --wide t2 | grep LOAD
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0008cc 0x0008cc R E 0x200000
LOAD 0x0008d0 0x00000000002008d0 0x00000000002008d0 0x000250 0x000258 RW 0x2000
在这里,您可以看到第一张图片需要固定的加载地址 - 0x400000
,第二张图片根本没有地址要求。
现在我们可以比较objdump
讲述main
的地址:
$ objdump -t t1 | grep ' main'
00000000004004b6 g F .text 000000000000000b main
$ objdump -t t2 | grep ' main'
0000000000000710 g F .text 000000000000000b main
如我们所见,地址是一个完整的虚拟地址,如果图像在地址加载,存储在程序头中,main
的第一个字节将占用。当然,第二张图像永远不会在0x0
加载,而是在另一个随机选择的位置加载,这将抵消实际功能位置。