####Test case:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
__thread int x = 0;
int main()
{
int tmp = x;
tmp ++;
printf("val: %d\n", tmp);
return 0;
}
Question: how to get the address of thread local variable "x"?
####Linux AArch64
Assembly(gcc -S)
mrs x0, tpidr_el0 // Line 1: TCB address
add x0, x0, #:tprel_hi12:x, lsl #12
add x0, x0, #:tprel_lo12_nc:x // Line 3: add the offset of "x"
ldr w0, [x0]
Disassembly(after link)
00000000000007a4 <main>:
7a4: a9be7bfd stp x29, x30, [sp, #-32]!
7a8: 910003fd mov x29, sp
7ac: d53bd040 mrs x0, tpidr_el0
7b0: 91400000 add x0, x0, #0x0, lsl #12
7b4: 91004000 add x0, x0, #0x10
7b8: b9400000 ldr w0, [x0]
For JIT: base addr + offset.
-
TCB address can be obtained via system register at runtime, i.e. "mrs"
-
the offset of "x" to TCB is determined during the compiler time.
Reference: https://blog.iret.xyz/article.aspx/thread_pointer_aarch64
####Macos Apple Silicon
Reference: http://www.jakubkonka.com/2021/01/21/llvm-tls-apple-silicon.html
Assembly(gcc -S)
_main: ; @main
...
adrp x8, _x@TLVPPAGE // Line 1:
ldr x8, [x8, _x@TLVPPAGEOFF] // Line 2
ldr x9, [x8] // Line 3:
mov x0, x8
blr x9 // Line 5:
mov w10, #0
stur wzr, [x29, #-4]
ldr w11, [x0] // Line 8:
stur w11, [x29, #-8]
ldur w11, [x29, #-8]
add w11, w11, #1 ; =1
Lines 1-2: get the address of of the __thread_vars section
Line 3: get the address of function tlv_get_address
Line 5: call function tlv_get_address
Line 8: address of "x" is returned in "x0" register.
before link:
c: 08 00 00 90 adrp x8, #0
10: 08 01 40 f9 ldr x8, [x8]
14: 09 01 40 f9 ldr x9, [x8]
18: e0 03 08 aa mov x0, x8
1c: 20 01 3f d6 blr x9
after link:
100003f0c: 28 00 00 b0 adrp x8, #20480
100003f10: 08 21 00 91 add x8, x8, #8 // ldr -> add.
100003f14: 09 01 40 f9 ldr x9, [x8]
100003f18: e0 03 08 aa mov x0, x8
100003f1c: 20 01 3f d6 blr x9
Question: how can JIT generate this code sequence?
I have a WIP PR to generate these offset/address in JIT: dotnet/runtime#87082