[lld] r197342 - Linking of shared libraries for MIPS little-endian 32-bit target.

Simon Atanasyan simon at atanasyan.com
Sun Dec 15 04:57:29 PST 2013


Author: atanasyan
Date: Sun Dec 15 06:57:28 2013
New Revision: 197342

URL: http://llvm.org/viewvc/llvm-project?rev=197342&view=rev
Log:
Linking of shared libraries for MIPS little-endian 32-bit target.

The following are the most significant peculiarities of MIPS target:
- MIPS ABI requires some special tags in the dynamic table.
- GOT consists of two parts local and global. The local part contains
  entries refer locally visible symbols. The global part contains entries
  refer global symbols.
- Entries in the .dynsym section which have corresponded entries in the
  GOT should be:
  * Emitted at the end of .dynsym section
  * Sorted accordingly to theirs GOT counterparts
- There are "paired" relocations. One or more R_MIPS_HI16 and R_MIPS_GOT16
  relocations should be followed by R_MIPS_LO16 relocation. To calculate
  result of R_MIPS_HI16 and R_MIPS_GOT16 relocations we need to combine
  addends from these relocations and paired R_MIPS_LO16 relocation.

The patch reviewed by Michael Spencer, Shankar Easwaran, Rui Ueyama.
http://llvm-reviews.chandlerc.com/D2156

Added:
    lld/trunk/lib/ReaderWriter/ELF/Mips/
    lld/trunk/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTarget.h
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
    lld/trunk/test/elf/Mips/
    lld/trunk/test/elf/Mips/Inputs/
    lld/trunk/test/elf/Mips/Inputs/dynobj.c
    lld/trunk/test/elf/Mips/Inputs/dynobj.o
    lld/trunk/test/elf/Mips/dynlib-dynamic.test
    lld/trunk/test/elf/Mips/dynlib-dynsym.test
    lld/trunk/test/elf/Mips/dynlib-fileheader.test
    lld/trunk/test/elf/Mips/dynlib-gotsym.test
Modified:
    lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt
    lld/trunk/lib/ReaderWriter/ELF/DefaultTargetHandler.h
    lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
    lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
    lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
    lld/trunk/lib/ReaderWriter/ELF/TargetHandler.h
    lld/trunk/lib/ReaderWriter/ELF/Targets.h
    lld/trunk/test/elf/phdr.test

