简体   繁体   中英

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). Here is what I see in the debugger when I study a malloc function:

(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. 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. 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. If there was a single GOT, then all libraries that loaded together must somehow agree on the meanings of each entry in GOT. Having a shared data structure (GOT), filled by all libraries together, would almost certainly create such a dependency.

For example, readelf says that .so-files also have got table:

$ 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.

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).

Second, I had an illusion that GOT is referred to an executable application, instead of any dynamically linkable object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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