[lld] r193379 - [ELF] Refactor x86-64 relocation pass.

Michael J. Spencer bigcheesegs at gmail.com
Thu Oct 24 15:46:48 PDT 2013


Author: mspencer
Date: Thu Oct 24 17:46:48 2013
New Revision: 193379

URL: http://llvm.org/viewvc/llvm-project?rev=193379&view=rev
Log:
[ELF] Refactor x86-64 relocation pass.

This renames the GOTPLTPass to RelocationPass and refactors it to better
represent the different types of relocations.

Added:
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
      - copied, changed from r193375, lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
Modified:
    lld/trunk/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
    lld/trunk/test/elf/gotpcrel.test
    lld/trunk/test/elf/x86-64-dynamic.test

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt?rev=193379&r1=193378&r2=193379&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt Thu Oct 24 17:46:48 2013
@@ -2,6 +2,7 @@ add_lld_library(lldX86_64ELFTarget
   X86_64LinkingContext.cpp
   X86_64TargetHandler.cpp
   X86_64RelocationHandler.cpp
+  X86_64RelocationPass.cpp
   )
 
 target_link_libraries(lldX86_64ELFTarget

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp?rev=193379&r1=193378&r2=193379&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp Thu Oct 24 17:46:48 2013
@@ -7,448 +7,25 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "Atoms.h"
 #include "X86_64LinkingContext.h"
 
 #include "lld/Core/File.h"
 #include "lld/Core/Instrumentation.h"
-#include "lld/Core/Parallel.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/PassManager.h"
-#include "lld/ReaderWriter/Simple.h"
 
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringSwitch.h"
 
+#include "Atoms.h"
+#include "X86_64RelocationPass.h"
+
 using namespace lld;
 using namespace lld::elf;
 
 namespace {
 using namespace llvm::ELF;
 
-// .got values
-const uint8_t x86_64GotAtomContent[8] = { 0 };
 const uint8_t x86_64InitFiniAtomContent[8] = { 0 };
 
-// .plt value (entry 0)
-const uint8_t x86_64Plt0AtomContent[16] = {
-  0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
-  0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
-  0x90, 0x90, 0x90, 0x90              // nopnopnop
-};
-
-// .plt values (other entries)
-const uint8_t x86_64PltAtomContent[16] = {
-  0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
-  0x68, 0x00, 0x00, 0x00, 0x00,       // pushq reloc-index
-  0xe9, 0x00, 0x00, 0x00, 0x00        // jmpq plt[-1]
-};
-
-/// \brief Atoms that are used by X86_64 dynamic linking
-class X86_64GOTAtom : public GOTAtom {
-public:
-  X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
-
-  virtual ArrayRef<uint8_t> rawContent() const {
-    return ArrayRef<uint8_t>(x86_64GotAtomContent, 8);
-  }
-};
-
-class X86_64PLT0Atom : public PLT0Atom {
-public:
-  X86_64PLT0Atom(const File &f) : PLT0Atom(f) {
-#ifndef NDEBUG
-    _name = ".PLT0";
-#endif
-  }
-  virtual ArrayRef<uint8_t> rawContent() const {
-    return ArrayRef<uint8_t>(x86_64Plt0AtomContent, 16);
-  }
-};
-
-class X86_64PLTAtom : public PLTAtom {
-public:
-  X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
-
-  virtual ArrayRef<uint8_t> rawContent() const {
-    return ArrayRef<uint8_t>(x86_64PltAtomContent, 16);
-  }
-};
-
-class ELFPassFile : public SimpleFile {
-public:
-  ELFPassFile(const ELFLinkingContext &eti) : SimpleFile(eti, "ELFPassFile") {
-    setOrdinal(eti.getNextOrdinalAndIncrement());
-  }
-
-  llvm::BumpPtrAllocator _alloc;
-};
-
-/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT
-/// along with IFUNC and TLS.
-template <class Derived> class GOTPLTPass : public Pass {
-  /// \brief Handle a specific reference.
-  void handleReference(const DefinedAtom &atom, const Reference &ref) {
-    switch (ref.kind()) {
-    case R_X86_64_32S:
-      static_cast<Derived *>(this)->handle32S(ref);
-      break;
-    case R_X86_64_PLT32:
-      static_cast<Derived *>(this)->handlePLT32(ref);
-      break;
-    case R_X86_64_PC32:
-      static_cast<Derived *>(this)->handlePC32(ref);
-      break;
-    case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset
-      static_cast<Derived *>(this)->handleGOTTPOFF(ref);
-      break;
-    case R_X86_64_GOTPCREL:
-      static_cast<Derived *>(this)->handleGOTPCREL(ref);
-      break;
-    }
-  }
-
-protected:
-  /// \brief get the PLT entry for a given IFUNC Atom.
-  ///
-  /// If the entry does not exist. Both the GOT and PLT entry is created.
-  const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) {
-    auto plt = _pltMap.find(da);
-    if (plt != _pltMap.end())
-      return plt->second;
-    auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
-    ga->addReference(R_X86_64_IRELATIVE, 0, da, 0);
-    auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
-    pa->addReference(R_X86_64_PC32, 2, ga, -4);
-#ifndef NDEBUG
-    ga->_name = "__got_ifunc_";
-    ga->_name += da->name();
-    pa->_name = "__plt_ifunc_";
-    pa->_name += da->name();
-#endif
-    _gotMap[da] = ga;
-    _pltMap[da] = pa;
-    _gotVector.push_back(ga);
-    _pltVector.push_back(pa);
-    return pa;
-  }
-
-  /// \brief Redirect the call to the PLT stub for the target IFUNC.
-  ///
-  /// This create a PLT and GOT entry for the IFUNC if one does not exist. The
-  /// GOT entry and a IRELATIVE relocation to the original target resolver.
-  ErrorOr<void> handleIFUNC(const Reference &ref) {
-    auto target = dyn_cast_or_null<const DefinedAtom>(ref.target());
-    if (target && target->contentType() == DefinedAtom::typeResolver)
-      const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target));
-    return error_code::success();
-  }
-
-  /// \brief Create a GOT entry for the TP offset of a TLS atom.
-  const GOTAtom *getGOTTPOFF(const Atom *atom) {
-    auto got = _gotMap.find(atom);
-    if (got == _gotMap.end()) {
-      auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
-      g->addReference(R_X86_64_TPOFF64, 0, atom, 0);
-#ifndef NDEBUG
-      g->_name = "__got_tls_";
-      g->_name += atom->name();
-#endif
-      _gotMap[atom] = g;
-      _gotVector.push_back(g);
-      return g;
-    }
-    return got->second;
-  }
-
-  /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to
-  /// the GOT.
-  void handleGOTTPOFF(const Reference &ref) {
-    const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
-    const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
-  }
-
-  /// \brief Create a GOT entry containing 0.
-  const GOTAtom *getNullGOT() {
-    if (!_null) {
-      _null = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
-#ifndef NDEBUG
-      _null->_name = "__got_null";
-#endif
-    }
-    return _null;
-  }
-
-  const GOTAtom *getGOT(const DefinedAtom *da) {
-    auto got = _gotMap.find(da);
-    if (got == _gotMap.end()) {
-      auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
-      g->addReference(R_X86_64_64, 0, da, 0);
-#ifndef NDEBUG
-      g->_name = "__got_";
-      g->_name += da->name();
-#endif
-      _gotMap[da] = g;
-      _gotVector.push_back(g);
-      return g;
-    }
-    return got->second;
-  }
-
-  /// \brief Handle a GOTPCREL relocation to an undefined weak atom by using a
-  /// null GOT entry.
-  void handleGOTPCREL(const Reference &ref) {
-    const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
-    if (isa<UndefinedAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getNullGOT());
-    else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getGOT(da));
-  }
-
-public:
-  GOTPLTPass(const ELFLinkingContext &ctx)
-      : _file(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
-        _got1(nullptr) {}
-
-  /// \brief Do the pass.
-  ///
-  /// The goal here is to first process each reference individually. Each call
-  /// to handleReference may modify the reference itself and/or create new
-  /// atoms which must be stored in one of the maps below.
-  ///
-  /// After all references are handled, the atoms created during that are all
-  /// added to mf.
-  virtual void perform(MutableFile &mf) {
-    ScopedTask task(getDefaultDomain(), "X86-64 GOT/PLT Pass");
-    // Process all references.
-    for (const auto &atom : mf.defined())
-      for (const auto &ref : *atom)
-        handleReference(*atom, *ref);
-
-    // Add all created atoms to the link.
-    uint64_t ordinal = 0;
-    if (_PLT0) {
-      _PLT0->setOrdinal(ordinal++);
-      mf.addAtom(*_PLT0);
-    }
-    for (auto &plt : _pltVector) {
-      plt->setOrdinal(ordinal++);
-      mf.addAtom(*plt);
-    }
-    if (_null) {
-      _null->setOrdinal(ordinal++);
-      mf.addAtom(*_null);
-    }
-    if (_PLT0) {
-      _got0->setOrdinal(ordinal++);
-      _got1->setOrdinal(ordinal++);
-      mf.addAtom(*_got0);
-      mf.addAtom(*_got1);
-    }
-    for (auto &got : _gotVector) {
-      got->setOrdinal(ordinal++);
-      mf.addAtom(*got);
-    }
-    for (auto obj : _objectVector) {
-      obj->setOrdinal(ordinal++);
-      mf.addAtom(*obj);
-    }
-  }
-
-protected:
-  /// \brief Owner of all the Atoms created by this pass.
-  ELFPassFile _file;
-
-  /// \brief Map Atoms to their GOT entries.
-  llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
-
-  /// \brief Map Atoms to their PLT entries.
-  llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
-
-  /// \brief Map Atoms to their Object entries.
-  llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
-
-  /// \brief the list of GOT/PLT atoms
-  std::vector<GOTAtom *> _gotVector;
-  std::vector<PLTAtom *> _pltVector;
-  std::vector<ObjectAtom *> _objectVector;
-
-  /// \brief GOT entry that is always 0. Used for undefined weaks.
-  GOTAtom *_null;
-
-  /// \brief The got and plt entries for .PLT0. This is used to call into the
-  /// dynamic linker for symbol resolution.
-  /// @{
-  PLT0Atom *_PLT0;
-  GOTAtom *_got0;
-  GOTAtom *_got1;
-  /// @}
-};
-
-/// This implements the static relocation model. Meaning GOT and PLT entries are
-/// not created for references that can be directly resolved. These are
-/// converted to a direct relocation. For entries that do require a GOT or PLT
-/// entry, that entry is statically bound.
-///
-/// TLS always assumes module 1 and attempts to remove indirection.
-class StaticGOTPLTPass LLVM_FINAL : public GOTPLTPass<StaticGOTPLTPass> {
-public:
-  StaticGOTPLTPass(const elf::X86_64LinkingContext &ctx) : GOTPLTPass(ctx) {}
-
-  ErrorOr<void> handlePLT32(const Reference &ref) {
-    // __tls_get_addr is handled elsewhere.
-    if (ref.target() && ref.target()->name() == "__tls_get_addr") {
-      const_cast<Reference &>(ref).setKind(R_X86_64_NONE);
-      return error_code::success();
-    } else
-      // Static code doesn't need PLTs.
-      const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
-    // Handle IFUNC.
-    if (const DefinedAtom *da =
-            dyn_cast_or_null<const DefinedAtom>(ref.target()))
-      if (da->contentType() == DefinedAtom::typeResolver)
-        return handleIFUNC(ref);
-    return error_code::success();
-  }
-
-  ErrorOr<void> handlePC32(const Reference &ref) { return handleIFUNC(ref); }
-
-  ErrorOr<void> handle32S(const Reference &ref) {
-    // Do nothing.
-    return error_code::success();
-  }
-};
-
-class DynamicGOTPLTPass LLVM_FINAL : public GOTPLTPass<DynamicGOTPLTPass> {
-public:
-  DynamicGOTPLTPass(const elf::X86_64LinkingContext &ctx) : GOTPLTPass(ctx) {}
-
-  const PLT0Atom *getPLT0() {
-    if (_PLT0)
-      return _PLT0;
-    // Fill in the null entry.
-    getNullGOT();
-    _PLT0 = new (_file._alloc) X86_64PLT0Atom(_file);
-    _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
-    _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
-    _PLT0->addReference(R_X86_64_PC32, 2, _got0, -4);
-    _PLT0->addReference(R_X86_64_PC32, 8, _got1, -4);
-#ifndef NDEBUG
-    _got0->_name = "__got0";
-    _got1->_name = "__got1";
-#endif
-    return _PLT0;
-  }
-
-  const PLTAtom *getPLTEntry(const Atom *a) {
-    auto plt = _pltMap.find(a);
-    if (plt != _pltMap.end())
-      return plt->second;
-    auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
-    ga->addReference(R_X86_64_JUMP_SLOT, 0, a, 0);
-    auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
-    pa->addReference(R_X86_64_PC32, 2, ga, -4);
-    pa->addReference(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0);
-    pa->addReference(R_X86_64_PC32, 12, getPLT0(), -4);
-    // Set the starting address of the got entry to the second instruction in
-    // the plt entry.
-    ga->addReference(R_X86_64_64, 0, pa, 6);
-#ifndef NDEBUG
-    ga->_name = "__got_";
-    ga->_name += a->name();
-    pa->_name = "__plt_";
-    pa->_name += a->name();
-#endif
-    _gotMap[a] = ga;
-    _pltMap[a] = pa;
-    _gotVector.push_back(ga);
-    _pltVector.push_back(pa);
-    return pa;
-  }
-
-  const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) {
-    auto obj = _objectMap.find(a);
-    if (obj != _objectMap.end())
-      return obj->second;
-
-    auto oa = new (_file._alloc) ObjectAtom(_file);
-    oa->addReference(R_X86_64_COPY, 0, a, 0);
-
-    oa->_name = a->name();
-    oa->_size = a->size();
-
-    _objectMap[a] = oa;
-    _objectVector.push_back(oa);
-    return oa;
-  }
-
-  ErrorOr<void> handle32S(const Reference &ref) {
-    if (auto sla = dyn_cast_or_null<SharedLibraryAtom>(ref.target())) {
-      if (sla->type() == SharedLibraryAtom::Type::Data)
-        const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
-      else if (sla->type() == SharedLibraryAtom::Type::Code)
-        const_cast<Reference &>(ref).setTarget(getPLTEntry(sla));
-    }
-    return error_code::success();
-  }
-
-  ErrorOr<void> handlePLT32(const Reference &ref) {
-    // Turn this into a PC32 to the PLT entry.
-    const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
-    // Handle IFUNC.
-    if (const DefinedAtom *da =
-            dyn_cast_or_null<const DefinedAtom>(ref.target()))
-      if (da->contentType() == DefinedAtom::typeResolver)
-        return handleIFUNC(ref);
-    if (isa<const SharedLibraryAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
-    return error_code::success();
-  }
-
-  ErrorOr<void> handlePC32(const Reference &ref) {
-    if (!ref.target())
-      return error_code::success();
-    if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
-      if (sla->type() == SharedLibraryAtom::Type::Code)
-        return handlePLT32(ref);
-      else if (sla->type() == SharedLibraryAtom::Type::Data) {
-        const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
-        return error_code::success();
-      } else
-        return handleGOTPCREL(ref);
-    }
-    return handleIFUNC(ref);
-  }
-
-  const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) {
-    auto got = _gotMap.find(sla);
-    if (got == _gotMap.end()) {
-      auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got.dyn");
-      g->addReference(R_X86_64_GLOB_DAT, 0, sla, 0);
-#ifndef NDEBUG
-      g->_name = "__got_";
-      g->_name += sla->name();
-#endif
-      _gotMap[sla] = g;
-      _gotVector.push_back(g);
-      return g;
-    }
-    return got->second;
-  }
-
-  ErrorOr<void> handleGOTPCREL(const Reference &ref) {
-    const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
-    if (isa<UndefinedAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getNullGOT());
-    else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getGOT(da));
-    else if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getSharedGOT(sla));
-    return error_code::success();
-  }
-};
-
 // X86_64InitFini Atom
 class X86_64InitAtom : public InitFiniAtom {
 public:
@@ -515,21 +92,9 @@ private:
 
 
 void elf::X86_64LinkingContext::addPasses(PassManager &pm) const {
-  switch (_outputELFType) {
-  case llvm::ELF::ET_EXEC:
-    if (_isStaticExecutable)
-      pm.add(std::unique_ptr<Pass>(new StaticGOTPLTPass(*this)));
-    else
-      pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this)));
-    break;
-  case llvm::ELF::ET_DYN:
-    pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this)));
-    break;
-  case llvm::ELF::ET_REL:
-    break;
-  default:
-    llvm_unreachable("Unhandled output file type");
-  }
+  auto pass = createX86_64RelocationPass(*this);
+  if (pass)
+    pm.add(std::move(pass));
   ELFLinkingContext::addPasses(pm);
 }
 

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=193379&r1=193378&r2=193379&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp Thu Oct 24 17:46:48 2013
@@ -74,6 +74,7 @@ ErrorOr<void> X86_64TargetRelocationHand
     reloc64(location, relocVAddress, targetVAddress, ref.addend());
     break;
   case R_X86_64_PC32:
