[lld] r218633 - [lld] [ELF] Support for general dynamic TLS relocations on X86_64

Rafael Auler rafaelauler at gmail.com
Mon Sep 29 15:05:27 PDT 2014


Author: rafauler
Date: Mon Sep 29 17:05:26 2014
New Revision: 218633

URL: http://llvm.org/viewvc/llvm-project?rev=218633&view=rev
Log:
[lld] [ELF] Support for general dynamic TLS relocations on X86_64

Summary:
This patch adds support for the general dynamic TLS access model for X86_64 (see www.akkadia.org/drepper/tls.pdf).

To properly support TLS, the patch also changes the __tls_get_addr atom to be a shared library atom instead of a regularly defined atom (the previous lld approach). This closely models the reality of a function that will be resolved at runtime by the dynamic linker and loader itself (ld.so). I was tempted to force LLD to link against ld.so itself to resolve these symbols, but since GNU ld does not need the ld.so library to resolve this symbol, I decided to mimic its behavior and keep hardwired a definition of __tls_get_addr in the lld code.

This patch also moves some important logic that previously was only available to the MIPS lld backend to be used to all ELF backends. This logic, which now lives in the DefaultLayout class, will monitor which external (shared lib) symbols are really imported by the current module and will only populate the dynamic symbol table with used symbols, as opposed to the previous approach of dumping all shared lib symbols in the dynamic symbol table. This is important to this patch to avoid __tls_get_addr from getting injected into all dynamic symbol tables.

By solving the previous problem of always adding __tls_get_addr, now the produced symbol tables are slightly smaller. But this impacted several tests that relied on hardwired/predefined sizes of the symbol table, requiring this patch to update such tests.

Test Plan: Added a LIT test case that exercises a simple use case of TLS variable in a shared library.

Reviewers: ruiu, rafael, Bigcheese, shankarke

Reviewed By: Bigcheese, shankarke

Subscribers: emaste, shankarke, joerg, kledzik, mcrosier, llvm-commits

Projects: #lld

Differential Revision: http://reviews.llvm.org/D5505

Added:
    lld/trunk/test/elf/X86_64/Inputs/generaltls-so.o.yaml
    lld/trunk/test/elf/X86_64/general-dynamic-tls.test
Modified:
    lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
    lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
    lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
    lld/trunk/lib/ReaderWriter/ELF/Atoms.h
    lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
    lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
    lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
    lld/trunk/lib/ReaderWriter/ELF/TODO.txt
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
    lld/trunk/test/elf/X86_64/omagic.test
    lld/trunk/test/elf/X86_64/undef.test
    lld/trunk/test/elf/X86_64/underscore-end.test
    lld/trunk/test/elf/dynamic-segorder.test
    lld/trunk/test/elf/dynamic-undef.test
    lld/trunk/test/elf/undef-from-main-dso.test

Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Mon Sep 29 17:05:26 2014
@@ -262,8 +262,8 @@ public:
 
   void setCreateSeparateROSegment() { _mergeRODataToTextSegment = false; }
 
-  bool hasCoalescedSharedLibPair(StringRef name) const {
-    return _sharedLibCoalescedSymbols.count(name) != 0;
+  bool isDynamicallyExportedSymbol(StringRef name) const {
+    return _dynamicallyExportedSymbols.count(name) != 0;
   }
 
 private:
@@ -300,7 +300,7 @@ protected:
   StringRefVector _rpathList;
   StringRefVector _rpathLinkList;
   std::map<std::string, uint64_t> _absoluteSymbols;
-  llvm::StringSet<> _sharedLibCoalescedSymbols;
+  llvm::StringSet<> _dynamicallyExportedSymbols;
 };
 } // end namespace lld
 

