https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66631

--- Comment #3 from Stas Sergeev <stsp at users dot sourceforge.net> ---
The signal handler needs to do the following things:
1. Restore segment registers (init_handler() func)
2. Increment thread-local var (fault_cnt)
3. Do stuff including reads of fault_cnt var

Being thread-local, fault_cnt var is being accessed
with the help of FS, but FS is only valid after the
call to init_handler().
Since fault_cnt is marked as volatile, gcc does not
move the access to it above the init_handler() call,
so that part is fine. What is NOT fine is this:

   0x00000000004438d4 <+20>:    mov    %fs:0x0,%rbp          <-- (bad) TLS
access
   0x00000000004438dd <+29>:    push   %rbx
   0x00000000004438de <+30>:    add    $0xffffffffffffff80,%rsp
   0x00000000004438e2 <+34>:    callq  0x4441b0 <init_handler>   <-- FS now
valid
   0x00000000004438e7 <+39>:    mov    0x35070a(%rip),%rbx        # 0x793ff8
   0x00000000004438ee <+46>:    mov    0x0(%rbp,%rbx,1),%eax     <-- STACK
FAULT

As you can see, gcc moved some TLS access above init_handler(),
which results in a stack fault later when trying to read from
fault_cnt.
To prevent moving any TLS access around init_handler(), I need
to do the following:
asm volatile("":::"fs");
but this gives a compilation error.

Is the explanation clear?

Reply via email to