简体   繁体   English

linux进程中的多个全局偏移表

[英]Multiple global offset tables in linux process

I'm examining memory layout of a running process and made an interesting observation.我正在检查正在运行的进程的内存布局并进行了有趣的观察。 There seems to be multiple GOTs (global offset table).似乎有多个 GOT(全局偏移表)。 Here is what I see in the debugger when I study a malloc function:这是我在研究 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>

I examine 3 different addresses of a malloc trampoline.我检查了malloc蹦床的 3 个不同地址。 When I look at the memory maps of the process, these addresses correspond to following entries:当我查看进程的内存映射时,这些地址对应于以下条目:

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

I see the different entries correspond to different "linkable objects": the binary and two dynamic libraries.我看到不同的条目对应于不同的“可链接对象”:二进制和两个动态库。

Further, two out of three trampolines point to the actual function.此外,三分之二的蹦床指向实际功能。 And both the pointers are the same.并且两个指针是相同的。 The third trampoline points to the stub.第三个蹦床指向存根。

(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>

Is there really a need for three trampolines?真的需要三个蹦床吗? If yes, then why?如果是,那为什么?

I realised that such system is the only sensible way to implement trampolines.我意识到这样的系统是实现蹦床的唯一明智方法。

In assembly, each call instruction to a dynamically linked function basically refers to an index of the function in GOT.在汇编中,对动态链接函数的每个调用指令基本上都引用了 GOT 中该函数的索引。 The index is encoded in the instruction directly.索引直接在指令中编码。 Therefore, the index must be known the latest during static linkage.因此,在静态链接期间必须知道索引是最新的。 Otherwise, the program code must be updated by the dynamic linker each time the program starts.否则,程序代码必须在每次程序启动时由动态链接器更新。 Clearly, very cumbersome task.显然,非常繁琐的任务。

Moreover, each library is compiled separately, therefore must not depend on other libraries, including their exact GOT layout.此外,每个库都是单独编译的,因此不能依赖其他库,包括它们的确切 GOT 布局。 If there was a single GOT, then all libraries that loaded together must somehow agree on the meanings of each entry in GOT.如果只有一个 GOT,那么所有加载在一起的库必须以某种方式在 GOT 中每个条目的含义上达成一致。 Having a shared data structure (GOT), filled by all libraries together, would almost certainly create such a dependency.拥有一个由所有库一起填充的共享数据结构 (GOT),几乎肯定会创建这样的依赖关系。

For example, readelf says that .so-files also have got table:例如, 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

Although, libpurple does not have .got.plt , which I don't fully understand.虽然, libpurple 没有.got.plt ,我不完全理解。

My confusion was coming from a fact that the table is called "global".我的困惑来自一个事实,即该表被称为“全局”。 The word "global" actually means that the table is global at the level of a linkable object, in contrast to a compilation module (.o files).与编译模块(.o 文件)相比,“全局”一词实际上意味着该表在可链接对象级别是全局的。

Second, I had an illusion that GOT is referred to an executable application, instead of any dynamically linkable object.其次,我有一种错觉,即 GOT 指的是可执行应用程序,而不是任何可动态链接的对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM