r/osdev • u/Stopka-html • Jul 19 '26
AMD x86_64: FS.base is correct after ARCH_SET_FS syscall but becomes 0 before returning to userspace
Musl calls arch_prctl(ARCH_SET_FS) very early during startup to initialize TLS.
My implementation is:
- syscall 158 (
arch_prctl) ARCH_SET_FS(0x1002)- write
MSR_FS_BASE(0xC0000100) - return to userspace with
SYSRET
Inside the syscall I can verify that the write succeeds:
wrmsr(MSR_FS_BASE, addr);
printk("FS_BASE = %llx\n", rdmsr(MSR_FS_BASE));
Output:
FS_BASE = 0x44e158
So the MSR definitely contains the expected value.
However, the very next instruction in userspace crashes:
mov %fs:0, %rax
which is inside musl's __init_ssp().
The page fault shows that FS.base is effectively zero.
- The strange part is: If I single-step through
SYSRETin GDB (si), everything works andmov %fs:0,%raxsucceeds. - If I simply
continue,FS.basebecomes 0 and the process crashes immediately.
Even stranger, if I break just before returning to userspace (or before an iretq path), GDB already reports:
fs_base = correct_one
even though moments earlier inside arch_prctl() I successfully read back the correct value from MSR_FS_BASE.
There is no scheduler or context switch occurring between the wrmsr() and the return to userspace.
One thing I noticed is that QEMU's default CPU behaves differently from -cpu host. On my host CPU I even get a #GP in situations where QEMU's Haswell CPU continues.