+  case R_X86_64_GOTPCREL:
     relocPC32(location, relocVAddress, targetVAddress, ref.addend());
     break;
   case R_X86_64_32:

Copied: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp (from r193375, lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp)
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp?p2=lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp&p1=lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp&r1=193375&r2=193379&rev=193379&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp Thu Oct 24 17:46:48 2013
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp ---------------===//
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp ---------------===//
 //
 //                             The LLVM Linker
 //
@@ -6,30 +6,35 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the relocation processing pass for x86-64. This includes
+///   GOT and PLT entries, TLS, COPY, and ifunc.
+///
+/// This is based on section 4.4.1 of the AMD64 ABI (no stable URL as of Oct,
+/// 2013).
+///
+/// This also includes aditional behaivor that gnu-ld and gold implement but
+/// which is not specified anywhere.
+///
+//===----------------------------------------------------------------------===//
 
-#include "Atoms.h"
-#include "X86_64LinkingContext.h"
+#include "X86_64RelocationPass.h"
 
-#include "lld/Core/File.h"
-#include "lld/Core/Instrumentation.h"
-#include "lld/Core/Parallel.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/PassManager.h"
 #include "lld/ReaderWriter/Simple.h"
 
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringSwitch.h"
+
+#include "Atoms.h"
+#include "X86_64LinkingContext.h"
 
 using namespace lld;
 using namespace lld::elf;
