summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/Mips
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2013-12-15 12:57:28 +0000
committerSimon Atanasyan <simon@atanasyan.com>2013-12-15 12:57:28 +0000
commit9931f95bac43c621d0343f9ef8777a60f5030b37 (patch)
tree50d16c2551e41d2305d352b6519f889522357b08 /lld/lib/ReaderWriter/ELF/Mips
parent7631b0eba40b0996cfd0b7fa614fbde0bcdb872a (diff)
downloadbcm5719-llvm-9931f95bac43c621d0343f9ef8777a60f5030b37.tar.gz
bcm5719-llvm-9931f95bac43c621d0343f9ef8777a60f5030b37.zip
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 llvm-svn: 197342
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/Mips')
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt9
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp230
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h38
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp189
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h49
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h80
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsTarget.h10
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp175
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h74
9 files changed, 854 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
new file mode 100644
index 00000000000..5893a76e95a
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lld_library(lldMipsELFTarget
+ MipsLinkingContext.cpp
+ MipsRelocationHandler.cpp
+ MipsTargetHandler.cpp
+ )
+
+target_link_libraries(lldMipsELFTarget
+ lldCore
+ )
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
new file mode 100644
index 00000000000..24718a3e3d4
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
@@ -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);
+}
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
new file mode 100644
index 00000000000..980cce49ac0
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
@@ -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
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
new file mode 100644
index 00000000000..a157c6b02b5
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
@@ -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();
+}
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
new file mode 100644
index 00000000000..af8bef655c8
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
@@ -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
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
new file mode 100644
index 00000000000..bbc66618e2d
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
@@ -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
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTarget.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTarget.h
new file mode 100644
index 00000000000..fe7012a84c1
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTarget.h
@@ -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"
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
new file mode 100644
index 00000000000..edcab37c7c3
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -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;
+ }
+}
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
new file mode 100644
index 00000000000..5e44eee98cf
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
@@ -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
OpenPOWER on IntegriCloud