Dear x86 and x64 developers, I and JonY are fumbling for implementation of native TLS support for x86 and x64 on Windows. Similarly to that on Linux, the address of a thread local object on Windows is calculated via indirection from the FS or GS segment register, but requires more than one steps. We have trouble comprehending how TLS works on Linux at the moment:
Compiling this program: ``` int a = 12345; int get_a(void){ return a; } __thread int b = 67890; int get_b(void){ return b; } ``` with `gcc -O2 -S` on x64 results in: ``` .file "test.c" .text .p2align 4,,15 .globl get_a .type get_a, @function get_a: .LFB0: .cfi_startproc movl a(%rip), %eax ret .cfi_endproc .LFE0: .size get_a, .-get_a .p2align 4,,15 .globl get_b .type get_b, @function get_b: .LFB1: .cfi_startproc movl %fs:b@tpoff, %eax ret .cfi_endproc .LFE1: .size get_b, .-get_b .globl b .section .tdata,"awT",@progbits .align 4 .type b, @object .size b, 4 b: .long 67890 .globl a .data .align 4 .type a, @object .size a, 4 a: .long 12345 .ident "GCC: (Debian 6.3.0-18) 6.3.0 20170516" .section .note.GNU-stack,"",@progbits ``` The questions are: 0) What is the magical `@tpoff` suffix supposed to do? The `@ntpoff` and `@dtpoff` things are documented in System V ABI but there doesn't seem to be anything about `@tpoff`. 1) How does LD tell that `b` (a thread-local integer) is different from `a` (a static integer)? `a` is apparently offset from RIP, but what thing is `b` offset from? 2) TLS initializers are placed into specially named sections. The sections will have the names like `.tls$XXX` where `$XXX` is used to sort these sections and discarded thereafter. How is LD supposed to associate the section containing the initializer with the symbol of object being initialized, without disordering? Any help will be appreciated. -- Best regards, LH_Mouse