How can I get the _GLOBAL_OFFSET_TABLE_ address in my program?
Asked Answered
O

3

6

I want to get the address of _GLOBAL_OFFSET_TABLE_ in my program. One way is to use the nm command in Linux, maybe redirect the output to a file and parse that file to get address of _GLOBAL_OFFSET_TABLE_. However, that method seems to be quite inefficient. What are some more efficient methods of doing it?

Onceover answered 13/3, 2012 at 15:11 Comment(0)
U
3

This appears to work:

// test.c
#include <stdio.h>

extern void *_GLOBAL_OFFSET_TABLE_;

int main()
{
    printf("_GLOBAL_OFFSET_TABLE = %p\n", &_GLOBAL_OFFSET_TABLE_);
    return 0;
}

In order to get consistent address of _GLOBAL_OFFSET_TABLE_, matching nm's result, you will need to compile your code with -fPIE to do code-gen as if linking into a position-independent executable. (Otherwise you get a small integer like 0x2ed6 with -fno-pie -no-pie). The GCC default for most modern Linux distros is -fPIE -pie, which would make nm addresses be just offsets relative to an image base, and the runtime address be ASLRed. (This is normally good for security, but you may not want it.)

$: gcc -fPIE -no-pie test.c -o test

It gives:

$ ./test
_GLOBAL_OFFSET_TABLE = 0x6006d0

However, nm thinks different:

$ nm test | fgrep GLOBAL
0000000000600868 d _GLOBAL_OFFSET_TABLE_

Or with a GCC too old to know about PIEs at all, let alone have it -fPIE -pie as the default, -fpic can work.

Unaccountable answered 13/3, 2012 at 15:21 Comment(6)
@Onceover Perhaps you can tell me why nm gives a different value?Unaccountable
OK, when I'll check it I'll let you know :).Onceover
This code is definitely not right. You're printing the first entry of the GOT, which is probably a pointer to DYNAMIC, not the address of the GOT. To print the address of the GOT you should be using &_GLOBAL_OFFSET_TABLE_.Symons
@Unaccountable just add the ampersand as R.. indicated, I believe that will fix it.Inestimable
@ZeZNiQ thanks for your edit on this old answer, but normally (on modern Linux) -fPIE -pie is already the default so I thought I should tweak some. I can confirm weirdness with -fno-pie -no-pie, like printing out 0x2ed6 for 64-bit mode, or 0x2e76 for -m32. I don't fully understand that, so can you take a look at my edit and make sure I didn't mangle any important point you were making?Superfecundation
The GOT is essentially an array of addresses. Therefore, a better declaration is extern void *_GLOBAL_OFFSET_TABLE_[] (as shown in Figure 5.1 of the AMD64 ABI). In this context, the expressions _GLOBAL_OFFSET_TABLE_ and &_GLOBAL_OFFSET_TABLE_ yield the same value.Rightist
T
0

If you use assembly language, you can get _GLOBAL_OFFSET_TABLE_ address without get_pc_thunk.
It is tricky way. :)


Here is the sample code :

$ cat test.s

.global main
main:
 lea HEREIS, %eax   # Now %eax holds address of _GLOBAL_OFFSET_TABLE_      

.section .got
HEREIS:

$ gcc -o test test.s

This is available because .got section is adjacent to the <.got.plt>
Therefore the symbol HEREIS and _GLOBAL_OFFSET_TABLE_ locate at same address.


PS. You can check it works with objdump.

Disassembly of section .got:

080495e8 <HEREIS-0x4>:
 80495e8:   00 00                   add    %al,(%eax)
    ...

Disassembly of section .got.plt:

080495ec <_GLOBAL_OFFSET_TABLE_>:
 80495ec:   00 95 04 08 00 00       add    %dl,0x804(%ebp)
 80495f2:   00 00                   add    %al,(%eax)
 80495f4:   00 00                   add    %al,(%eax)
Talca answered 4/10, 2018 at 17:14 Comment(1)
The question is tagged x86-64 so you can use RIP-relative addressing like lea HEREIS(%rip), %rsi / ... / call printf@plt. Or just _GLOBAL_OFFSET_TABLE_(%rip). If you are going to use a 32-bit absolute address, though, always prefer mov $HEREIS, %eax. LEA is pointless for static addresses except for RIP-relative. (larger code-size to do the same thing with a [disp32] addressing mode)Superfecundation
E
0

The accepted answer addresses the use of -fPIC or -fPIE to get the address of _GLOBAL_OFFSET_TABLE_.

In the event that you have to compile without -fPIC and -fPIE enabled, the _GLOBAL_OFFSET_TABLE_ symbol is referenced relative to the current instruction. So the value retrieved is actually an offset and not an absolute address.

We can still get the actual address by taking advantage of an extension in that allows you to take the address of a label so it can be supplied by value to a goto statement.

void *got_offset, *got_start;
l1:
    got_offset = &_GLOBAL_OFFSET_TABLE_;
got_start = (void *)((uintptr_t)&&l1 + (uintptr_t)got_offset);

The expression &&l1 gives us the address in the code segment of the label where we're getting the address of _GLOBAL_OFFSET_TABLE_. We can then add the value of this address to the stored offset to give us the actual address of _GLOBAL_OFFSET_TABLE_.

Engrail answered 12/8 at 15:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.