-
-namespace {
 using namespace llvm::ELF;
 
+namespace {
 // .got values
 const uint8_t x86_64GotAtomContent[8] = { 0 };
-const uint8_t x86_64InitFiniAtomContent[8] = { 0 };
 
 // .plt value (entry 0)
 const uint8_t x86_64Plt0AtomContent[16] = {
@@ -85,27 +90,30 @@ public:
   llvm::BumpPtrAllocator _alloc;
 };
 
-/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT
-/// along with IFUNC and TLS.
-template <class Derived> class GOTPLTPass : public Pass {
+/// \brief CRTP base for handling relocations.
+template <class Derived> class RelocationPass : public Pass {
   /// \brief Handle a specific reference.
   void handleReference(const DefinedAtom &atom, const Reference &ref) {
     switch (ref.kind()) {
+    case R_X86_64_32:
     case R_X86_64_32S:
-      static_cast<Derived *>(this)->handle32S(ref);
+    case R_X86_64_64:
+    case R_X86_64_PC32:
+    case R_X86_64_PC64:
+      static_cast<Derived *>(this)->handlePlain(ref);
       break;
     case R_X86_64_PLT32:
       static_cast<Derived *>(this)->handlePLT32(ref);
       break;
-    case R_X86_64_PC32:
-      static_cast<Derived *>(this)->handlePC32(ref);
+    case R_X86_64_GOT32:
+    case R_X86_64_GOTPC32:
+    case R_X86_64_GOTPCREL:
+    case R_X86_64_GOTOFF64:
+      static_cast<Derived *>(this)->handleGOT(ref);
       break;
     case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset
       static_cast<Derived *>(this)->handleGOTTPOFF(ref);
       break;
-    case R_X86_64_GOTPCREL:
-      static_cast<Derived *>(this)->handleGOTPCREL(ref);
-      break;
     }
   }
 
@@ -196,19 +204,9 @@ protected:
     return got->second;
   }
 
-  /// \brief Handle a GOTPCREL relocation to an undefined weak atom by using a
-  /// null GOT entry.
-  void handleGOTPCREL(const Reference &ref) {
-    const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
-    if (isa<UndefinedAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getNullGOT());
-    else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getGOT(da));
-  }
-
 public:
-  GOTPLTPass(const ELFLinkingContext &ctx)
-      : _file(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
+  RelocationPass(const ELFLinkingContext &ctx)
+      : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
         _got1(nullptr) {}
 
   /// \brief Do the pass.
@@ -259,6 +257,7 @@ public:
 protected:
   /// \brief Owner of all the Atoms created by this pass.
   ELFPassFile _file;
+  const ELFLinkingContext &_ctx;
 
   /// \brief Map Atoms to their GOT entries.
   llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
@@ -292,9 +291,13 @@ protected:
 /// entry, that entry is statically bound.
 ///
 /// TLS always assumes module 1 and attempts to remove indirection.
-class StaticGOTPLTPass LLVM_FINAL : public GOTPLTPass<StaticGOTPLTPass> {
+class StaticRelocationPass LLVM_FINAL
+    : public RelocationPass<StaticRelocationPass> {
 public:
-  StaticGOTPLTPass(const elf::X86_64LinkingContext &ctx) : GOTPLTPass(ctx) {}
+  StaticRelocationPass(const elf::X86_64LinkingContext &ctx)
+      : RelocationPass(ctx) {}
+
+  ErrorOr<void> handlePlain(const Reference &ref) { return handleIFUNC(ref); }
 
   ErrorOr<void> handlePLT32(const Reference &ref) {
     // __tls_get_addr is handled elsewhere.
@@ -312,17 +315,20 @@ public:
     return error_code::success();
   }
 
-  ErrorOr<void> handlePC32(const Reference &ref) { return handleIFUNC(ref); }
-
-  ErrorOr<void> handle32S(const Reference &ref) {
-    // Do nothing.
+  ErrorOr<void> handleGOT(const Reference &ref) {
+    if (isa<UndefinedAtom>(ref.target()))
+      const_cast<Reference &>(ref).setTarget(getNullGOT());
+    else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+      const_cast<Reference &>(ref).setTarget(getGOT(da));
     return error_code::success();
   }
 };
 
-class DynamicGOTPLTPass LLVM_FINAL : public GOTPLTPass<DynamicGOTPLTPass> {
+class DynamicRelocationPass LLVM_FINAL
+    : public RelocationPass<DynamicRelocationPass> {
 public:
-  DynamicGOTPLTPass(const elf::X86_64LinkingContext &ctx) : GOTPLTPass(ctx) {}
+  DynamicRelocationPass(const elf::X86_64LinkingContext &ctx)
+      : RelocationPass(ctx) {}
 
   const PLT0Atom *getPLT0() {
     if (_PLT0)
@@ -383,13 +389,16 @@ public:
     return oa;
   }
 
-  ErrorOr<void> handle32S(const Reference &ref) {
-    if (auto sla = dyn_cast_or_null<SharedLibraryAtom>(ref.target())) {
+  ErrorOr<void> handlePlain(const Reference &ref) {
+    if (!ref.target())
+      return error_code::success();
+    if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
       if (sla->type() == SharedLibraryAtom::Type::Data)
         const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
       else if (sla->type() == SharedLibraryAtom::Type::Code)
         const_cast<Reference &>(ref).setTarget(getPLTEntry(sla));
-    }
+    } else
+      return handleIFUNC(ref);
     return error_code::success();
   }
 
@@ -406,21 +415,6 @@ public:
     return error_code::success();
   }
 
-  ErrorOr<void> handlePC32(const Reference &ref) {
-    if (!ref.target())
-      return error_code::success();
-    if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
-      if (sla->type() == SharedLibraryAtom::Type::Code)
-        return handlePLT32(ref);
-      else if (sla->type() == SharedLibraryAtom::Type::Data) {
-        const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
-        return error_code::success();
-      } else
-        return handleGOTPCREL(ref);
-    }
-    return handleIFUNC(ref);
-  }
-
   const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) {
     auto got = _gotMap.find(sla);
     if (got == _gotMap.end()) {
@@ -437,8 +431,7 @@ public:
     return got->second;
   }
 
-  ErrorOr<void> handleGOTPCREL(const Reference &ref) {
-    const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
+  ErrorOr<void> handleGOT(const Reference &ref) {
     if (isa<UndefinedAtom>(ref.target()))
       const_cast<Reference &>(ref).setTarget(getNullGOT());
     else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
@@ -448,185 +441,21 @@ public:
     return error_code::success();
   }
 };
-
-// X86_64InitFini Atom
-class X86_64InitAtom : public InitFiniAtom {
-public:
-  X86_64InitAtom(const File &f, StringRef function)
-      : InitFiniAtom(f, ".init_array") {
-#ifndef NDEBUG
-    _name = "__init_fn_";
-    _name += function;
-#endif
-  }
-  virtual ArrayRef<uint8_t> rawContent() const {
-    return ArrayRef<uint8_t>(x86_64InitFiniAtomContent, 8);
-  }
-  virtual Alignment alignment() const { return Alignment(3); }
-};
-
-class X86_64FiniAtom : public InitFiniAtom {
-public:
-  X86_64FiniAtom(const File &f, StringRef function)
-      : InitFiniAtom(f, ".fini_array") {
-#ifndef NDEBUG
-    _name = "__fini_fn_";
-    _name += function;
-#endif
-  }
-  virtual ArrayRef<uint8_t> rawContent() const {
-    return ArrayRef<uint8_t>(x86_64InitFiniAtomContent, 8);
-  }
-
-  virtual Alignment alignment() const { return Alignment(3); }
-};
-
-class X86_64InitFiniFile : public SimpleFile {
-public:
-  X86_64InitFiniFile(const ELFLinkingContext &context)
-      : SimpleFile(context, "command line option -init/-fini"), _ordinal(0) {}
-
-  void addInitFunction(StringRef name) {
-    Atom *initFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name);
-    X86_64InitAtom *initAtom =
-           (new (_allocator) X86_64InitAtom(*this, name));
-    initAtom->addReference(llvm::ELF::R_X86_64_64, 0, initFunctionAtom, 0);
-    initAtom->setOrdinal(_ordinal++);
-    addAtom(*initFunctionAtom);
-    addAtom(*initAtom);
-  }
-
-  void addFiniFunction(StringRef name) {
-    Atom *finiFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name);
-    X86_64FiniAtom *finiAtom =
-           (new (_allocator) X86_64FiniAtom(*this, name));
-    finiAtom->addReference(llvm::ELF::R_X86_64_64, 0, finiFunctionAtom, 0);
-    finiAtom->setOrdinal(_ordinal++);
-    addAtom(*finiFunctionAtom);
-    addAtom(*finiAtom);
-  }
-
-private:
-  llvm::BumpPtrAllocator _allocator;
-  uint64_t _ordinal;
-};
-
 } // end anon namespace
 
-
-void elf::X86_64LinkingContext::addPasses(PassManager &pm) const {
-  switch (_outputELFType) {
+std::unique_ptr<Pass>
+lld::elf::createX86_64RelocationPass(const X86_64LinkingContext &ctx) {
+  switch (ctx.getOutputELFType()) {
   case llvm::ELF::ET_EXEC:
-    if (_isStaticExecutable)
-      pm.add(std::unique_ptr<Pass>(new StaticGOTPLTPass(*this)));
+    if (ctx.isDynamic())
+      return std::unique_ptr<Pass>(new DynamicRelocationPass(ctx));
     else
-      pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this)));
-    break;
+      return std::unique_ptr<Pass>(new StaticRelocationPass(ctx));
   case llvm::ELF::ET_DYN:
-    pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this)));
-    break;
+    return std::unique_ptr<Pass>(new DynamicRelocationPass(ctx));
   case llvm::ELF::ET_REL:
