[lld] 6fa1343 - [ELF] Resolve R_DTPREL in .debug_* referencing discarded symbols to -1

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 3 09:51:50 PDT 2020


Author: Fangrui Song
Date: 2020-07-03T09:50:30-07:00
New Revision: 6fa1343bb3e8a59116cdafc4186c85d6c6ce12df

URL: https://github.com/llvm/llvm-project/commit/6fa1343bb3e8a59116cdafc4186c85d6c6ce12df
DIFF: https://github.com/llvm/llvm-project/commit/6fa1343bb3e8a59116cdafc4186c85d6c6ce12df.diff

LOG: [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 at DTPREL+0x8000
* riscv: neither GCC nor clang has implemented DW_AT_location. It is likely .long/.quad tls at dtprel+0x800
* x86-32: .long tls at DTPOFF
* x86-64: .long tls at DTPOFF; .quad tls at 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

Added: 
    lld/test/ELF/debug-dead-reloc-tls-arm.s
    lld/test/ELF/debug-dead-reloc-tls.s
    lld/test/ELF/gc-sections-tls.s

Modified: 
    lld/ELF/InputSection.cpp

Removed: 
    lld/test/ELF/gc-debuginfo-tls.s


################################################################################
diff  --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 8376ac4bfdf9..fa7c0fb9b4c1 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -907,12 +907,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
       continue;
     }
 
-    if (sym.isTls() && !Out::tlsPhdr) {
-      target->relocateNoSym(bufLoc, type, 0);
-      continue;
-    }
-
-    if (isDebug && type == target->symbolicRel) {
+    if (isDebug && (type == target->symbolicRel || expr == R_DTPREL)) {
       // Resolve relocations in .debug_* referencing (discarded symbols or ICF
       // folded section symbols) to a tombstone value. Resolving to addend is
       // unsatisfactory because the result address range may collide with a
@@ -924,6 +919,10 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
       // to resolve an address attribute (which may have a non-zero addend) to
       // -1+addend (wrap around to a low address).
       //
+      // R_DTPREL type relocations represent an offset into the dynamic thread
+      // vector. The computed value is st_value plus a non-negative offset.
+      // Negative values are invalid, so -1 can be used as the tombstone value.
+      //
       // If the referenced symbol is discarded (made Undefined), or the
       // section defining the referenced symbol is garbage collected,
       // sym.getOutputSection() is nullptr. `ds->section->repl != ds->section`

diff  --git a/lld/test/ELF/debug-dead-reloc-tls-arm.s b/lld/test/ELF/debug-dead-reloc-tls-arm.s
new file mode 100644
index 000000000000..146133a5c8c0
--- /dev/null
+++ b/lld/test/ELF/debug-dead-reloc-tls-arm.s
@@ -0,0 +1,23 @@
+# REQUIRES: arm
+## Test we resolve relocations referencing TLS symbols in .debug_* sections to
+## a tombstone value if the referenced TLS symbol is discarded.
+
+# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+# RUN: ld.lld --gc-sections %t.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK:      Contents of section .debug_info:
+## FIXME: Use ffffffff
+# CHECK-NEXT:  0000 00000000
+
+.globl _start
+_start:
+  bx lr
+
+.section .tbss,"awT",%nobits
+.globl tls
+  .long 0
+
+.section .debug_info
+## R_ARM_TLS_LDO32
+  .long tls(tlsldo)

diff  --git a/lld/test/ELF/debug-dead-reloc-tls.s b/lld/test/ELF/debug-dead-reloc-tls.s
new file mode 100644
index 000000000000..1b26a920d3dd
--- /dev/null
+++ b/lld/test/ELF/debug-dead-reloc-tls.s
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+## Test we resolve relocations referencing TLS symbols in .debug_* sections to
+## a tombstone value if the referenced TLS symbol is discarded.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld --gc-sections %t.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK:      Contents of section .debug_info:
+# CHECK-NEXT:  0000 ffffffff ffffffff ffffffff ffffffff
+# CHECK-NEXT:  0010 ffffffff ffffffff
+
+.globl _start
+_start:
+  ret
+
+.section .tbss,"awT", at nobits
+.globl global
+local:
+global:
+  .quad 0
+
+.section .debug_info
+## On ppc64, .quad local at dtprel+0x8000 (st_value 0 is supposed to point to
+## 0x8000 bytes past the start of ## the dynamic TLS vector. References usually
+## have an addend of 0x8000). MIPS is similar. RISC-V uses 0x800.
+  .quad local at dtpoff+0x8000
+  .quad global at dtpoff+0x8000
+
+## Many other architectures don't use an offset. GCC x86-64 uses a 32-bit value.
+  .long global at dtpoff
+  .long -1

diff  --git a/lld/test/ELF/gc-debuginfo-tls.s b/lld/test/ELF/gc-debuginfo-tls.s
deleted file mode 100644
index 2fe6a32965d4..000000000000
--- a/lld/test/ELF/gc-debuginfo-tls.s
+++ /dev/null
@@ -1,24 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: ld.lld %t.o --gc-sections -shared -o %t1
-# RUN: ld.lld %t.o -shared -o %t2
-# RUN: llvm-readobj --symbols %t1 | FileCheck %s --check-prefix=GC
-# RUN: llvm-readobj --symbols %t2 | FileCheck %s --check-prefix=NOGC
-
-# NOGC:      Symbol {
-# NOGC:        Name: patatino
-# NOGC-NEXT:   Value: 0x0
-# NOGC-NEXT:   Size: 0
-# NOGC-NEXT:   Binding: Local
-# NOGC-NEXT:   Type: TLS
-# NOGC-NEXT:   Other: 0
-# NOGC-NEXT:   Section: .tbss
-# NOGC-NEXT: }
-
-# GC-NOT: tbss
-
-.section .tbss,"awT", at nobits
-patatino:
-  .long 0
-  .section .noalloc,""
-  .quad patatino

diff  --git a/lld/test/ELF/gc-sections-tls.s b/lld/test/ELF/gc-sections-tls.s
new file mode 100644
index 000000000000..ccc9ac3c74e5
--- /dev/null
+++ b/lld/test/ELF/gc-sections-tls.s
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+## Relocation in a non .debug_* referencing a discarded TLS symbol is invalid.
+## If we happen to have no PT_TLS, we will emit an error.
+# RUN: not ld.lld %t.o --gc-sections -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# ERR: error: {{.*}}.o has an STT_TLS symbol but doesn't have an SHF_TLS section
+
+## If we happen to have a PT_TLS, we will resolve the relocation to
+## an arbitrary value (current implementation uses a negative value).
+# RUN: echo '.section .tbss,"awT"; .globl root; root: .long 0' | \
+# RUN:   llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
+# RUN: ld.lld --gc-sections -u root %t.o %t1.o -o %t
+# RUN: llvm-readelf -x .noalloc %t | FileCheck %s
+
+# CHECK:      Hex dump of section '.noalloc':
+# CHECK-NEXT: 0x00000000 {{[0-9a-f]+}} ffffffff
+
+.section .tbss,"awT", at nobits
+tls:
+  .long 0
+
+.section .noalloc,""
+  .quad tls+0x8000


        


More information about the llvm-commits mailing list