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`.

Reply via email to