Modified: lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h Mon Sep 29 17:05:26 2014
@@ -57,7 +57,6 @@ bool AArch64DynamicLibraryWriter<ELFT>::
     std::vector<std::unique_ptr<File>> &result) {
   DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
   _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
-  _gotFile->addAtom(*new (_gotFile->_alloc) TLSGETADDRAtom(*_gotFile));
   _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
   result.push_back(std::move(_gotFile));
   return true;

Modified: lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h Mon Sep 29 17:05:26 2014
@@ -56,7 +56,6 @@ bool AArch64ExecutableWriter<ELFT>::crea
     std::vector<std::unique_ptr<File>> &result) {
   ExecutableWriter<ELFT>::createImplicitFiles(result);
   _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
-  _gotFile->addAtom(*new (_gotFile->_alloc) TLSGETADDRAtom(*_gotFile));
   if (_context.isDynamic())
     _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
   result.push_back(std::move(_gotFile));

Modified: lld/trunk/lib/ReaderWriter/ELF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Atoms.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Atoms.h Mon Sep 29 17:05:26 2014
@@ -820,31 +820,6 @@ public:
   ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
 };
 
-class TLSGETADDRAtom : public SimpleELFDefinedAtom {
-public:
-  TLSGETADDRAtom(const File &f) : SimpleELFDefinedAtom(f) {}
-
-  StringRef name() const override { return "__tls_get_addr"; }
-
-  Scope scope() const override { return scopeGlobal; }
-
-  Merge merge() const override { return mergeAsWeak; }
-
-  SectionChoice sectionChoice() const override { return sectionCustomRequired; }
-
-  StringRef customSectionName() const override { return ".text"; }
-
-  ContentType contentType() const override { return typeCode; }
-
-  uint64_t size() const override { return 0; }
-
-  ContentPermissions permissions() const override { return permR_X; }
-
-  Alignment alignment() const override { return Alignment(0); }
-
-  ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
-};
-
 class DYNAMICAtom : public SimpleELFDefinedAtom {
 public:
   DYNAMICAtom(const File &f) : SimpleELFDefinedAtom(f) {}

Modified: lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h Mon Sep 29 17:05:26 2014
@@ -21,6 +21,7 @@
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
@@ -296,6 +297,10 @@ public:
     return 0;
   }
 
+  bool isReferencedByDefinedAtom(const SharedLibraryAtom *sla) const {
+    return _referencedDynAtoms.count(sla);
+  }
+
 protected:
   /// \brief Allocate a new section.
   virtual AtomSection<ELFT> *createSection(
@@ -317,6 +322,7 @@ protected:
   LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _dynamicRelocationTable;
   LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _pltRelocationTable;
   std::vector<lld::AtomLayout *> _absoluteAtoms;
+  llvm::DenseSet<const SharedLibraryAtom *> _referencedDynAtoms;
   const ELFLinkingContext &_context;
 };
 
@@ -556,11 +562,14 @@ ErrorOr<const lld::AtomLayout &> Default
     AtomSection<ELFT> *section =
         getSection(sectionName, contentType, permissions);
     // Add runtime relocations to the .rela section.
-    for (const auto &reloc : *definedAtom)
+    for (const auto &reloc : *definedAtom) {
       if (_context.isDynamicRelocation(*definedAtom, *reloc))
         getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
       else if (_context.isPLTRelocation(*definedAtom, *reloc))
         getPLTRelocationTable()->addRelocation(*definedAtom, *reloc);
+      if (const auto *sla = dyn_cast<SharedLibraryAtom>(reloc->target()))
+        _referencedDynAtoms.insert(sla);
+    }
     return section->appendAtom(atom);
   } else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
     // Absolute atoms are not part of any section, they are global for the whole

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp Mon Sep 29 17:05:26 2014
@@ -259,7 +259,7 @@ void ELFLinkingContext::notifySymbolTabl
     // If strong defined atom coalesces away an atom declared
     // in the shared object the strong atom needs to be dynamically exported.
     // Save its name.
-    _sharedLibCoalescedSymbols.insert(ua->name());
+    _dynamicallyExportedSymbols.insert(ua->name());
 }
 
 } // end namespace lld

