[lld] r362078 - [ELF] Implement Local Dynamic style TLSDESC for x86-64

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu May 30 03:00:20 PDT 2019


Author: maskray
Date: Thu May 30 03:00:20 2019
New Revision: 362078

URL: http://llvm.org/viewvc/llvm-project?rev=362078&view=rev
Log:
[ELF] Implement Local Dynamic style TLSDESC for x86-64

For the Local Dynamic case of TLSDESC, _TLS_MODULE_BASE_ is defined as a
special TLS symbol that makes:

1) Without relaxation: it produces a dynamic TLSDESC relocation that
computes 0. Adding @dtpoff to access a TLS symbol.
2) With LD->LE relaxation: _TLS_MODULE_BASE_ at tpoff = 0 (lowest address in
the TLS block). Adding @tpoff to access a TLS symbol.

For 1), this saves dynamic relocations and GOT slots as otherwise
(General Dynamic) we would create an R_X86_64_TLSDESC and reserve two
GOT slots for each symbol.

Add ElfSym::TlsModuleBase and change the signature of getTlsTpOffset()
to special case _TLS_MODULE_BASE_.

Reviewed By: ruiu

Differential Revision: https://reviews.llvm.org/D62577

Added:
    lld/trunk/test/ELF/x86-64-tlsdesc-ld.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Thu May 30 03:00:20 2019
@@ -584,24 +584,28 @@ static Relocation *getRISCVPCRelHi20(con
 
 // A TLS symbol's virtual address is relative to the TLS segment. Add a
 // target-specific adjustment to produce a thread-pointer-relative offset.
-static int64_t getTlsTpOffset() {
+static int64_t getTlsTpOffset(const Symbol &S) {
+  // On targets that support TLSDESC, _TLS_MODULE_BASE_ at tpoff = 0.
+  if (&S == ElfSym::TlsModuleBase)
+    return 0;
+
   switch (Config->EMachine) {
   case EM_ARM:
   case EM_AARCH64:
     // Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
     // followed by a variable amount of alignment padding, followed by the TLS
     // segment.
-    return alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
+    return S.getVA(0) + alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
   case EM_386:
   case EM_X86_64:
     // Variant 2. The TLS segment is located just before the thread pointer.
-    return -alignTo(Out::TlsPhdr->p_memsz, Out::TlsPhdr->p_align);
+    return S.getVA(0) - alignTo(Out::TlsPhdr->p_memsz, Out::TlsPhdr->p_align);
   case EM_PPC64:
     // The thread pointer points to a fixed offset from the start of the
     // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
     // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
     // program's TLS segment.
-    return -0x7000;
+    return S.getVA(0) - 0x7000;
   default:
     llvm_unreachable("unhandled Config->EMachine");
   }
@@ -745,12 +749,12 @@ static uint64_t getRelocTargetVA(const I
     // loaders.
     if (Sym.isUndefined())
       return A;
-    return Sym.getVA(A) + getTlsTpOffset();
+    return getTlsTpOffset(Sym) + A;
   case R_RELAX_TLS_GD_TO_LE_NEG:
   case R_NEG_TLS:
     if (Sym.isUndefined())
       return A;
-    return -Sym.getVA(0) - getTlsTpOffset() + A;
+    return -getTlsTpOffset(Sym) + A;
   case R_SIZE:
     return Sym.getSize() + A;
   case R_TLSDESC:

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Thu May 30 03:00:20 2019
@@ -39,6 +39,7 @@ Defined *ElfSym::MipsGpDisp;
 Defined *ElfSym::MipsLocalGp;
 Defined *ElfSym::RelaIpltStart;
 Defined *ElfSym::RelaIpltEnd;
+Defined *ElfSym::TlsModuleBase;
 
 static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
   switch (Sym.kind()) {

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Thu May 30 03:00:20 2019
@@ -436,6 +436,9 @@ struct ElfSym {
   // __rel{,a}_iplt_{start,end} symbols.
   static Defined *RelaIpltStart;
   static Defined *RelaIpltEnd;
+
+  // _TLS_MODULE_BASE_ on targets that support TLSDESC.
+  static Defined *TlsModuleBase;
 };
 
 // A buffer class that is large enough to hold any Symbol-derived

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=362078&r1=362077&r2=362078&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu May 30 03:00:20 2019
@@ -1606,6 +1606,27 @@ template <class ELFT> void Writer<ELFT>:
     if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
       addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800);
 
+  if (Config->EMachine == EM_X86_64) {
+    // On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a
+    // way that:
+    //
+    // 1) Without relaxation: it produces a dynamic TLSDESC relocation that
+    // computes 0.
+    // 2) With LD->LE relaxation: _TLS_MODULE_BASE_ at tpoff = 0 (lowest address in
+    // the TLS block).
+    //
+    // 2) is special cased in @tpoff computation. To satisfy 1), we define it as
+    // an absolute symbol of zero. This is different from GNU linkers which
+    // define _TLS_MODULE_BASE_ relative to the first TLS section.
+    Symbol *S = Symtab->find("_TLS_MODULE_BASE_");
+    if (S && S->isUndefined()) {
+      S->resolve(Defined{/*File=*/nullptr, S->getName(), STB_GLOBAL, STV_HIDDEN,
+                         STT_TLS, /*Value=*/0, 0,
+                         /*Section=*/nullptr});
+      ElfSym::TlsModuleBase = cast<Defined>(S);
+    }
+  }
+
   // This responsible for splitting up .eh_frame section into
   // pieces. The relocation scan uses those pieces, so this has to be
   // earlier.

Added: lld/trunk/test/ELF/x86-64-tlsdesc-ld.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-tlsdesc-ld.s?rev=362078&view=auto
==============================================================================
--- lld/trunk/test/ELF/x86-64-tlsdesc-ld.s (added)
+++ lld/trunk/test/ELF/x86-64-tlsdesc-ld.s Thu May 30 03:00:20 2019
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=LD-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s
+
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s
+
+## Check _TLS_MODULE_BASE_ used by LD produces a dynamic relocation with a value of 0.
+# LD-REL:      .rela.dyn {
+# LD-REL-NEXT:   0x20A0 R_X86_64_TLSDESC - 0x0
+# LD-REL-NEXT: }
+
+## 0x20a0-0x1007 = 4249
+## dtpoff(a) = 8, dtpoff(b) = 12
+# LD:            leaq 4249(%rip), %rax
+# LD-NEXT: 1007: callq *(%rax)
+# LD-NEXT:       movl %fs:8(%rax), %edx
+# LD-NEXT:       addl %fs:12(%rax), %edx
+
+## When producing an executable, the LD code sequence can be relaxed to LE.
+## It is the same as GD->LE.
+## tpoff(_TLS_MODULE_BASE_) = 0, tpoff(a) = -8, tpoff(b) = -4
+
+# NOREL: no relocations
+
+# LE:      movq $0, %rax
+# LE-NEXT: nop
+# LE-NEXT: movl %fs:-8(%rax), %edx
+# LE-NEXT: addl %fs:-4(%rax), %edx
+
+leaq _TLS_MODULE_BASE_ at tlsdesc(%rip), %rax
+call *_TLS_MODULE_BASE_ at tlscall(%rax)
+movl %fs:a at dtpoff(%rax), %edx
+addl %fs:b at dtpoff(%rax), %edx
+
+.section .tbss
+.zero 8
+a:
+.zero 4
+b:
+.zero 4




More information about the llvm-commits mailing list