On i386, _GLOBAL_OFFSET_TABLE_ should reference the location of .got.plt. However, the following piece of code prints out a bogus value: ``` $ cat foo.c #include <stdio.h> extern char _GLOBAL_OFFSET_TABLE_[]; char *ptr = _GLOBAL_OFFSET_TABLE_; int main() { printf("%lx\n", (unsigned long)ptr); } $ i686-linux-gnu-gcc-12 -m32 -c foo.c $ i686-linux-gnu-gcc-12 -m32 -o foo foo.o $ ./foo ffffffd0 ``` This is because the relocation for .data is of type R_386_GOTPC. It should be R_386_32. ``` $ readelf -r foo.o Relocation section '.rel.text' at offset 0x234 contains 5 entries: Offset Info Type Sym. Value Symbol's Name 00000010 00000802 R_386_PC32 00000000 __x86.get_pc_thunk.ax 00000015 0000060a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_ 0000001b 00000509 R_386_GOTOFF 00000000 ptr 00000025 00000309 R_386_GOTOFF 00000000 .rodata 0000002d 00000904 R_386_PLT32 00000000 printf Relocation section '.rel.data.rel' at offset 0x25c contains 1 entry: Offset Info Type Sym. Value Symbol's Name 00000000 0000060a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_ ``` I found this bug when writing a test for the mold linker. Related to: https://github.com/rui314/mold/issues/693
Surely this is a Binutils (assembler) bug? gcc emits ptr: .long _GLOBAL_OFFSET_TABLE_
Perhaps s/bug/feature/ Some symbol names are simply special in certain assembler dialects and imply certain relocations, in other assembler dialects all relocations are explicit. _GLOBAL_OFFSET_TABLE_ begins with underscore and upper case letter, so it is a reserved name, so it is fine if the above testcase means something different from what you expect.
It would be unfortunate if that makes it difficult or even impossible to make a R_386_32 relocation for the address of GOT in hand-written assembly. In any case, it seems GCC is not making the rules here, so this should be reported against Binutils so they can clarify the situation?
I think there are ways to get around it, adding an alias to _G_O_T_ and using that alias.
To access this special symbol: [hjl@gnu-tgl-3 tmp]$ cat c.c #include <stdio.h> extern char GLOBAL_OFFSET_TABLE[]; char *ptr = GLOBAL_OFFSET_TABLE; int main() { printf("%lx\n", (unsigned long)ptr); } [hjl@gnu-tgl-3 tmp]$ gcc -m32 c.c /usr/local/bin/ld: /tmp/ccK14eSl.o:(.data+0x0): undefined reference to `GLOBAL_OFFSET_TABLE' collect2: error: ld returned 1 exit status [hjl@gnu-tgl-3 tmp]$ gcc -m32 c.c -Wl,--defsym,GLOBAL_OFFSET_TABLE=_GLOBAL_OFFSET_TABLE_ [hjl@gnu-tgl-3 tmp]$ ./a.out 804bff4 [hjl@gnu-tgl-3 tmp]$
If it silently produces a value that doesn't make sense, shouldn't we ban the use of the variable or at least show a warning?
(In reply to Rui Ueyama from comment #6) > If it silently produces a value that doesn't make sense, shouldn't we ban > the use of the variable or at least show a warning? I opened: https://sourceware.org/bugzilla/show_bug.cgi?id=29551
GCC generates _GLOBAL_OFFSET_TABLE_ to indicate GOTPC32 relocation. It can't be treated as a normal symbol.
_GLOBAL_OFFSET_TABLE_ is in the implementation reserved namespace (due to the underscore and capital letter) so an user using it and thinking it should do something is just undefined.
(In reply to Rui Ueyama from comment #6) > If it silently produces a value that doesn't make sense, shouldn't we ban > the use of the variable or at least show a warning? That is PR 51437 for a warning on reserved names.