Modified: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h Mon Sep 29 17:05:26 2014
@@ -68,9 +68,6 @@ public:
     // 2. Set of shared library atoms have corresponding R_MIPS_COPY copies.
     if (const auto *da = dyn_cast<DefinedAtom>(atom))
       for (const Reference *ref : *da) {
-        if (const auto *sla = dyn_cast<SharedLibraryAtom>(ref->target()))
-          _referencedDynAtoms.insert(sla);
-
         if (ref->kindNamespace() == lld::Reference::KindNamespace::ELF) {
           assert(ref->kindArch() == Reference::KindArch::Mips);
           if (ref->kindValue() == llvm::ELF::R_MIPS_COPY)
@@ -81,10 +78,6 @@ public:
     return TargetLayout<ELFType>::addAtom(atom);
   }
 
-  bool isReferencedByDefinedAtom(const SharedLibraryAtom *sla) const {
-    return _referencedDynAtoms.count(sla);
-  }
-
   bool isCopied(const SharedLibraryAtom *sla) const {
     return _copiedDynSymNames.count(sla->name());
   }
@@ -116,7 +109,6 @@ private:
   MipsPLTSection<ELFType> *_pltSection;
   llvm::Optional<AtomLayout *> _gpAtom;
   llvm::Optional<AtomLayout *> _gpDispAtom;
-  llvm::DenseSet<const SharedLibraryAtom *> _referencedDynAtoms;
   llvm::StringSet<> _copiedDynSymNames;
 };
 

Modified: lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h Mon Sep 29 17:05:26 2014
@@ -110,7 +110,7 @@ protected:
 
   /// \brief Create entry in the dynamic symbols table for this atom.
   virtual bool isDynSymEntryRequired(const SharedLibraryAtom *sla) const {
-    return true;
+    return _layout.isReferencedByDefinedAtom(sla);
   }
 
   /// \brief Create DT_NEEDED dynamic tage for the shared library.
@@ -183,7 +183,7 @@ void OutputELFWriter<ELFT>::buildDynamic
       for (const auto &atom : section->atoms()) {
         const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
         if (da && (da->dynamicExport() == DefinedAtom::dynamicExportAlways ||
-                   _context.hasCoalescedSharedLibPair(da->name())))
+                   _context.isDynamicallyExportedSymbol(da->name())))
           _dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
                                          atom->_virtualAddr, atom);
       }

Modified: lld/trunk/lib/ReaderWriter/ELF/TODO.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/TODO.txt?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/TODO.txt (original)
+++ lld/trunk/lib/ReaderWriter/ELF/TODO.txt Mon Sep 29 17:05:26 2014
@@ -8,8 +8,6 @@ lib/ReaderWriter/ELF
 
 - _GLOBAL_OFFSET_TABLE should be hidden and normally dropped from the output.
 
-- Find out where __tls_get_addr gets created and stop that.
-
 - Preserve SHT_NOTE sections from input, merge them if applicable.
 
 - Do not create __got_* / __plt_* symbol table entries by default.

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h Mon Sep 29 17:05:26 2014
@@ -57,7 +57,6 @@ bool X86_64DynamicLibraryWriter<ELFT>::c
     std::vector<std::unique_ptr<File>> &result) {
   DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
   _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
-  _gotFile->addAtom(*new (_gotFile->_alloc) TLSGETADDRAtom(*_gotFile));
   _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
   result.push_back(std::move(_gotFile));
   return true;

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h Mon Sep 29 17:05:26 2014
@@ -56,7 +56,6 @@ bool X86_64ExecutableWriter<ELFT>::creat
     std::vector<std::unique_ptr<File>> &result) {
   ExecutableWriter<ELFT>::createImplicitFiles(result);
   _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
-  _gotFile->addAtom(*new (_gotFile->_alloc) TLSGETADDRAtom(*_gotFile));
   if (_context.isDynamic())
     _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
   result.push_back(std::move(_gotFile));

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h Mon Sep 29 17:05:26 2014
@@ -50,6 +50,8 @@ public:
     case llvm::ELF::R_X86_64_RELATIVE:
     case llvm::ELF::R_X86_64_GLOB_DAT:
     case llvm::ELF::R_X86_64_COPY:
+    case llvm::ELF::R_X86_64_DTPMOD64:
+    case llvm::ELF::R_X86_64_DTPOFF64:
       return true;
     default:
       return false;

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp Mon Sep 29 17:05:26 2014
@@ -88,6 +88,10 @@ std::error_code X86_64TargetRelocationHa
     }
     break;
   }
