The location of a TLS variable is encoded as a DW_OP_const4u/DW_OP_const8u
followed by a DW_OP_push_tls_address (or DW_OP_GNU_push_tls_address https://sourceware.org/bugzilla/show_bug.cgi?id=11616 ).
This change follows up to D81784 and makes relocations types generalized as
R_DTPREL (e.g. R_X86_64_DTPOFF{32,64}, R_PPC64_DTPREL64) use -1 as the
tombstone value as well. This works for both TLS Variant I and Variant II
architectures.
- arm: .long tls(tlsldo) # not working currently (R_ARM_TLS_LDO32 is R_ABS)
- mips64: .dtpreldword tls+32768
- ppc64: .quad tls@DTPREL+0x8000
- riscv: neither GCC nor clang has implemented DW_AT_location. It is likely .long/.quad tls@dtprel+0x800
- x86-32: .long tls@DTPOFF
- x86-64: .long tls@DTPOFF; .quad tls@DTPOFF
tls has a non-negative st_value, so such relocations (st_value+addend)
never resolve to -1 in a normal (not discarded) case.
// clang -fuse-ld=lld -g -ffunction-sections a.c -Wl,--gc-sections // foo and tls will be discarded by --gc-sections. // DW_AT_location [DW_FORM_exprloc] (DW_OP_const8u 0xffffffffffffffff, DW_OP_GNU_push_tls_address) thread_local int tls; int foo() { return ++tls; } int main() {}
Also, drop logic added in D26201 intended to address PR30793. It added a test
(gc-debuginfo-tls.s) using a non-SHF_ALLOC section and a local symbol, which
does not reflect the intended scenario: a relocation in a SHF_ALLOC section
referencing a discarded non-local symbol. For such a non .debug_* section, just
emit an error.
At the moment this won't work for Arm. The debug relocation is R_ARM_TLS_LDO32 which currently maps to the expr R_ABS. I don't know whether that is a problem in ARM.cpp. The only difference I can see is that R_DTPREL is relaxed which we don't want to do on Arm. It maybe that it is best to make R_ARM_TLS_LDO32 (S + A - TLS) to R_DTPREL and then prevent the relaxation for Arm as it is a bit more obvious.
I'll try and run some tests tomorrow.