https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128136
Bug ID: 128136
Summary: x86-64: wrong code at -O1 and above: a __seg_gs load
returns the value just stored through __seg_fs at the
same offset
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: kyuwoncho18 at gmail dot com
Target Milestone: ---
Target: x86_64-pc-linux-gnu
#include <asm/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
int x, y = 2;
__attribute__((noinline)) int f(unsigned long p)
{
*(int __seg_fs *)p = 1;
return *(int __seg_gs *)p;
}
int main(void)
{
unsigned long fs;
syscall(SYS_arch_prctl, ARCH_GET_FS, &fs);
unsigned long p = (unsigned long)&x - fs;
syscall(SYS_arch_prctl, ARCH_SET_GS, (unsigned long)&y - p);
if (f(p) != 2)
__builtin_abort();
}
godbolt: https://godbolt.org/z/Ef8cb71TP
The store writes FS base + p, which is x, and the load reads GS base + p, which
is y (the GS base is installed with arch_prctl), so f must return 2 and the
program must exit normally, as it does at -O0 and with -O2 -fno-dse. At -O1,
-O2, -O3 and -Os the load is replaced by the stored constant (f is movl $1,
%fs:(%rdi); movl $1, %eax; ret), f returns 1, and the program aborts.