+  case R_X86_64_TLSGD: {
+    relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+    break;
+  }
   case R_X86_64_TLSLD: {
     // Rewrite to move %fs:0 into %rax. Technically we should verify that the
     // next relocation is a PC32 to __tls_get_addr...
@@ -115,6 +119,8 @@ std::error_code X86_64TargetRelocationHa
   case R_X86_64_IRELATIVE:
   case R_X86_64_JUMP_SLOT:
   case R_X86_64_GLOB_DAT:
+  case R_X86_64_DTPMOD64:
+  case R_X86_64_DTPOFF64:
     break;
   default: {
     std::string str;

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp Mon Sep 29 17:05:26 2014
@@ -50,6 +50,12 @@ const uint8_t x86_64PltAtomContent[16] =
   0xe9, 0x00, 0x00, 0x00, 0x00        // jmpq plt[-1]
 };
 
+// TLS GD Entry
+static const uint8_t x86_64GotTlsGdAtomContent[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
 /// \brief Atoms that are used by X86_64 dynamic linking
 class X86_64GOTAtom : public GOTAtom {
 public:
@@ -60,6 +66,16 @@ public:
   }
 };
 
+/// \brief X86_64 GOT TLS GD entry.
+class GOTTLSGdAtom : public X86_64GOTAtom {
+public:
+  GOTTLSGdAtom(const File &f, StringRef secName) : X86_64GOTAtom(f, secName) {}
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(x86_64GotTlsGdAtomContent);
+  }
+};
+
 class X86_64PLT0Atom : public PLT0Atom {
 public:
   X86_64PLT0Atom(const File &f) : PLT0Atom(f) {
@@ -117,6 +133,9 @@ template <class Derived> class Relocatio
     case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset
       static_cast<Derived *>(this)->handleGOTTPOFF(ref);
       break;
+    case R_X86_64_TLSGD:
+      static_cast<Derived *>(this)->handleTLSGd(ref);
+      break;
     }
   }
 
@@ -180,6 +199,11 @@ protected:
     const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
   }
 
+  /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations.
+  void handleTLSGd(const Reference &ref) {
+    const_cast<Reference &>(ref).setTarget(getTLSGdGOTEntry(ref.target()));
+  }
+
   /// \brief Create a GOT entry containing 0.
   const GOTAtom *getNullGOT() {
     if (!_null) {
@@ -207,6 +231,21 @@ protected:
     return got->second;
   }
 
+  const GOTAtom *getTLSGdGOTEntry(const Atom *a) {
+    auto got = _gotTLSGdMap.find(a);
+    if (got != _gotTLSGdMap.end())
+      return got->second;
+
+    auto ga = new (_file._alloc) GOTTLSGdAtom(_file, ".got");
+    _gotTLSGdMap[a] = ga;
+
+    _tlsGotVector.push_back(ga);
+    ga->addReferenceELF_x86_64(R_X86_64_DTPMOD64, 0, a, 0);
+    ga->addReferenceELF_x86_64(R_X86_64_DTPOFF64, 8, a, 0);
+
+    return ga;
+  }
+
 public:
   RelocationPass(const ELFLinkingContext &ctx)
       : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
@@ -251,6 +290,10 @@ public:
       got->setOrdinal(ordinal++);
       mf->addAtom(*got);
     }
