-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
Since e8ea476 we have support for TLS on x86 Linux, but this does not work on AArch64.
For AArch64 we do now have the tpidr register accessible, which is one piece of the puzzle.
The other part is that the compiler does not emit any TLS hint in the DWARF. Example code:
#include <pthread.h>
__thread int tls1=10;
void *start(void* ptr) {
int a=10+tls1;
return NULL;
}
int main() {
pthread_t t1;
pthread_create(&t1, NULL, start, NULL);
void* r;
pthread_join(t1, &r);
return 0;
}
Compiled with clang for AArch64 we get this description:
0x00000023: DW_TAG_variable
DW_AT_name ("tls1")
DW_AT_type (0x0000002b "int")
DW_AT_external (true)
DW_AT_decl_file ("/tmp/test.c")
DW_AT_decl_line (3)
For x86 you get:
0x000000e6: DW_TAG_variable
DW_AT_name ("tls1")
DW_AT_decl_file ("/tmp/test.c")
DW_AT_decl_line (3)
DW_AT_decl_column (0x0e)
DW_AT_type (0x00000057 "int")
DW_AT_external (true)
DW_AT_location (DW_OP_const8u 0x0, DW_OP_GNU_push_tls_address)
Arm has not decided on a way to represent TLS variables in this same way (see AArch64_ELFTargetObjectFile::Initialize).
I briefly tried flipping that boolean so AArch64 did emit it, then using tpidr as the thread pointer. However the existing calculations do not work and I don't have time right now to see what the data structures are supposed to be.
My hacks aside, a vanilla LLDB doesn't see the variable at all:
(lldb) p tls1
error: <user expression 0>:1:1: use of undeclared identifier 'tls1'
1 | tls1
| ^
GDB can read it:
(gdb) p tls1
$1 = 10
Apparently GDB is using thread_db from glibc to work this out, but I don't have the details.
We would I think have to:
- Mark tpidr as the thread pointer register.
- Pass this information to glibc somehow, using the symbol's address as the offset.
- Read the resulting location.