[lld] r252682 - [elf2] Add support for R_X86_64_TLSLD.

Michael J. Spencer via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 10 17:00:25 PST 2015


Author: mspencer
Date: Tue Nov 10 19:00:24 2015
New Revision: 252682

URL: http://llvm.org/viewvc/llvm-project?rev=252682&view=rev
Log:
[elf2] Add support for R_X86_64_TLSLD.

leaq symbol at tlsld(%rip), %rdi
call __tls_get_addr at plt

symbol at tlsld (R_X86_64_TLSLD) instructs the linker to generate a tls_index entry (two GOT slots) in the GOT for the entire module (shared object or executable) with an offset of 0. The symbol for this GOT entry doesn't matter (as long as it's either local to the module or null), and gold doesn't put a symbol in the dynamic R_X86_64_DTPMOD64 relocation for the GOT entry.

All other platforms defined in http://www.akkadia.org/drepper/tls.pdf except for Itanium use a similar model where global and local dynamic GOT entries take up 2 contiguous GOT slots, so we can handle this in a unified manner if we don't care about Itanium.

While scanning relocations we need to identify local dynamic relocations and generate a single tls_index entry in the GOT for the module and store the address of it somewhere so we can later statically resolve the offset for R_X86_64_TLSLD relocations. We also need to generate a R_X86_64_DTPMOD64 relocation in the RelaDyn relocation section.

This implementation is a bit hacky. It side steps the issue of GotSection and RelocationSection only handling SymbolBody entries by relying on a specific relocation type. The alternative to this seemed to be completely rewriting how GotSection and RelocationSection work, or using a different hacky signaling method.

Added:
    lld/trunk/test/elf2/tls-dynamic.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.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=252682&r1=252681&r2=252682&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue Nov 10 19:00:24 2015
@@ -90,14 +90,23 @@ void InputSection<ELFT>::relocate(
   for (const RelType &RI : Rels) {
     uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
     uint32_t Type = RI.getType(Config->Mips64EL);
+    uint8_t *BufLoc = Buf + RI.r_offset;
+    uintX_t AddrLoc = BaseAddr + RI.r_offset;
+
+    if (Type == Target->getTlsLocalDynamicReloc()) {
+      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
+                          Out<ELFT>::Got->getVA() +
+                              Out<ELFT>::LocalModuleTlsIndexOffset +
+                              getAddend<ELFT>(RI));
+      continue;
+    }
 
     // Handle relocations for local symbols -- they never get
     // resolved so we don't allocate a SymbolBody.
     const Elf_Shdr *SymTab = File.getSymbolTable();
     if (SymIndex < SymTab->sh_info) {
       uintX_t SymVA = getLocalRelTarget(File, RI);
-      Target->relocateOne(Buf + RI.r_offset, BufEnd, Type,
-                          BaseAddr + RI.r_offset, SymVA);
+      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
       continue;
     }
 
@@ -116,7 +125,7 @@ void InputSection<ELFT>::relocate(
                isa<SharedSymbol<ELFT>>(Body)) {
       continue;
     }
-    Target->relocateOne(Buf + RI.r_offset, BufEnd, Type, BaseAddr + RI.r_offset,
+    Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
                         SymVA + getAddend<ELFT>(RI));
   }
 }

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=252682&r1=252681&r2=252682&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Tue Nov 10 19:00:24 2015
@@ -82,6 +82,12 @@ template <class ELFT> void GotSection<EL
   Entries.push_back(Sym);
 }
 
+template <class ELFT> uint32_t GotSection<ELFT>::addLocalModuleTlsIndex() {
+  Entries.push_back(nullptr);
+  Entries.push_back(nullptr);
+  return (Entries.size() - 2) * sizeof(uintX_t);
+}
+
 template <class ELFT>
 typename GotSection<ELFT>::uintX_t
 GotSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
@@ -99,6 +105,8 @@ template <class ELFT> void GotSection<EL
   for (const SymbolBody *B : Entries) {
     uint8_t *Entry = Buf;
     Buf += sizeof(uintX_t);
+    if (!B)
+      continue;
     // MIPS has special rules to fill up GOT entries.
     // See "Global Offset Table" in Chapter 5 in the following document
     // for detailed description:
@@ -177,6 +185,15 @@ template <class ELFT> void RelocationSec
       Body = Body->repl();
 
     uint32_t Type = RI.getType(Config->Mips64EL);
+
+    if (Type == Target->getTlsLocalDynamicReloc()) {
+      P->setSymbolAndType(0, Target->getTlsModuleIndexReloc(),
+                          Config->Mips64EL);
+      P->r_offset =
+          Out<ELFT>::Got->getVA() + Out<ELFT>::LocalModuleTlsIndexOffset;
+      continue;
+    }
+
     bool NeedsCopy = Body && Target->relocNeedsCopy(Type, *Body);
     bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body);
     bool CanBePreempted = canBePreempted(Body, NeedsGot);

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=252682&r1=252681&r2=252682&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Tue Nov 10 19:00:24 2015
@@ -116,6 +116,7 @@ public:
   void finalize() override;
   void writeTo(uint8_t *Buf) override;
   void addEntry(SymbolBody *Sym);