+    for (auto &got : _tlsGotVector) {
+      got->setOrdinal(ordinal++);
+      mf->addAtom(*got);
+    }
     for (auto obj : _objectVector) {
       obj->setOrdinal(ordinal++);
       mf->addAtom(*obj);
@@ -268,6 +311,9 @@ protected:
   /// \brief Map Atoms to their PLT entries.
   llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
 
+  /// \brief Map Atoms to TLS GD GOT entries.
+  llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
+
   /// \brief Map Atoms to their Object entries.
   llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
 
@@ -276,6 +322,9 @@ protected:
   std::vector<PLTAtom *> _pltVector;
   std::vector<ObjectAtom *> _objectVector;
 
+  /// \brief the list of TLS GOT atoms.
+  std::vector<GOTAtom *> _tlsGotVector;
+
   /// \brief GOT entry that is always 0. Used for undefined weaks.
   GOTAtom *_null;
 
@@ -414,7 +463,10 @@ public:
             dyn_cast_or_null<const DefinedAtom>(ref.target()))
       if (da->contentType() == DefinedAtom::typeResolver)
         return handleIFUNC(ref);
-    if (isa<const SharedLibraryAtom>(ref.target()))
+    // If it is undefined at link time, push the work to the dynamic linker by
+    // creating a PLT entry
+    if (isa<SharedLibraryAtom>(ref.target()) ||
+        isa<UndefinedAtom>(ref.target()))
       const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
     return std::error_code();
   }

Added: lld/trunk/test/elf/X86_64/Inputs/generaltls-so.o.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/Inputs/generaltls-so.o.yaml?rev=218633&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/Inputs/generaltls-so.o.yaml (added)
+++ lld/trunk/test/elf/X86_64/Inputs/generaltls-so.o.yaml Mon Sep 29 17:05:26 2014
@@ -0,0 +1,68 @@
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         554889E566488D3D00000000666648E8000000008B005DC3
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000008
+        Symbol:          mynumber
+        Type:            R_X86_64_TLSGD
+        Addend:          -4
+      - Offset:          0x0000000000000010
+        Symbol:          __tls_get_addr
+        Type:            R_X86_64_PLT32
+        Addend:          -4
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .tdata
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+    AddressAlign:    0x0000000000000004
+    Content:         '21000000'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .tdata
+      Type:            STT_SECTION
+      Section:         .tdata
+  Global:
+    - Name:            getnumber
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x0000000000000018
+    - Name:            mynumber
+      Type:            STT_TLS
+      Section:         .tdata
+      Size:            0x0000000000000004
+    - Name:            _GLOBAL_OFFSET_TABLE_
+    - Name:            __tls_get_addr
+...

