我正在检查一个正在运行的进程的内存布局,并做了一个有趣的观察。似乎有多个GOT(全局偏移表)。下面是我在学习malloc函数时在调试器中看到的内容:
(gdb) p (void *) 0x7ff5806ae020
$5 = (void *) 0x7ff5806ae020 <malloc@got.plt>
(gdb) p (void *) 0x7ff5806471d0
$6 = (void *) 0x7ff5806471d0 <malloc@got.plt>
(gdb) p (void *) 0x5634ef446030
$7 = (void *) 0x5634ef446030 <malloc@got.plt>我检查了3个不同地址的malloc弹床。当我查看进程的内存映射时,这些地址对应于以下条目:
7ff580647000-7ff580648000 rw-p 0001c000 fd:01 547076 /lib/x86_64-linux-gnu/libpthread-2.31.so
5634ef446000-5634ef447000 rw-p 00003000 fd:02 12248955 /home/user/binary
7ff5806ae000-7ff5806af000 rw-p 0002a000 fd:01 523810 /lib/x86_64-linux-gnu/ld-2.31.so我看到不同的条目对应于不同的“可链接对象”:二进制和两个动态库。
此外,三个弹床中有两个指向实际功能。两个指针都是一样的。第三个弹床指向短节。
(gdb) p *(void **) 0x5634ef446030
$8 = (void *) 0x7ff5804ef1b0 <__GI___libc_malloc>
(gdb) p *(void **) 0x7ff5806471d0
$9 = (void *) 0x7ff580631396 <malloc@plt+6>
(gdb) p *(void **) 0x7ff5806ae020
$10 = (void *) 0x7ff5804ef1b0 <__GI___libc_malloc>真的需要三张跳床吗?如果是,那是为什么?
发布于 2020-10-29 22:50:11
我意识到这样的系统是实现跳床的唯一明智的方式。
在汇编中,对动态链接函数的每个调用指令基本上都引用GOT中该函数的一个索引。索引直接编码在指令中。因此,在静态链接期间,索引必须是最新的。否则,每次程序启动时,动态链接器都必须更新程序代码。显然,这是一项非常繁琐的任务。
此外,每个库都是单独编译的,因此不能依赖于其他库,包括它们确切的GOT布局。如果只有一个GOT,那么所有加载在一起的库必须以某种方式在GOT中的每个条目的含义上达成一致。拥有一个由所有库共同填充的共享数据结构(GOT),几乎肯定会创建这样的依赖关系。
例如,readelf说.so-files也有表:
$ readelf -S /lib/ld-linux.so.2
[18] .got PROGBITS 00029ff4 028ff4 000008 04 WA 0 0 4
[19] .got.plt PROGBITS 0002a000 029000 000028 04 WA 0 0 4
$ readelf -S /usr/lib/libpurple.so.0.13.0
[21] .got PROGBITS 0000000000137318 00136318
0000000000003cd8 0000000000000008 WA 0 0 8不过,libpurple没有.got.plt,这一点我并不完全理解。
我的困惑来自于表被称为“全局”的事实。“全局”一词实际上意味着表在可链接对象级别是全局的,而不是编译模块(.o文件)。
其次,我有一个错觉,GOT引用的是一个可执行的应用程序,而不是任何动态可链接的对象。
https://stackoverflow.com/questions/64581570
复制相似问题