Bug 106835 - [i386] Taking an address of _GLOBAL_OFFSET_TABLE_ produces a wrong value
Summary: [i386] Taking an address of _GLOBAL_OFFSET_TABLE_ produces a wrong value
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 11.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-09-05 08:53 UTC by Rui Ueyama
Modified: 2022-10-21 02:55 UTC (History)
4 users (show)

See Also:
Host:
Target: i?86-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rui Ueyama 2022-09-05 08:53:16 UTC
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
Comment 1 Alexander Monakov 2022-09-05 08:57:54 UTC
Surely this is a Binutils (assembler) bug? gcc emits

ptr:
        .long   _GLOBAL_OFFSET_TABLE_
Comment 2 Jakub Jelinek 2022-09-05 09:37:01 UTC
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.
Comment 3 Alexander Monakov 2022-09-05 11:18:37 UTC
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?
Comment 4 Jakub Jelinek 2022-09-05 11:21:17 UTC
I think there are ways to get around it, adding an alias to _G_O_T_ and using that alias.
Comment 5 H.J. Lu 2022-09-05 16:46:54 UTC
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]$
Comment 6 Rui Ueyama 2022-09-06 01:05:16 UTC
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?
Comment 7 H.J. Lu 2022-09-06 15:55:32 UTC
(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
Comment 8 H.J. Lu 2022-09-06 21:58:11 UTC
GCC generates _GLOBAL_OFFSET_TABLE_ to indicate GOTPC32 relocation.  It can't be
treated as a normal symbol.
Comment 9 Andrew Pinski 2022-10-21 02:54:16 UTC
_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.
Comment 10 Andrew Pinski 2022-10-21 02:55:32 UTC
(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.