Added: lld/trunk/test/elf/X86_64/general-dynamic-tls.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/general-dynamic-tls.test?rev=218633&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/general-dynamic-tls.test (added)
+++ lld/trunk/test/elf/X86_64/general-dynamic-tls.test Mon Sep 29 17:05:26 2014
@@ -0,0 +1,129 @@
+# This test exercises a simple general dynamic TLS access model in X86_64.
+#
+# It is composed of two parts: a program and a shared library. The shared
+# library uses TLS, but the program does not.
+#
+# The shared library should import __tls_get_addr, since it uses the general
+# dynamic TLS access mode (see www.akkadia.org/drepper/tls.pdf). Notice that
+# once we support TLS strength reduction, this test should be updated, since
+# this can be converted into a local dynamic TLS model.
+
+# Prepare inputs
+#RUN: yaml2obj -format=elf %p/Inputs/generaltls-so.o.yaml -o=%t.o.so
+#RUN: lld -flavor gnu  -target x86_64 -shared %t.o.so -o %T/libgeneraltls.so
+#RUN: yaml2obj -format=elf %s -o=%t.o
+
+# Link - (we supply --defsym=__tls_get_addr to avoid the need to link with
+# system libraries)
+#RUN: lld -flavor gnu  -target x86_64 -e main %t.o -L%T -lgeneraltls -o %t1 \
+#RUN:   --defsym=__tls_get_addr=0
+
+# Check
+#RUN: llvm-readobj -dyn-symbols %t1 | FileCheck -check-prefix CHECKPROG %s
+#RUN: llvm-readobj -relocations -dyn-symbols %T/libgeneraltls.so | FileCheck \
+#RUN:     -check-prefix CHECKDSO %s
+
+# Test case generated with the following code:
+#
+# DSO: (file %p/Inputs/generaltls-so.o.yaml)
+#
+# __thread int mynumber=33;
+#
+# int getnumber() {
+#     return mynumber;
+# }
+#
+# Program: (this file). Note: The printf() relocation was removed to simplify
+# this test and allow us to test this without libc.
+#
+# #include <stdio.h>
+# int getnumber();
+#
+# int main() {
+#     printf("getnumber() = %d\n", getnumber());
+#     return 0;
+# }
+#
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         554889E54883EC10C745FC00000000B000E80000000048BF000000000000000089C6B000E80000000031F68945F889F04883C4105DC3
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000012
+        Symbol:          getnumber
+        Type:            R_X86_64_PC32
+        Addend:          -4
+      - Offset:          0x0000000000000018
+        Symbol:          .rodata.str1.1
+        Type:            R_X86_64_64
+        Addend:          0
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .rodata.str1.1
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         6765746E756D6265722829203D2025640A00
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .rodata.str1.1
+      Type:            STT_SECTION
+      Section:         .rodata.str1.1
+  Global:
+    - Name:            main
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x0000000000000036
+    - Name:            getnumber
+
+# Program should import the function defined in the shared library
+#CHECKPROG: getnumber@
+# Program should not import __tls_get_addr, since it does not directly use TLS
+#CHECKPROG-NOT: __tls_get_addr@
+
+# Check for the presence of X86_64 TLS relocations in the shared library
+#CHECKDSO: R_X86_64_DTPMOD64
+#CHECKDSO: R_X86_64_DTPOFF64
+#CHECKDSO: R_X86_64_JUMP_SLOT
+
+# The shared library should import __tls_get_addr, since it uses the general
+# dynamic TLS access mode.
+#CHECKDSO:          Name: __tls_get_addr@
+#CHECKDSO-NEXT:     Value: 0x0
+#CHECKDSO-NEXT:     Size: 0
+#CHECKDSO-NEXT:     Binding: Global
+#CHECKDSO-NEXT:     Type: None
+#CHECKDSO-NEXT:     Other: 0
+#CHECKDSO-NEXT:     Section: Undefined
+

Modified: lld/trunk/test/elf/X86_64/omagic.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/omagic.test?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/test/elf/X86_64/omagic.test (original)
+++ lld/trunk/test/elf/X86_64/omagic.test Mon Sep 29 17:05:26 2014
@@ -185,7 +185,7 @@ OMAGICSECTIONS:    Flags [ (0x0)
 OMAGICSECTIONS:    ]
 OMAGICSECTIONS:    Address: 0x0
 OMAGICSECTIONS:    Offset: 0x1E8
-OMAGICSECTIONS:    Size: 528
+OMAGICSECTIONS:    Size: 504
 OMAGICSECTIONS:    Link: 13
 OMAGICSECTIONS:    Info: 2
 OMAGICSECTIONS:    AddressAlignment: 8
