https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117149
Bug ID: 117149
Summary: GCC's optimizer intermittently generates erroneous
thread-local storage code, causing segmentation fault
Product: gcc
Version: 14.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: devraymondsh at gmail dot com
Target Milestone: ---
I have encountered a critical bug in GCC's optimizer when compiling a small
project using nolibc. The project doesn't utilize thread-local storage (TLS) at
all, yet GCC generates instructions to load from the `%fs` register, which is
used to reference thread-local variables in x86-64 architecture. This behavior
is incorrect and leads to a segmentation fault when the generated program is
run.
Specifically, the following problematic instruction is generated:
401010: 64 48 8b 04 25 28 00 00 00 mov %fs:0x28,%rax
This instruction attempts to load a value from the TLS area into `%rax`, which
shouldn't happen because the project does not involve any thread-local
variables. The loading from `%fs:0x28` causes a segmentation fault when
executed, as this area is not valid for this simple nolibc program.
Steps to Reproduce:
1. Here’s a minimal reproducible example:
static void memcpy(volatile char *__restrict dest, const char *__restrict src,
long n) {
for (long i = 0; i < n; ++i) dest [i] = src [i];
}
extern "C" void __attribute__((noinline, noreturn)) start(void *s) {
const char source [] = "Hello, World!";
char dest [20] = {0};
memcpy(dest, source, sizeof(source));
__asm__ __volatile__("syscall" ::"a"(60), "D"(0) : "rcx", "r11", "memory");
__builtin_unreachable();
}
__asm__(".text \n"
".global _start \n"
"_start: \n"
" xor %rbp,%rbp \n"
" mov %rsp,%rdi \n"
" andq $-16,%rsp \n"
" call start \n");
2. Compile the code with optimization flags:
gcc gcc_bug.cpp -o gcc_bug -ffreestanding -nostdlib -static -O3
3. Disassemble the binary using:
objdump -D --section=.text ./gcc_bug
The disassembly reveals that, at address `0x401010`, GCC inserts the following
invalid instruction:
401010: 64 48 8b 04 25 28 00 00 00 mov %fs:0x28,%rax
This is unexpected, as there are no thread-local variables in the program. This
bug appears sporadically when using different optimization flags such as
`-static`, `-fstack-protector`, `-flto`, or various `-Ox` levels.
Notes:
- The bug does not always appear, but it is more likely to manifest with
different combinations of optimization flags like `-static`,
`-fstack-protector`, `-flto`, and `-Ox`.