Modified: lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt (original)
+++ lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt Sun Dec 15 06:57:28 2013
@@ -7,6 +7,7 @@ add_lld_library(lldELF
 
 target_link_libraries(lldELF
   lldHexagonELFTarget
+  lldMipsELFTarget
   lldPPCELFTarget
   lldPasses
   lldReaderWriter

Modified: lld/trunk/lib/ReaderWriter/ELF/DefaultTargetHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DefaultTargetHandler.h?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/DefaultTargetHandler.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/DefaultTargetHandler.h Sun Dec 15 06:57:28 2013
@@ -58,6 +58,24 @@ public:
   /// \brief allocate Commons, some architectures may move small common
   /// symbols over to small data, this would also be used
   void allocateCommons() {}
+
+  /// \brief create dynamic table
+  LLD_UNIQUE_BUMP_PTR(DynamicTable<ELFT>) createDynamicTable() {
+    return LLD_UNIQUE_BUMP_PTR(DynamicTable<ELFT>)(
+        new (_alloc) DynamicTable<ELFT>(
+            this->_context, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
+  }
+
+  /// \brief create dynamic symbol table
+  LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<ELFT>) createDynamicSymbolTable() {
+    return LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<ELFT>)(
+        new (_alloc) DynamicSymbolTable<ELFT>(
+            this->_context, ".dynsym",
+            DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
+  }
+
+private:
+  llvm::BumpPtrAllocator _alloc;
 };
 } // end namespace elf
 } // end namespace lld

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp Sun Dec 15 06:57:28 2013
@@ -67,6 +67,8 @@ uint16_t ELFLinkingContext::getOutputMac
     return llvm::ELF::EM_X86_64;
   case llvm::Triple::hexagon:
     return llvm::ELF::EM_HEXAGON;
+  case llvm::Triple::mipsel:
+    return llvm::ELF::EM_MIPS;
   case llvm::Triple::ppc:
     return llvm::ELF::EM_PPC;
   default:
@@ -124,6 +126,9 @@ ELFLinkingContext::create(llvm::Triple t
   case llvm::Triple::hexagon:
     return std::unique_ptr<ELFLinkingContext>(
         new lld::elf::HexagonLinkingContext(triple));
+  case llvm::Triple::mipsel:
+    return std::unique_ptr<ELFLinkingContext>(
+        new lld::elf::MipsLinkingContext(triple));
   case llvm::Triple::ppc:
     return std::unique_ptr<ELFLinkingContext>(
         new lld::elf::PPCLinkingContext(triple));

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/CMakeLists.txt?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/CMakeLists.txt (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/CMakeLists.txt Sun Dec 15 06:57:28 2013
@@ -0,0 +1,9 @@
+add_lld_library(lldMipsELFTarget
+  MipsLinkingContext.cpp
+  MipsRelocationHandler.cpp
+  MipsTargetHandler.cpp
+  )
+
+target_link_libraries(lldMipsELFTarget
+  lldCore
+  )

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp Sun Dec 15 06:57:28 2013
@@ -0,0 +1,230 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp -------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "MipsLinkingContext.h"
+#include "MipsTargetHandler.h"
+
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+
+// Lazy resolver
+const uint8_t mipsGot0AtomContent[] = { 0x00, 0x00, 0x00, 0x00 };
+
+// Module pointer
+const uint8_t mipsGotModulePointerAtomContent[] = { 0x00, 0x00, 0x00, 0x80 };
+
+/// \brief Abstract base class represent MIPS GOT entries.
+class MipsGOTAtom : public GOTAtom {
+public:
+  MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
+
+  virtual Alignment alignment() const { return Alignment(2); }
+};
+
+/// \brief MIPS GOT entry initialized by zero.
+class MipsGOT0Atom : public MipsGOTAtom {
+public:
+  MipsGOT0Atom(const File &f) : MipsGOTAtom(f) {}
+
+  virtual ArrayRef<uint8_t> rawContent() const {
+    return llvm::makeArrayRef(mipsGot0AtomContent);
+  }
+};
+
+/// \brief MIPS GOT entry initialized by zero.
+class MipsGOTModulePointerAtom : public MipsGOTAtom {
+public:
+  MipsGOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {}
+
+  virtual ArrayRef<uint8_t> rawContent() const {
+    return llvm::makeArrayRef(mipsGotModulePointerAtomContent);
+  }
+};
+
+class MipsGOTPassFile : public SimpleFile {
+public:
+  MipsGOTPassFile(const ELFLinkingContext &ctx)
+      : SimpleFile(ctx, "MipsGOTPassFile") {
+    setOrdinal(ctx.getNextOrdinalAndIncrement());
+  }
+
+  llvm::BumpPtrAllocator _alloc;
+};
+
+class MipsGOTPass : public Pass {
+public:
+  MipsGOTPass(MipsLinkingContext &context)
+      : _file(context), _got0(new (_file._alloc) MipsGOT0Atom(_file)),
+        _got1(new (_file._alloc) MipsGOTModulePointerAtom(_file)) {
+    _localGotVector.push_back(_got0);
+    _localGotVector.push_back(_got1);
+  }
+
+  virtual void perform(std::unique_ptr<MutableFile> &mf) {
+    // Process all references.
+    for (const auto &atom : mf->defined())
+      for (const auto &ref : *atom)
+        handleReference(*atom, *ref);
+
+    uint64_t ordinal = 0;
+
+    for (auto &got : _localGotVector) {
+      DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOT ] Adding L "
+                                              << got->name() << "\n");
+      got->setOrdinal(ordinal++);
+      mf->addAtom(*got);
+    }
+
+    for (auto &got : _globalGotVector) {
+      DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOT ] Adding G "
+                                              << got->name() << "\n");
+      got->setOrdinal(ordinal++);
+      mf->addAtom(*got);
+    }
+  }
+
+private:
+  /// \brief Owner of all the Atoms created by this pass.
+  MipsGOTPassFile _file;
+
+  /// \brief GOT header entries.
+  GOTAtom *_got0;
+  GOTAtom *_got1;
+
+  /// \brief Map Atoms to their GOT entries.
+  llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+
+  /// \brief the list of local GOT atoms.
+  std::vector<GOTAtom *> _localGotVector;
+
+  /// \brief the list of global GOT atoms.
+  std::vector<GOTAtom *> _globalGotVector;
+
+  /// \brief Handle a specific reference.
+  void handleReference(const DefinedAtom &atom, const Reference &ref) {
+    switch (ref.kind()) {
+    case R_MIPS_GOT16:
+    case R_MIPS_CALL16:
+      handleGOT(ref);
+      break;
+    }
+  }
+
+  void handleGOT(const Reference &ref) {
+    const_cast<Reference &>(ref).setTarget(getEntry(ref.target()));
+  }
+
+  const GOTAtom *getEntry(const Atom *a) {
+    auto got = _gotMap.find(a);
+    if (got != _gotMap.end())
+      return got->second;
+
+    const DefinedAtom *da = dyn_cast<DefinedAtom>(a);
+    bool isLocal = (da && da->scope() == Atom::scopeTranslationUnit);
+
+    auto ga = new (_file._alloc) MipsGOT0Atom(_file);
+    _gotMap[a] = ga;
+    if (isLocal)
+      _localGotVector.push_back(ga);
+    else {
+      if (da)
+        ga->addReference(R_MIPS_32, 0, a, 0);
+      else
+        ga->addReference(R_MIPS_NONE, 0, a, 0);
+      _globalGotVector.push_back(ga);
+    }
+
+    DEBUG_WITH_TYPE("MipsGOT", {
+      ga->_name = "__got_";
+      ga->_name += a->name();
+      llvm::dbgs() << "[ GOT ] Create " << (isLocal ? "L " : "G ") << a->name()
+                   << "\n";
+    });
+
+    return ga;
+  }
+};
+
+} // end anon namespace
+
+MipsLinkingContext::MipsLinkingContext(llvm::Triple triple)
+    : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+                                    new MipsTargetHandler(*this))) {}
+
+MipsTargetLayout<Mips32ElELFType> &MipsLinkingContext::getTargetLayout() {
+  auto &layout = getTargetHandler<Mips32ElELFType>().targetLayout();
+  return static_cast<MipsTargetLayout<Mips32ElELFType> &>(layout);
+}
+
+const MipsTargetLayout<Mips32ElELFType> &
+MipsLinkingContext::getTargetLayout() const {
+  auto &layout = getTargetHandler<Mips32ElELFType>().targetLayout();
+  return static_cast<MipsTargetLayout<Mips32ElELFType> &>(layout);
+}
+
+bool MipsLinkingContext::isLittleEndian() const {
+  return Mips32ElELFType::TargetEndianness == llvm::support::little;
+}
+
+#undef LLD_CASE
+#define LLD_CASE(name) .Case(#name, llvm::ELF::name)
+
+ErrorOr<Reference::Kind>
+MipsLinkingContext::relocKindFromString(StringRef str) const {
+  int32_t ret = llvm::StringSwitch<int32_t>(str)
+    LLD_CASE(R_MIPS_NONE)
+    LLD_CASE(R_MIPS_32)
+    LLD_CASE(R_MIPS_HI16)
+    LLD_CASE(R_MIPS_LO16)
+    LLD_CASE(R_MIPS_GOT16)
+    LLD_CASE(R_MIPS_CALL16)
+    LLD_CASE(R_MIPS_JALR)
+    .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>
+MipsLinkingContext::stringFromRelocKind(Reference::Kind kind) const {
+  switch (kind) {
+    LLD_CASE(R_MIPS_NONE)
+    LLD_CASE(R_MIPS_32)
+    LLD_CASE(R_MIPS_HI16)
+    LLD_CASE(R_MIPS_LO16)
+    LLD_CASE(R_MIPS_GOT16)
+    LLD_CASE(R_MIPS_CALL16)
+    LLD_CASE(R_MIPS_JALR)
+  }
+
+  return make_error_code(YamlReaderError::illegal_value);
+}
+
+void MipsLinkingContext::addPasses(PassManager &pm) {
+  switch (getOutputELFType()) {
+  case llvm::ELF::ET_DYN:
+    pm.add(std::unique_ptr<Pass>(new MipsGOTPass(*this)));
+    break;
+  default:
+    llvm_unreachable("Unhandled output file type");
+  }
+
+  ELFLinkingContext::addPasses(pm);
+}

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h Sun Dec 15 06:57:28 2013
@@ -0,0 +1,38 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h ---------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_MIPS_LINKING_CONTEXT_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> Mips32ElELFType;
+
+template <class ELFType> class MipsTargetLayout;
+
+class MipsLinkingContext LLVM_FINAL : public ELFLinkingContext {
+public:
+  MipsLinkingContext(llvm::Triple triple);
+
+  MipsTargetLayout<Mips32ElELFType> &getTargetLayout();
+  const MipsTargetLayout<Mips32ElELFType> &getTargetLayout() const;
+
+  // ELFLinkingContext
+  virtual bool isLittleEndian() const;
+  virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
+  virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
+  virtual void addPasses(PassManager &pm);
+};
+
+} // elf
+} // lld
+
+#endif

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp Sun Dec 15 06:57:28 2013
@@ -0,0 +1,189 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsTargetHandler.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+
+#include "lld/ReaderWriter/RelocationHelperFunctions.h"
+
+using namespace lld;
+using namespace elf;
+using namespace llvm::ELF;
+
+namespace {
+
+inline void applyReloc(uint8_t *location, uint32_t result) {
+  auto target = reinterpret_cast<llvm::support::ulittle32_t *>(location);
+  *target = result | *target;
+}
+
+/// \brief Calculate AHL value combines addends from 'hi' and 'lo' relocations.
+inline int64_t calcAHL(int64_t AHI, int64_t ALO) {
+  AHI &= 0xffff;
+  ALO &= 0xffff;
+  return (AHI << 16) + (int16_t)ALO;
+}
+
+/// \brief R_MIPS_32
+/// local/external: word32 S + A (truncate)
+void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+  uint32_t result = (uint32_t)(S + A);
+  applyReloc(location, result);
+}
+
+/// \brief R_MIPS_HI16
+/// local/external: hi16 (AHL + S) - (short)(AHL + S) (truncate)
+/// _gp_disp      : hi16 (AHL + GP - P) - (short)(AHL + GP - P) (verify)
+void relocHi16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
+               uint64_t GP, bool isGPDisp) {
+  int32_t result = 0;
+
+  if (isGPDisp)
+    result = (AHL + GP - P) - (int16_t)(AHL + GP - P);
+  else
+    result = (AHL + S) - (int16_t)(AHL + S);
+
+  result = lld::scatterBits<uint32_t>(result >> 16, 0xffff);
+  applyReloc(location, result);
+}
+
+/// \brief R_MIPS_LO16
+/// local/external: lo16 AHL + S (truncate)
+/// _gp_disp      : lo16 AHL + GP - P + 4 (verify)
+void relocLo16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
+               uint64_t GP, bool isGPDisp) {
+  int32_t result = 0;
+
+  if (isGPDisp)
+    result = AHL + GP - P + 4;
+  else
+    result = AHL + S;
+
+  result = lld::scatterBits<uint32_t>(result, 0xffff);
+  applyReloc(location, result);
+}
+
+/// \brief R_MIPS_GOT16
+/// local/external: rel16 G (verify)
+void relocGOT16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
+                uint64_t GP) {
+  // FIXME (simon): for local sym put high 16 bit of AHL to the GOT
+  int32_t G = (int32_t)(S - GP);
+  int32_t result = lld::scatterBits<uint32_t>(G, 0xffff);
+  applyReloc(location, result);
+}
+
+/// \brief R_MIPS_CALL16
+/// external: rel16 G (verify)
+void relocCall16(uint8_t *location, uint64_t P, uint64_t S, int64_t A,
+                 uint64_t GP) {
+  int32_t G = (int32_t)(S - GP);
+  int32_t result = lld::scatterBits<uint32_t>(G, 0xffff);
+  applyReloc(location, result);
+}
+
+} // end anon namespace
+
+MipsTargetRelocationHandler::MipsTargetRelocationHandler(
+    const MipsLinkingContext &context, const MipsTargetHandler &handler)
+    : _context(context), _targetHandler(handler) {}
+
+void
+MipsTargetRelocationHandler::savePairedRelocation(const lld::AtomLayout &atom,
+                                                  const Reference &ref) const {
+  auto pi = _pairedRelocations.find(&atom);
+  if (pi == _pairedRelocations.end())
+    pi = _pairedRelocations.emplace(&atom, PairedRelocationsT()).first;
+
+  pi->second.push_back(&ref);
+}
+
+void MipsTargetRelocationHandler::applyPairedRelocations(
+    ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+    int64_t loAddend) const {
+  auto pi = _pairedRelocations.find(&atom);
+  if (pi == _pairedRelocations.end())
+    return;
+
+  for (auto ri : pi->second) {
+    uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+    uint8_t *location = atomContent + ri->offsetInAtom();
+    uint64_t targetVAddress = writer.addressOfAtom(ri->target());
+    uint64_t relocVAddress = atom._virtualAddr + ri->offsetInAtom();
+
+    int64_t ahl = calcAHL(ri->addend(), loAddend);
+
+    switch (ri->kind()) {
+    case R_MIPS_HI16:
+      relocHi16(location, relocVAddress, targetVAddress, ahl,
+                _targetHandler.getGPDispSymAddr(),
+                ri->target()->name() == "_gp_disp");
+      break;
+    case R_MIPS_GOT16:
+      relocGOT16(location, relocVAddress, targetVAddress, ahl,
+                 _targetHandler.getGPDispSymAddr());
+      break;
+    default:
+      llvm_unreachable("Unknown type of paired relocation.");
+    }
+  }
+
+  _pairedRelocations.erase(pi);
+}
+
+error_code MipsTargetRelocationHandler::applyRelocation(
+    ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+    const Reference &ref) const {
+  uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+  uint8_t *location = atomContent + ref.offsetInAtom();
+  uint64_t targetVAddress = writer.addressOfAtom(ref.target());
+  uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+
+  switch (ref.kind()) {
+  case R_MIPS_NONE:
+    break;
+  case R_MIPS_32:
+    reloc32(location, relocVAddress, targetVAddress, ref.addend());
+    break;
+  case R_MIPS_HI16:
+    savePairedRelocation(atom, ref);
+    break;
+  case R_MIPS_LO16:
+    relocLo16(location, relocVAddress, targetVAddress, calcAHL(0, ref.addend()),
+              _targetHandler.getGPDispSymAddr(),
+              ref.target()->name() == "_gp_disp");
+    applyPairedRelocations(writer, buf, atom, ref.addend());
+    break;
+  case R_MIPS_GOT16:
+    savePairedRelocation(atom, ref);
+    break;
+  case R_MIPS_CALL16:
+    relocCall16(location, relocVAddress, targetVAddress, ref.addend(),
+                _targetHandler.getGPDispSymAddr());
+    break;
+  case R_MIPS_JALR:
+    // We do not do JALR optimization now.
+    break;
+  case lld::Reference::kindLayoutAfter:
+  case lld::Reference::kindLayoutBefore:
+  case lld::Reference::kindInGroup:
+    break;
+  default: {
+    std::string str;
+    llvm::raw_string_ostream s(str);
+    auto name = _context.stringFromRelocKind(ref.kind());
+    s << "Unhandled relocation: "
+      << (name ? *name : "<unknown>") << " (" << ref.kind() << ")";
+    llvm_unreachable(s.str().c_str());
+  }
+  }
+
+  return error_code::success();
+}

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h Sun Dec 15 06:57:28 2013
@@ -0,0 +1,49 @@
+//===- lld/ReaderWriter/ELF/Mips/MipsRelocationHandler.h ------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_RELOCATION_HANDLER_H
+#define LLD_READER_WRITER_ELF_MIPS_RELOCATION_HANDLER_H
+
+#include "MipsLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+class MipsTargetHandler;
+
+class MipsTargetRelocationHandler LLVM_FINAL
+    : public TargetRelocationHandler<Mips32ElELFType> {
+public:
+  MipsTargetRelocationHandler(const MipsLinkingContext &context,
+                              const MipsTargetHandler &handler);
+
+  virtual error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+                                     const lld::AtomLayout &,
+                                     const Reference &) const;
+
+private:
+  const MipsLinkingContext &_context;
+  const MipsTargetHandler &_targetHandler;
+
+  typedef std::vector<const Reference *> PairedRelocationsT;
+  typedef std::unordered_map<const lld::AtomLayout *, PairedRelocationsT>
+  PairedRelocationMapT;
+
+  mutable PairedRelocationMapT _pairedRelocations;
+
+  void savePairedRelocation(const lld::AtomLayout &atom,
+                            const Reference &ref) const;
+  void applyPairedRelocations(ELFWriter &writer, llvm::FileOutputBuffer &buf,
+                              const lld::AtomLayout &atom,
+                              int64_t loAddend) const;
+};
+
+} // elf
+} // lld
+
+#endif

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h Sun Dec 15 06:57:28 2013
@@ -0,0 +1,80 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h ----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_SECTION_CHUNKS_H
+#define LLD_READER_WRITER_ELF_MIPS_SECTION_CHUNKS_H
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class MipsTargetLayout;
+class MipsLinkingContext;
+
+/// \brief Handle Mips GOT section
+template <class ELFType> class MipsGOTSection : public AtomSection<ELFType> {
+public:
+  MipsGOTSection(const MipsLinkingContext &context)
+      : AtomSection<ELFType>(context, ".got", DefinedAtom::typeGOT,
+                             DefinedAtom::permRW_,
+                             MipsTargetLayout<ELFType>::ORDER_GOT),
+        _globalCount(0) {
+    this->_flags |= SHF_MIPS_GPREL;
+    this->_align2 = 4;
+  }
+
+  /// \brief Number of local GOT entries.
+  std::size_t getLocalCount() const {
+    return this->_atoms.size() - _globalCount;
+  }
+
+  /// \brief Number of global GOT entries.
+  std::size_t getGlobalCount() const { return _globalCount; }
+
+  /// \brief Compare two atoms accordingly theirs positions in the GOT.
+  bool compare(const Atom *a, const Atom *b) const {
+    auto ia = _posMap.find(a);
+    auto ib = _posMap.find(b);
+
+    if (ia != _posMap.end() && ib != _posMap.end())
+      return ia->second < ib->second;
+
+    return ia == _posMap.end() && ib != _posMap.end();
+  }
+
+  virtual const lld::AtomLayout &appendAtom(const Atom *atom) {
+    const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
+
+    const Atom *ta = nullptr;
+    for (const auto &r : *da) {
+      if (r->kind() == llvm::ELF::R_MIPS_32 ||
+          r->kind() == llvm::ELF::R_MIPS_NONE) {
+        ta = r->target();
+        break;
+      }
+    }
+
+    if (ta) {
+      _posMap[ta] = _posMap.size();
+      ++_globalCount;
+    }
+
+    return AtomSection<ELFType>::appendAtom(atom);
+  }
+
+private:
+  /// \brief Number of global GOT entries.
+  std::size_t _globalCount;
+
+  /// \brief Map Atoms to their GOT entry index.
+  llvm::DenseMap<const Atom *, std::size_t> _posMap;
+};
+
+} // elf
+} // lld
+
+#endif

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTarget.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTarget.h?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTarget.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTarget.h Sun Dec 15 06:57:28 2013
@@ -0,0 +1,10 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsTarget.h -----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsLinkingContext.h"

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp Sun Dec 15 06:57:28 2013
@@ -0,0 +1,175 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp --------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "File.h"
+#include "MipsLinkingContext.h"
+#include "MipsTargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+namespace {
+
+class MipsDynamicSymbolTable : public DynamicSymbolTable<Mips32ElELFType> {
+public:
+  MipsDynamicSymbolTable(const MipsLinkingContext &context)
+      : DynamicSymbolTable<Mips32ElELFType>(
+            context, ".dynsym",
+            DefaultLayout<Mips32ElELFType>::ORDER_DYNAMIC_SYMBOLS),
+        _layout(context.getTargetLayout()) {}
+
+  virtual void sortSymbols() {
+    std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
+                     [this](const SymbolEntry &A, const SymbolEntry &B) {
+      if (A._symbol.getBinding() != STB_GLOBAL &&
+          B._symbol.getBinding() != STB_GLOBAL)
+        return A._symbol.getBinding() < B._symbol.getBinding();
+
+      return _layout.getGOTSection().compare(A._atom, B._atom);
+    });
+  }
+
+private:
+  const MipsTargetLayout<Mips32ElELFType> &_layout;
+};
+
+class MipsDynamicTable : public DynamicTable<Mips32ElELFType> {
+public:
+  MipsDynamicTable(MipsLinkingContext &context)
+      : DynamicTable<Mips32ElELFType>(
+            context, ".dynamic", DefaultLayout<Mips32ElELFType>::ORDER_DYNAMIC),
+        _layout(context.getTargetLayout()) {}
+
+  virtual void createDefaultEntries() {
+    DynamicTable<Mips32ElELFType>::createDefaultEntries();
+
+    Elf_Dyn dyn;
+
+    // Version id for the Runtime Linker Interface.
+    dyn.d_un.d_val = 1;
+    dyn.d_tag = DT_MIPS_RLD_VERSION;
+    addEntry(dyn);
+
+    // MIPS flags.
+    dyn.d_un.d_val = RHF_NOTPOT;
+    dyn.d_tag = DT_MIPS_FLAGS;
+    addEntry(dyn);
+
+    // The base address of the segment.
+    dyn.d_un.d_ptr = 0;
+    dyn.d_tag = DT_MIPS_BASE_ADDRESS;
+    addEntry(dyn);
+
+    // Number of local global offset table entries.
+    dyn.d_un.d_val = 0;
+    dyn.d_tag = DT_MIPS_LOCAL_GOTNO;
+    _dt_localgot = addEntry(dyn);
+
+    // Number of entries in the .dynsym section.
+    dyn.d_un.d_val = 0;
+    dyn.d_tag = DT_MIPS_SYMTABNO;
+    _dt_symtabno = addEntry(dyn);
+
+    // The index of the first dynamic symbol table entry that corresponds
+    // to an entry in the global offset table.
+    dyn.d_un.d_val = 0;
+    dyn.d_tag = DT_MIPS_GOTSYM;
+    _dt_gotsym = addEntry(dyn);
+
+    // Address of the .got section.
+    dyn.d_un.d_val = 0;
+    dyn.d_tag = DT_PLTGOT;
+    _dt_pltgot = addEntry(dyn);
+  }
+
+  virtual void updateDynamicTable() {
+    DynamicTable<Mips32ElELFType>::updateDynamicTable();
+
+    auto &got = _layout.getGOTSection();
+
+    _entries[_dt_symtabno].d_un.d_val = getSymbolTable()->size();
+    _entries[_dt_gotsym].d_un.d_val =
+        getSymbolTable()->size() - got.getGlobalCount();
+    _entries[_dt_localgot].d_un.d_val = got.getLocalCount();
+    _entries[_dt_pltgot].d_un.d_ptr =
+        _layout.findOutputSection(".got")->virtualAddr();
+  }
+
+private:
+  MipsTargetLayout<Mips32ElELFType> &_layout;
+
+  std::size_t _dt_symtabno;
+  std::size_t _dt_localgot;
+  std::size_t _dt_gotsym;
+  std::size_t _dt_pltgot;
+};
+}
+
+MipsTargetHandler::MipsTargetHandler(MipsLinkingContext &context)
+    : DefaultTargetHandler(context), _targetLayout(context),
+      _relocationHandler(context, *this) {}
+
+uint64_t MipsTargetHandler::getGPDispSymAddr() const {
+  return _gpDispSymAtom ? _gpDispSymAtom->_virtualAddr : 0;
+}
+
+MipsTargetLayout<Mips32ElELFType> &MipsTargetHandler::targetLayout() {
+  return _targetLayout;
+}
+
+const MipsTargetRelocationHandler &
+MipsTargetHandler::getRelocationHandler() const {
+  return _relocationHandler;
+}
+
+LLD_UNIQUE_BUMP_PTR(DynamicTable<Mips32ElELFType>)
+MipsTargetHandler::createDynamicTable() {
+  return LLD_UNIQUE_BUMP_PTR(DynamicTable<Mips32ElELFType>)(
+      new (_alloc) MipsDynamicTable(
+          static_cast<MipsLinkingContext &>(_context)));
+}
+
+LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<Mips32ElELFType>)
+MipsTargetHandler::createDynamicSymbolTable() {
+  return LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<Mips32ElELFType>)(
+      new (_alloc) MipsDynamicSymbolTable(
+          static_cast<MipsLinkingContext &>(_context)));
+}
+
+bool MipsTargetHandler::createImplicitFiles(
+    std::vector<std::unique_ptr<File>> &result) {
+  typedef CRuntimeFile<Mips32ElELFType> RFile;
+  auto file = std::unique_ptr<RFile>(new RFile(_context, "MIPS runtime file"));
+
+  if (_context.isDynamic()) {
+    file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+    file->addAbsoluteAtom("_gp_disp");
+  }
+  result.push_back(std::move(file));
+  return true;
+}
+
+void MipsTargetHandler::finalizeSymbolValues() {
+  DefaultTargetHandler<Mips32ElELFType>::finalizeSymbolValues();
+
+  if (_context.isDynamic()) {
+    auto gotSection = _targetLayout.findOutputSection(".got");
+
+    auto gotAtomIter = _targetLayout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+    assert(gotAtomIter != _targetLayout.absoluteAtoms().end());
+    _gotSymAtom = (*gotAtomIter);
+    _gotSymAtom->_virtualAddr = gotSection ? gotSection->virtualAddr() : 0;
+
+    auto gpDispAtomIter = _targetLayout.findAbsoluteAtom("_gp_disp");
+    assert(gpDispAtomIter != _targetLayout.absoluteAtoms().end());
+    _gpDispSymAtom = (*gpDispAtomIter);
+    _gpDispSymAtom->_virtualAddr =
+        gotSection ? gotSection->virtualAddr() + 0x7FF0 : 0;
+  }
+}