-    break;
+    return std::unique_ptr<Pass>();
   default:
     llvm_unreachable("Unhandled output file type");
   }
-  ELFLinkingContext::addPasses(pm);
-}
-
-bool elf::X86_64LinkingContext::createInternalFiles(
-    std::vector<std::unique_ptr<File> > &result) const {
-  ELFLinkingContext::createInternalFiles(result);
-  std::unique_ptr<X86_64InitFiniFile> initFiniFile(
-      new X86_64InitFiniFile(*this));
-  for (auto ai : initFunctions())
-    initFiniFile->addInitFunction(ai);
-  for (auto ai:finiFunctions())
-    initFiniFile->addFiniFunction(ai);
-  result.push_back(std::move(initFiniFile));
-  return true;
 }
-
-#define LLD_CASE(name) .Case(#name, llvm::ELF::name)
-
-ErrorOr<Reference::Kind>
-elf::X86_64LinkingContext::relocKindFromString(StringRef str) const {
-  int32_t ret = llvm::StringSwitch<int32_t>(str) LLD_CASE(R_X86_64_NONE)
-      LLD_CASE(R_X86_64_64) LLD_CASE(R_X86_64_PC32) LLD_CASE(R_X86_64_GOT32)
-      LLD_CASE(R_X86_64_PLT32) LLD_CASE(R_X86_64_COPY)
-      LLD_CASE(R_X86_64_GLOB_DAT) LLD_CASE(R_X86_64_JUMP_SLOT)
-      LLD_CASE(R_X86_64_RELATIVE) LLD_CASE(R_X86_64_GOTPCREL)
-      LLD_CASE(R_X86_64_32) LLD_CASE(R_X86_64_32S) LLD_CASE(R_X86_64_16)
-      LLD_CASE(R_X86_64_PC16) LLD_CASE(R_X86_64_8) LLD_CASE(R_X86_64_PC8)
-      LLD_CASE(R_X86_64_DTPMOD64) LLD_CASE(R_X86_64_DTPOFF64)
-      LLD_CASE(R_X86_64_TPOFF64) LLD_CASE(R_X86_64_TLSGD)
-      LLD_CASE(R_X86_64_TLSLD) LLD_CASE(R_X86_64_DTPOFF32)
-      LLD_CASE(R_X86_64_GOTTPOFF) LLD_CASE(R_X86_64_TPOFF32)
-      LLD_CASE(R_X86_64_PC64) LLD_CASE(R_X86_64_GOTOFF64)
-      LLD_CASE(R_X86_64_GOTPC32) LLD_CASE(R_X86_64_GOT64)
-      LLD_CASE(R_X86_64_GOTPCREL64) LLD_CASE(R_X86_64_GOTPC64)
-      LLD_CASE(R_X86_64_GOTPLT64) LLD_CASE(R_X86_64_PLTOFF64)
-      LLD_CASE(R_X86_64_SIZE32) LLD_CASE(R_X86_64_SIZE64)
-      LLD_CASE(R_X86_64_GOTPC32_TLSDESC) LLD_CASE(R_X86_64_TLSDESC_CALL)
-      LLD_CASE(R_X86_64_TLSDESC) LLD_CASE(R_X86_64_IRELATIVE)
-          .Case("LLD_R_X86_64_GOTRELINDEX", LLD_R_X86_64_GOTRELINDEX)
-          .Default(-1);
-
-  if (ret == -1)
-    return make_error_code(YamlReaderError::illegal_value);
-  return ret;
-}
-
-#undef LLD_CASE
-
-#define LLD_CASE(name)                                                         \
-  case llvm::ELF::name:                                                        \
-  return std::string(#name);
-
-ErrorOr<std::string>
-elf::X86_64LinkingContext::stringFromRelocKind(Reference::Kind kind) const {
-  switch (kind) {
-    LLD_CASE(R_X86_64_NONE)
-    LLD_CASE(R_X86_64_64)
-    LLD_CASE(R_X86_64_PC32)
-    LLD_CASE(R_X86_64_GOT32)
-    LLD_CASE(R_X86_64_PLT32)
-    LLD_CASE(R_X86_64_COPY)
-    LLD_CASE(R_X86_64_GLOB_DAT)
-    LLD_CASE(R_X86_64_JUMP_SLOT)
-    LLD_CASE(R_X86_64_RELATIVE)
-    LLD_CASE(R_X86_64_GOTPCREL)
-    LLD_CASE(R_X86_64_32)
-    LLD_CASE(R_X86_64_32S)
-    LLD_CASE(R_X86_64_16)
-    LLD_CASE(R_X86_64_PC16)
-    LLD_CASE(R_X86_64_8)
-    LLD_CASE(R_X86_64_PC8)
-    LLD_CASE(R_X86_64_DTPMOD64)
-    LLD_CASE(R_X86_64_DTPOFF64)
-    LLD_CASE(R_X86_64_TPOFF64)
-    LLD_CASE(R_X86_64_TLSGD)
-    LLD_CASE(R_X86_64_TLSLD)
-    LLD_CASE(R_X86_64_DTPOFF32)
-    LLD_CASE(R_X86_64_GOTTPOFF)
-    LLD_CASE(R_X86_64_TPOFF32)
-    LLD_CASE(R_X86_64_PC64)
-    LLD_CASE(R_X86_64_GOTOFF64)
-    LLD_CASE(R_X86_64_GOTPC32)
-    LLD_CASE(R_X86_64_GOT64)
-    LLD_CASE(R_X86_64_GOTPCREL64)
-    LLD_CASE(R_X86_64_GOTPC64)
-    LLD_CASE(R_X86_64_GOTPLT64)
-    LLD_CASE(R_X86_64_PLTOFF64)
-    LLD_CASE(R_X86_64_SIZE32)
-    LLD_CASE(R_X86_64_SIZE64)
-    LLD_CASE(R_X86_64_GOTPC32_TLSDESC)
-    LLD_CASE(R_X86_64_TLSDESC_CALL)
-    LLD_CASE(R_X86_64_TLSDESC)
-    LLD_CASE(R_X86_64_IRELATIVE)
-  case LLD_R_X86_64_GOTRELINDEX:
-    return std::string("LLD_R_X86_64_GOTRELINDEX");
-  }
-
-  return make_error_code(YamlReaderError::illegal_value);
-}
-

Added: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h?rev=193379&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h Thu Oct 24 17:46:48 2013
@@ -0,0 +1,32 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h -----------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares the relocation processing pass for x86-64. This includes
+///   GOT and PLT entries, TLS, COPY, and ifunc.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_RELOCATION_PASS_H
+#define LLD_READER_WRITER_ELF_X86_64_RELOCATION_PASS_H
+
+#include <memory>
+
+namespace lld {
+class Pass;
+namespace elf {
+class X86_64LinkingContext;
+
+/// \brief Create x86-64 relocation pass for the given linking context.
+std::unique_ptr<Pass>
+createX86_64RelocationPass(const X86_64LinkingContext &);
+}
+}
+
+#endif

Modified: lld/trunk/test/elf/gotpcrel.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/gotpcrel.test?rev=193379&r1=193378&r2=193379&view=diff
==============================================================================
--- lld/trunk/test/elf/gotpcrel.test (original)
+++ lld/trunk/test/elf/gotpcrel.test Thu Oct 24 17:46:48 2013
@@ -13,10 +13,10 @@ YAML: target: main
 
 YAML: name: main
 YAML: references:      
-YAML:   kind:    R_X86_64_PC32
+YAML:   kind:    R_X86_64_GOTPCREL
 YAML:   offset:  3
 YAML:   target:  [[NULLGOT]]
-YAML:   kind:    R_X86_64_PC32
+YAML:   kind:    R_X86_64_GOTPCREL
 YAML:   offset:  10
 YAML:   target:  [[MAINGOT]]
 

Modified: lld/trunk/test/elf/x86-64-dynamic.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/x86-64-dynamic.test?rev=193379&r1=193378&r2=193379&view=diff
==============================================================================
--- lld/trunk/test/elf/x86-64-dynamic.test (original)
+++ lld/trunk/test/elf/x86-64-dynamic.test Thu Oct 24 17:46:48 2013
@@ -26,7 +26,7 @@ CHECK:      - kind:            R_X86_64_
 CHECK:        offset:          18
 CHECK:        target:          [[PLTNAME:[-a-zA-Z0-9_]+]]
 CHECK:        addend:          -4
-CHECK:      - kind:            R_X86_64_PC32
+CHECK:      - kind:            R_X86_64_GOTPCREL
 CHECK:        offset:          25
 CHECK:        target:          [[GOTNAME:[-a-zA-Z0-9_]+]]
 CHECK:        addend:          -4





More information about the llvm-commits mailing list