@@ -197,8 +197,8 @@ OMAGICSECTIONS:    Type: SHT_STRTAB (0x3
 OMAGICSECTIONS:    Flags [ (0x0)
 OMAGICSECTIONS:    ]
 OMAGICSECTIONS:    Address: 0x0
-OMAGICSECTIONS:    Offset: 0x3F8
-OMAGICSECTIONS:    Size: 246
+OMAGICSECTIONS:    Offset: 0x3E0
+OMAGICSECTIONS:    Size: 231
 OMAGICSECTIONS:    Link: 0
 OMAGICSECTIONS:    Info: 0
 OMAGICSECTIONS:    AddressAlignment: 1

Modified: lld/trunk/test/elf/X86_64/undef.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/undef.test?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/test/elf/X86_64/undef.test (original)
+++ lld/trunk/test/elf/X86_64/undef.test Mon Sep 29 17:05:26 2014
@@ -7,7 +7,7 @@ RUN: lld -flavor gnu -target x86_64 %p/I
 RUN: llvm-readobj -symbols %t | FileCheck %s
 
 SYMFROMARCHIVE:  Symbol {
-SYMFROMARCHIVE:    Name: fn (16)
+SYMFROMARCHIVE:    Name: fn ({{[0-9]+}}
 SYMFROMARCHIVE:    Size: 11
 SYMFROMARCHIVE:    Binding: Global (0x1)
 SYMFROMARCHIVE:    Type: Function (0x2)

Modified: lld/trunk/test/elf/X86_64/underscore-end.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/underscore-end.test?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/test/elf/X86_64/underscore-end.test (original)
+++ lld/trunk/test/elf/X86_64/underscore-end.test Mon Sep 29 17:05:26 2014
@@ -7,7 +7,7 @@ RUN: --noinhibit-exec -o %t --omagic
 RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=OMAGICABSSYMBOLS %s
 
 NMAGICABSSYMBOLS:  Symbol {
-NMAGICABSSYMBOLS:    Name: __bss_start (51)
+NMAGICABSSYMBOLS:    Name: __bss_start ({{[0-9]+}}
 NMAGICABSSYMBOLS:    Value: 0x40100C
 NMAGICABSSYMBOLS:    Size: 0
 NMAGICABSSYMBOLS:    Binding: Global (0x1)
@@ -16,7 +16,7 @@ NMAGICABSSYMBOLS:    Other: 0
 NMAGICABSSYMBOLS:    Section: Absolute (0xFFF1)
 NMAGICABSSYMBOLS:  }
 NMAGICABSSYMBOLS:  Symbol {
-NMAGICABSSYMBOLS:    Name: __bss_end (63)
+NMAGICABSSYMBOLS:    Name: __bss_end ({{[0-9]+}}
 NMAGICABSSYMBOLS:    Value: 0x40100C
 NMAGICABSSYMBOLS:    Size: 0
 NMAGICABSSYMBOLS:    Binding: Global (0x1)
@@ -25,7 +25,7 @@ NMAGICABSSYMBOLS:    Other: 0
 NMAGICABSSYMBOLS:    Section: Absolute (0xFFF1)
 NMAGICABSSYMBOLS:  }
 NMAGICABSSYMBOLS:  Symbol {
-NMAGICABSSYMBOLS:    Name: _end (73)
+NMAGICABSSYMBOLS:    Name: _end ({{[0-9]+}}
 NMAGICABSSYMBOLS:    Value: 0x40100C
 NMAGICABSSYMBOLS:    Size: 0
 NMAGICABSSYMBOLS:    Binding: Global (0x1)
@@ -34,7 +34,7 @@ NMAGICABSSYMBOLS:    Other: 0
 NMAGICABSSYMBOLS:    Section: Absolute (0xFFF1)
 NMAGICABSSYMBOLS:  }
 NMAGICABSSYMBOLS:  Symbol {
-NMAGICABSSYMBOLS:    Name: end (78)
+NMAGICABSSYMBOLS:    Name: end ({{[0-9]+}}
 NMAGICABSSYMBOLS:    Value: 0x40100C
 NMAGICABSSYMBOLS:    Size: 0
 NMAGICABSSYMBOLS:    Binding: Global (0x1)
@@ -44,7 +44,7 @@ NMAGICABSSYMBOLS:    Section: Absolute (
 NMAGICABSSYMBOLS:  }
 
 OMAGICABSSYMBOLS:  Symbol {
-OMAGICABSSYMBOLS:    Name: __bss_start (51)
+OMAGICABSSYMBOLS:    Name: __bss_start ({{[0-9]+}})
 OMAGICABSSYMBOLS:    Value: 0x400144
 OMAGICABSSYMBOLS:    Size: 0
 OMAGICABSSYMBOLS:    Binding: Global (0x1)
@@ -53,7 +53,7 @@ OMAGICABSSYMBOLS:    Other: 0
 OMAGICABSSYMBOLS:    Section: Absolute (0xFFF1)
 OMAGICABSSYMBOLS:  }
 OMAGICABSSYMBOLS:  Symbol {
-OMAGICABSSYMBOLS:    Name: __bss_end (63)
+OMAGICABSSYMBOLS:    Name: __bss_end ({{[0-9]+}}
 OMAGICABSSYMBOLS:    Value: 0x400144
 OMAGICABSSYMBOLS:    Size: 0
 OMAGICABSSYMBOLS:    Binding: Global (0x1)
@@ -62,7 +62,7 @@ OMAGICABSSYMBOLS:    Other: 0
 OMAGICABSSYMBOLS:    Section: Absolute (0xFFF1)
 OMAGICABSSYMBOLS:  }
 OMAGICABSSYMBOLS:  Symbol {
-OMAGICABSSYMBOLS:    Name: _end (73)
+OMAGICABSSYMBOLS:    Name: _end ({{[0-9]+}}
 OMAGICABSSYMBOLS:    Value: 0x400144
 OMAGICABSSYMBOLS:    Size: 0
 OMAGICABSSYMBOLS:    Binding: Global (0x1)
@@ -71,7 +71,7 @@ OMAGICABSSYMBOLS:    Other: 0
 OMAGICABSSYMBOLS:    Section: Absolute (0xFFF1)
 OMAGICABSSYMBOLS:  }
 OMAGICABSSYMBOLS:  Symbol {
-OMAGICABSSYMBOLS:    Name: end (78)
+OMAGICABSSYMBOLS:    Name: end ({{[0-9]+}}
 OMAGICABSSYMBOLS:    Value: 0x400144
 OMAGICABSSYMBOLS:    Size: 0
 OMAGICABSSYMBOLS:    Binding: Global (0x1)

Modified: lld/trunk/test/elf/dynamic-segorder.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/dynamic-segorder.test?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/test/elf/dynamic-segorder.test (original)
+++ lld/trunk/test/elf/dynamic-segorder.test Mon Sep 29 17:05:26 2014
@@ -1,5 +1,6 @@
 RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
-RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined \
+RUN:   --defsym=__tls_get_addr=0
 RUN: llvm-objdump -p %t | FileCheck %s
 
 CHECK: PHDR

Modified: lld/trunk/test/elf/dynamic-undef.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/dynamic-undef.test?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/test/elf/dynamic-undef.test (original)
+++ lld/trunk/test/elf/dynamic-undef.test Mon Sep 29 17:05:26 2014
@@ -9,7 +9,8 @@ RUN:   %p/Inputs/shared.so-x86-64 -o %t
 RUN: FileCheck -check-prefix=EXEC %s < %t1
 # This test will pass because of --allow-shlib-undefined
 RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
-RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined \
+RUN:   --defsym=__tls_get_addr=0
 # Building shared libraries should not fail when there is a undefined symbol.
 # Test creation of shared library, this should pass because we are using
 # shared option and by default, dynamic library wouldn't create undefined atoms

Modified: lld/trunk/test/elf/undef-from-main-dso.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/undef-from-main-dso.test?rev=218633&r1=218632&r2=218633&view=diff
==============================================================================
--- lld/trunk/test/elf/undef-from-main-dso.test (original)
+++ lld/trunk/test/elf/undef-from-main-dso.test Mon Sep 29 17:05:26 2014
@@ -41,4 +41,3 @@ CHECK-NEXT:    Type: Object (0x1)
 CHECK-NEXT:    Other: 0
 CHECK-NEXT:    Section: .bss
 
-CHECK:         Name: x@ ({{[0-9]+}}





More information about the llvm-commits mailing list