Added: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h?rev=197342&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h Sun Dec 15 06:57:28 2013
@@ -0,0 +1,74 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h ----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_MIPS_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+#include "MipsSectionChunks.h"
+#include "TargetLayout.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief TargetLayout for Mips
+template <class ELFType>
+class MipsTargetLayout LLVM_FINAL : public TargetLayout<ELFType> {
+public:
+  MipsTargetLayout(const MipsLinkingContext &ctx)
+      : TargetLayout<ELFType>(ctx),
+        _gotSection(new (_alloc) MipsGOTSection<ELFType>(ctx)) {}
+
+  const MipsGOTSection<ELFType> &getGOTSection() const { return *_gotSection; }
+
+  virtual AtomSection<ELFType> *
+  createSection(StringRef name, int32_t type,
+                DefinedAtom::ContentPermissions permissions,
+                Layout::SectionOrder order) {
+    if (type == DefinedAtom::typeGOT)
+      return _gotSection;
+    return DefaultLayout<ELFType>::createSection(name, type, permissions,
+                                                 order);
+  }
+
+private:
+  llvm::BumpPtrAllocator _alloc;
+  MipsGOTSection<ELFType> *_gotSection;
+};
+
+/// \brief TargetHandler for Mips
+class MipsTargetHandler LLVM_FINAL
+    : public DefaultTargetHandler<Mips32ElELFType> {
+public:
+  MipsTargetHandler(MipsLinkingContext &targetInfo);
+
+  uint64_t getGPDispSymAddr() const;
+
+  virtual MipsTargetLayout<Mips32ElELFType> &targetLayout();
+  virtual const MipsTargetRelocationHandler &getRelocationHandler() const;
+  virtual LLD_UNIQUE_BUMP_PTR(DynamicTable<Mips32ElELFType>)
+  createDynamicTable();
+  virtual LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<Mips32ElELFType>)
+  createDynamicSymbolTable();
+  virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &result);
+  virtual void finalizeSymbolValues();
+
+private:
+  llvm::BumpPtrAllocator _alloc;
+  MipsTargetLayout<Mips32ElELFType> _targetLayout;
+  MipsTargetRelocationHandler _relocationHandler;
+  AtomLayout *_gotSymAtom;
+  AtomLayout *_gpDispSymAtom;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif

Modified: lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h Sun Dec 15 06:57:28 2013
@@ -286,12 +286,10 @@ template <class ELFT> void OutputELFWrit
   }
 
   if (_context.isDynamic()) {
-    _dynamicTable.reset(new (_alloc) DynamicTable<ELFT>(
-        _context, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
+    _dynamicTable = std::move(_targetHandler.createDynamicTable());
     _dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
         _context, ".dynstr", DefaultLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true));
-    _dynamicSymbolTable.reset(new (_alloc) DynamicSymbolTable<ELFT>(
-        _context, ".dynsym", DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
+    _dynamicSymbolTable = std::move(_targetHandler.createDynamicSymbolTable());
     _hashTable.reset(new (_alloc) HashSection<ELFT>(
         _context, ".hash", DefaultLayout<ELFT>::ORDER_HASH));
     // Set the hash table in the dynamic symbol table so that the entries in the

Modified: lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h Sun Dec 15 06:57:28 2013
@@ -607,19 +607,10 @@ template<class ELFT>
 class SymbolTable : public Section<ELFT> {
   typedef typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr
       Elf_Addr;
-  typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
-
-  struct SymbolEntry {
-    SymbolEntry(const Atom *a, const Elf_Sym &sym,
-                const lld::AtomLayout *layout)
-        : _atom(a), _atomLayout(layout), _symbol(sym) {}
-
-    const Atom *_atom;
-    const lld::AtomLayout *_atomLayout;
-    Elf_Sym _symbol;
-  };
 
 public:
+  typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
   SymbolTable(const ELFLinkingContext &context, const char *str, int32_t order);
 
   /// \brief set the number of entries that would exist in the symbol
@@ -629,6 +620,9 @@ public:
       _stringSection->setNumEntries(numEntries);
   }
 
+  /// \brief return number of entries
+  std::size_t size() const { return _symbolTable.size(); }
+
   void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0,
                  const lld::AtomLayout *layout = nullptr);
 
@@ -669,6 +663,16 @@ public:
   StringTable<ELFT> *getStringTable() const { return _stringSection; }
 
 protected:
+  struct SymbolEntry {
+    SymbolEntry(const Atom *a, const Elf_Sym &sym,
+                const lld::AtomLayout *layout)
+        : _atom(a), _atomLayout(layout), _symbol(sym) {}
+
+    const Atom *_atom;
+    const lld::AtomLayout *_atomLayout;
+    Elf_Sym _symbol;
+  };
+
   llvm::BumpPtrAllocator _symbolAllocate;
   StringTable<ELFT> *_stringSection;
   std::vector<SymbolEntry> _symbolTable;
@@ -982,10 +986,10 @@ private:
 template <class ELFT> class HashSection;
 
 template <class ELFT> class DynamicTable : public Section<ELFT> {
+public:
   typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn;
   typedef std::vector<Elf_Dyn> EntriesT;
 
-public:
   DynamicTable(const ELFLinkingContext &context, StringRef str, int32_t order)
       : Section<ELFT>(context, str) {
     this->setOrder(order);
@@ -1020,7 +1024,7 @@ public:
     std::memcpy(dest, _entries.data(), this->_fsize);
   }
 
-  void createDefaultEntries() {
+  virtual void createDefaultEntries() {
     Elf_Dyn dyn;
     dyn.d_un.d_val = 0;
 
@@ -1074,9 +1078,13 @@ public:
     _dynamicSymbolTable = dynsym;
   }
 
+  const DynamicSymbolTable<ELFT> *getSymbolTable() const {
+    return _dynamicSymbolTable;
+  }
+
   void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; }
 
-  void updateDynamicTable() {
+  virtual void updateDynamicTable() {
     StringTable<ELFT> *dynamicStringTable =
         _dynamicSymbolTable->getStringTable();
     _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr();
@@ -1104,8 +1112,10 @@ public:
     }
   }
 
-private:
+protected:
   EntriesT _entries;
+
+private:
   std::size_t _dt_hash;
   std::size_t _dt_strtab;
   std::size_t _dt_symtab;

Modified: lld/trunk/lib/ReaderWriter/ELF/TargetHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/TargetHandler.h?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/TargetHandler.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/TargetHandler.h Sun Dec 15 06:57:28 2013
@@ -20,6 +20,7 @@
 
 #include "lld/Core/LLVM.h"
 #include "lld/Core/LinkingContext.h"
+#include "lld/Core/STDExtras.h"
 #include "lld/ReaderWriter/ELFLinkingContext.h"
 
 #include "llvm/ADT/Hashing.h"
@@ -30,6 +31,8 @@
 
 namespace lld {
 namespace elf {
+template <class ELFT> class DynamicTable;
+template <class ELFT> class DynamicSymbolTable;
 template <class ELFT> class ELFDefinedAtom;
 template <class ELFT> class ELFReference;
 class ELFWriter;
@@ -117,8 +120,15 @@ public:
   /// symbols over to small data, this would also be used
   virtual void allocateCommons() = 0;
 
+  /// \brief create dynamic table
+  virtual LLD_UNIQUE_BUMP_PTR(DynamicTable<ELFT>) createDynamicTable() = 0;
+
+  /// \brief create dynamic symbol table
+  virtual LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<ELFT>)
+  createDynamicSymbolTable() = 0;
+
 protected:
-  const ELFLinkingContext &_context;
+  ELFLinkingContext &_context;
 };
 } // end namespace elf
 } // end namespace lld

Modified: lld/trunk/lib/ReaderWriter/ELF/Targets.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Targets.h?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Targets.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Targets.h Sun Dec 15 06:57:28 2013
@@ -11,6 +11,7 @@
 #define LLD_READER_WRITER_ELF_TARGETS_H
 
 #include "Hexagon/HexagonTarget.h"
+#include "Mips/MipsTarget.h"
 #include "PPC/PPCTarget.h"
 #include "X86/X86Target.h"
 #include "X86_64/X86_64Target.h"

Added: lld/trunk/test/elf/Mips/Inputs/dynobj.c
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/Inputs/dynobj.c?rev=197342&view=auto
==============================================================================
--- lld/trunk/test/elf/Mips/Inputs/dynobj.c (added)
+++ lld/trunk/test/elf/Mips/Inputs/dynobj.c Sun Dec 15 06:57:28 2013
@@ -0,0 +1,14 @@
+// clang -O0 -EL -fPIC -target mipsel-linux-gnu -c dynobj.c -o dynobj.o
+int xyz(const char *);
+int abc(const char *);
+
+int bar(void)
+{
+  return 1;
+}
+
+int foo(void)
+{
+  bar();
+  return xyz("str1") + abc("str2");
+}

Added: lld/trunk/test/elf/Mips/Inputs/dynobj.o
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/Inputs/dynobj.o?rev=197342&view=auto
==============================================================================
Binary files lld/trunk/test/elf/Mips/Inputs/dynobj.o (added) and lld/trunk/test/elf/Mips/Inputs/dynobj.o Sun Dec 15 06:57:28 2013 differ

Added: lld/trunk/test/elf/Mips/dynlib-dynamic.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/dynlib-dynamic.test?rev=197342&view=auto
==============================================================================
--- lld/trunk/test/elf/Mips/dynlib-dynamic.test (added)
+++ lld/trunk/test/elf/Mips/dynlib-dynamic.test Sun Dec 15 06:57:28 2013
@@ -0,0 +1,27 @@
+# Check MIPS specific tags in the dynamic table.
+RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+RUN:     -o %t %p/Inputs/dynobj.o
+RUN: llvm-readobj -dynamic-table %t | FileCheck %s
+
+CHECK: Format: ELF32-mips
+CHECK: Arch: mipsel
+CHECK: AddressSize: 32bit
+CHECK: LoadName: 
+CHECK: DynamicSection [ (15 entries)
+CHECK:   Tag        Type                 Name/Value
+CHECK:   0x00000004 HASH                 0xE0
+CHECK:   0x00000005 STRTAB               0x158
+CHECK:   0x00000006 SYMTAB               0x108
+CHECK:   0x0000000A STRSZ                17 (bytes)
+CHECK:   0x0000000B SYMENT               16 (bytes)
+CHECK:   0x0000001A FINI_ARRAY           0x0
+CHECK:   0x0000001C FINI_ARRAYSZ         0 (bytes)
+CHECK:   0x70000001 MIPS_RLD_VERSION     1
+CHECK:   0x70000005 MIPS_FLAGS           0x2
+CHECK:   0x70000006 MIPS_BASE_ADDRESS    0x0
+CHECK:   0x7000000A MIPS_LOCAL_GOTNO     4
+CHECK:   0x70000011 MIPS_SYMTABNO        5
+CHECK:   0x70000013 MIPS_GOTSYM          0x2
+CHECK:   0x00000003 PLTGOT               0x1000
+CHECK:   0x00000000 NULL                 0x0
+CHECK: ]

Added: lld/trunk/test/elf/Mips/dynlib-dynsym.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/dynlib-dynsym.test?rev=197342&view=auto
==============================================================================
--- lld/trunk/test/elf/Mips/dynlib-dynsym.test (added)
+++ lld/trunk/test/elf/Mips/dynlib-dynsym.test Sun Dec 15 06:57:28 2013
@@ -0,0 +1,118 @@
+# Check sorting of .dynsym content accordingly to .got section.
+RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+RUN:     -o %t %p/Inputs/dynobj.o
+RUN: llvm-readobj -dyn-symbols %t | FileCheck -check-prefix=CHECK-DYN %s
+
+RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+RUN:     --output-filetype=yaml -o %t %p/Inputs/dynobj.o
+RUN: FileCheck -check-prefix=CHECK-GOT %s < %t
+
+CHECK-DYN: Format: ELF32-mips
+CHECK-DYN: Arch: mipsel
+CHECK-DYN: AddressSize: 32bit
+CHECK-DYN: LoadName: 
+CHECK-DYN: DynamicSymbols [
+CHECK-DYN:   Symbol {
+CHECK-DYN:     Name: @ (0)
+CHECK-DYN:     Value: 0x0
+CHECK-DYN:     Size: 0
+CHECK-DYN:     Binding: Local (0x0)
+CHECK-DYN:     Type: None (0x0)
+CHECK-DYN:     Other: 0
+CHECK-DYN:     Section:  (0x0)
+CHECK-DYN:   }
+CHECK-DYN:   Symbol {
+CHECK-DYN:     Name: foo@ (5)
+CHECK-DYN:     Value: 0x194
+CHECK-DYN:     Size: 156
+CHECK-DYN:     Binding: Global (0x1)
+CHECK-DYN:     Type: Function (0x2)
+CHECK-DYN:     Other: 0
+CHECK-DYN:     Section: .text (0x4)
+CHECK-DYN:   }
+CHECK-DYN:   Symbol {
+CHECK-DYN:     Name: bar@ (1)
+CHECK-DYN:     Value: 0x170
+CHECK-DYN:     Size: 36
+CHECK-DYN:     Binding: Global (0x1)
+CHECK-DYN:     Type: Function (0x2)
+CHECK-DYN:     Other: 0
+CHECK-DYN:     Section: .text (0x4)
+CHECK-DYN:   }
+CHECK-DYN:   Symbol {
+CHECK-DYN:     Name: xyz@ (9)
+CHECK-DYN:     Value: 0x0
+CHECK-DYN:     Size: 0
+CHECK-DYN:     Binding: Global (0x1)
+CHECK-DYN:     Type: None (0x0)
+CHECK-DYN:     Other: 0
+CHECK-DYN:     Section:  (0x0)
+CHECK-DYN:   }
+CHECK-DYN:   Symbol {
+CHECK-DYN:     Name: abc@ (13)
+CHECK-DYN:     Value: 0x0
+CHECK-DYN:     Size: 0
+CHECK-DYN:     Binding: Global (0x1)
+CHECK-DYN:     Type: None (0x0)
+CHECK-DYN:     Other: 0
+CHECK-DYN:     Section:  (0x0)
+CHECK-DYN:   }
+CHECK-DYN: ]
+
+CHECK-GOT:   - type:            got
+CHECK-GOT:     content:         [ 00, 00, 00, 00 ]
+CHECK-GOT:     alignment:       2^2
+CHECK-GOT:     section-choice:  custom-required
+CHECK-GOT:     section-name:    .got
+CHECK-GOT:     permissions:     rw-
+CHECK-GOT:   - type:            got
+CHECK-GOT:     content:         [ 00, 00, 00, 80 ]
+CHECK-GOT:     alignment:       2^2
+CHECK-GOT:     section-choice:  custom-required
+CHECK-GOT:     section-name:    .got
+CHECK-GOT:     permissions:     rw-
+CHECK-GOT:   - ref-name:        L004
+CHECK-GOT:     type:            got
+CHECK-GOT:     content:         [ 00, 00, 00, 00 ]
+CHECK-GOT:     alignment:       2^2
+CHECK-GOT:     section-choice:  custom-required
+CHECK-GOT:     section-name:    .got
+CHECK-GOT:     permissions:     rw-
+CHECK-GOT:   - ref-name:        L006
+CHECK-GOT:     type:            got
+CHECK-GOT:     content:         [ 00, 00, 00, 00 ]
+CHECK-GOT:     alignment:       2^2
+CHECK-GOT:     section-choice:  custom-required
+CHECK-GOT:     section-name:    .got
+CHECK-GOT:     permissions:     rw-
+CHECK-GOT:   - ref-name:        L003
+CHECK-GOT:     type:            got
+CHECK-GOT:     content:         [ 00, 00, 00, 00 ]
+CHECK-GOT:     alignment:       2^2
+CHECK-GOT:     section-choice:  custom-required
+CHECK-GOT:     section-name:    .got
+CHECK-GOT:     permissions:     rw-
+CHECK-GOT:     references:
+CHECK-GOT:       - kind:            R_MIPS_32
+CHECK-GOT:         offset:          0
+CHECK-GOT:         target:          bar
+CHECK-GOT:   - ref-name:        L005
+CHECK-GOT:     type:            got
+CHECK-GOT:     content:         [ 00, 00, 00, 00 ]
+CHECK-GOT:     alignment:       2^2
+CHECK-GOT:     section-choice:  custom-required
+CHECK-GOT:     section-name:    .got
+CHECK-GOT:     permissions:     rw-
+CHECK-GOT:   - ref-name:        L007
+CHECK-GOT:     type:            got
+CHECK-GOT:     content:         [ 00, 00, 00, 00 ]
+CHECK-GOT:     alignment:       2^2
+CHECK-GOT:     section-choice:  custom-required
+CHECK-GOT:     section-name:    .got
+CHECK-GOT:     permissions:     rw-
+CHECK-GOT:   - ref-name:        L002
+CHECK-GOT:     alignment:       2^4
+CHECK-GOT:     references:
+CHECK-GOT:       - kind:            layout-after
+CHECK-GOT:         offset:          0
+CHECK-GOT:         target:          bar

Added: lld/trunk/test/elf/Mips/dynlib-fileheader.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/dynlib-fileheader.test?rev=197342&view=auto
==============================================================================
--- lld/trunk/test/elf/Mips/dynlib-fileheader.test (added)
+++ lld/trunk/test/elf/Mips/dynlib-fileheader.test Sun Dec 15 06:57:28 2013
@@ -0,0 +1,33 @@
+RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+RUN:     -o %t %p/Inputs/dynobj.o
+RUN: llvm-readobj -file-headers %t | FileCheck %s
+
+CHECK: Format: ELF32-mips
+CHECK: Arch: mipsel
+CHECK: AddressSize: 32bit
+CHECK: LoadName: 
+CHECK: ElfHeader {
+CHECK:   Ident {
+CHECK:    Magic: (7F 45 4C 46)
+CHECK:    Class: 32-bit (0x1)
+CHECK:    DataEncoding: LittleEndian (0x1)
+CHECK:    FileVersion: 1
+CHECK:    OS/ABI: SystemV (0x0)
+CHECK:    ABIVersion: 0
+CHECK:    Unused: (00 00 00 00 00 00 00)
+CHECK:  }
+CHECK:  Type: SharedObject (0x3)
+CHECK:  Machine: EM_MIPS (0x8)
+CHECK:  Version: 1
+CHECK:  Entry: 0x170
+CHECK:  ProgramHeaderOffset: 0x34
+CHECK:  SectionHeaderOffset: 0x21C8
+CHECK:  Flags [ (0x0)
+CHECK:  ]
+CHECK:  HeaderSize: 52
+CHECK:  ProgramHeaderEntrySize: 32
+CHECK:  ProgramHeaderCount: 5
+CHECK:  SectionHeaderEntrySize: 40
+CHECK:  SectionHeaderCount: 16
+CHECK:  StringTableSectionIndex: 13
+CHECK:}

Added: lld/trunk/test/elf/Mips/dynlib-gotsym.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/dynlib-gotsym.test?rev=197342&view=auto
==============================================================================
--- lld/trunk/test/elf/Mips/dynlib-gotsym.test (added)
+++ lld/trunk/test/elf/Mips/dynlib-gotsym.test Sun Dec 15 06:57:28 2013
@@ -0,0 +1,11 @@
+# Check _gp_disp and GOT_OFFSET_TABLE value
+RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+RUN:     -o %t %p/Inputs/dynobj.o
+RUN: llvm-objdump -section-headers -t %t | FileCheck %s
+
+CHECK: Idx Name          Size      Address          Type
+CHECK:   7 .got          0000001c 0000000000001000 DATA 
+
+CHECK: SYMBOL TABLE:
+CHECK: 00001000 g       *ABS*  00000000 _GLOBAL_OFFSET_TABLE_
+CHECK: 00008ff0 g       *ABS*  00000000 _gp_disp

Modified: lld/trunk/test/elf/phdr.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/phdr.test?rev=197342&r1=197341&r2=197342&view=diff
==============================================================================
--- lld/trunk/test/elf/phdr.test (original)
+++ lld/trunk/test/elf/phdr.test Sun Dec 15 06:57:28 2013
@@ -92,7 +92,7 @@ I386-NEXT:     MemSize: 64
 I386-NEXT:     Flags [ (0x4)
 I386-NEXT:       PF_R (0x4)
 I386-NEXT:     ]
-I386-NEXT:     Alignment: 4
+I386-NEXT:     Alignment: 2
 I386-NEXT:   }
 
 X86_64: LOAD off    0x0000000000000000





More information about the llvm-commits mailing list