+  uint32_t addLocalModuleTlsIndex();
   bool empty() const { return Entries.empty(); }
   uintX_t getEntryAddr(const SymbolBody &B) const;
 
@@ -371,6 +372,7 @@ template <class ELFT> struct Out {
   static SymbolTableSection<ELFT> *DynSymTab;
   static SymbolTableSection<ELFT> *SymTab;
   static Elf_Phdr *TlsPhdr;
+  static uint32_t LocalModuleTlsIndexOffset;
 };
 
 template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
@@ -391,6 +393,7 @@ template <class ELFT> StringTableSection
 template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
 template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
 template <class ELFT> typename Out<ELFT>::Elf_Phdr *Out<ELFT>::TlsPhdr;
+template <class ELFT> uint32_t Out<ELFT>::LocalModuleTlsIndexOffset = -1;
 
 } // namespace elf2
 } // namespace lld

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=252682&r1=252681&r2=252682&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Tue Nov 10 19:00:24 2015
@@ -215,6 +215,8 @@ X86_64TargetInfo::X86_64TargetInfo() {
   GotRefReloc = R_X86_64_PC32;
   PltReloc = R_X86_64_JUMP_SLOT;
   RelativeReloc = R_X86_64_RELATIVE;
+  TlsLocalDynamicReloc = R_X86_64_TLSLD;
+  TlsModuleIndexReloc = R_X86_64_DTPMOD64;
   LazyRelocations = true;
   PltEntrySize = 16;
   PltZeroEntrySize = 16;
@@ -330,6 +332,7 @@ void X86_64TargetInfo::relocateOne(uint8
   case R_X86_64_PC32:
   case R_X86_64_GOTPCREL:
   case R_X86_64_PLT32:
+  case R_X86_64_TLSLD:
     write32le(Loc, SA - P);
     break;
   case R_X86_64_64:

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=252682&r1=252681&r2=252682&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Tue Nov 10 19:00:24 2015
@@ -29,6 +29,8 @@ public:
   unsigned getPltReloc() const { return PltReloc; }
   unsigned getGotRefReloc() const { return GotRefReloc; }
   unsigned getRelativeReloc() const { return RelativeReloc; }
+  unsigned getTlsLocalDynamicReloc() const { return TlsLocalDynamicReloc; }
+  unsigned getTlsModuleIndexReloc() const { return TlsModuleIndexReloc; }
   unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; }
   unsigned getPltEntrySize() const { return PltEntrySize; }
   bool supportsLazyRelocations() const { return LazyRelocations; }
@@ -67,6 +69,8 @@ protected:
   unsigned GotReloc;
   unsigned PltReloc;
   unsigned RelativeReloc;
+  unsigned TlsLocalDynamicReloc = 0;
+  unsigned TlsModuleIndexReloc;
   unsigned PltEntrySize = 8;
   unsigned PltZeroEntrySize = 0;
   unsigned GotHeaderEntriesNum = 0;

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=252682&r1=252681&r2=252682&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Tue Nov 10 19:00:24 2015
@@ -190,6 +190,15 @@ void Writer<ELFT>::scanRelocs(
     SymbolBody *Body = File.getSymbolBody(SymIndex);
     uint32_t Type = RI.getType(Config->Mips64EL);
 
+    if (Type == Target->getTlsLocalDynamicReloc()) {
+      if (Out<ELFT>::LocalModuleTlsIndexOffset == uint32_t(-1)) {
+        Out<ELFT>::LocalModuleTlsIndexOffset =
+            Out<ELFT>::Got->addLocalModuleTlsIndex();
+        Out<ELFT>::RelaDyn->addReloc({C, RI});
+      }
+      continue;
+    }
+
     // Set "used" bit for --as-needed.
     if (Body && Body->isUndefined() && !Body->isWeak())
       if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body->repl()))

Added: lld/trunk/test/elf2/tls-dynamic.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/tls-dynamic.s?rev=252682&view=auto
==============================================================================
--- lld/trunk/test/elf2/tls-dynamic.s (added)
+++ lld/trunk/test/elf2/tls-dynamic.s Tue Nov 10 19:00:24 2015
@@ -0,0 +1,48 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld2 -shared %t -o %tout
+// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+  leaq  a at tlsld(%rip), %rdi
+  callq __tls_get_addr at PLT
+  leaq  b at tlsld(%rip), %rdi
+  callq __tls_get_addr at PLT
+
+  .global	a
+	.section	.tbss,"awT", at nobits
+  .align 4
+a:
+	.long	0
+  
+  .global	b
+	.section	.tbss,"awT", at nobits
+  .align 4
+b:
+	.long	0
+
+// Get the address of the got, and check that it has two entries.
+
+// CHECK:      Sections [
+// CHECK:          Name: .got
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x20D0
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 16
+
+// CHECK:      Relocations [
+// CHECK:        Section ({{.+}}) .rela.dyn {
+// CHECK-NEXT:     0x20D0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT:   }
+
+// 4297 = (0x20D0 + -4) - (0x1000 + 3) // PC relative offset to got entry.
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: .text:
+// DIS-NEXT:     1000: {{.+}} leaq    4297(%rip), %rdi
+// DIS-NEXT:     1007: {{.+}} callq
+// DIS-NEXT:     100c: {{.+}} leaq    4285(%rip), %rdi




More information about the llvm-commits mailing list