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.