[ELF] Resolve R_DTPREL in .debug_* referencing discarded symbols to -1
authorFangrui Song <maskray@google.com>
Fri, 3 Jul 2020 16:50:30 +0000 (09:50 -0700)
committerFangrui Song <maskray@google.com>
Fri, 3 Jul 2020 16:50:30 +0000 (09:50 -0700)
commit6fa1343bb3e8a59116cdafc4186c85d6c6ce12df
treeae6c02d55cc304db591e3c0b4c17ef83b2364259
parenteb46137daa92723b75d828f2db959f2061612622
[ELF] Resolve R_DTPREL in .debug_* referencing discarded symbols to -1

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.

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D82899
lld/ELF/InputSection.cpp
lld/test/ELF/debug-dead-reloc-tls-arm.s [new file with mode: 0644]
lld/test/ELF/debug-dead-reloc-tls.s [new file with mode: 0644]
lld/test/ELF/gc-debuginfo-tls.s [deleted file]
lld/test/ELF/gc-sections-tls.s [new file with mode: 0644]