https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106834
Bug ID: 106834
Summary: GCC creates R_X86_64_GOTOFF64 for 4-bytes immediate
Product: gcc
Version: 12.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: rui314 at gmail dot com
Target Milestone: ---
I think I found a GCC bug. Here is how to reproduce the issue:
```
$ cat foo.c
#include <stdio.h>
extern char _GLOBAL_OFFSET_TABLE_[];
int main() {
printf("%lx", (unsigned long)_GLOBAL_OFFSET_TABLE_);
}
$ gcc-12 -c -fPIC foo.c
$ gcc -o foo foo.o
$ ./foo
Illegal instruction (core dumped)
```
The resulting executable crashes with an illegal instruction because the linker
overwrites instructions with an immediate. Take a look at the following objdump
output:
```
$ objdump -dr foo.o
foo.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # f <main+0xf>
b: R_X86_64_GOTOFF64 _GLOBAL_OFFSET_TABLE_-0x4
f: 48 89 c6 mov %rax,%rsi
12: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # 19 <main+0x19>
15: R_X86_64_PC32 .rodata-0x4
19: 48 89 c7 mov %rax,%rdi
1c: b8 00 00 00 00 mov $0x0,%eax
21: e8 00 00 00 00 call 26 <main+0x26>
22: R_X86_64_PLT32 printf-0x4
26: b8 00 00 00 00 mov $0x0,%eax
2b: 5d pop %rbp
2c: c3 ret
```
At offset 0xb, there's a relocation of type R_X86_64_GOTOFF64. GOTOFF64 makes
the linker to write a 8-bytes offset to a given symbol. However, the
instruction for that relocation is just `mov` and not `movabs`, so the
subsequent 4-bytes are accidentally overwrote byt eh linker.