diff options
author | Simon Atanasyan <simon@atanasyan.com> | 2013-12-15 12:57:28 +0000 |
---|---|---|
committer | Simon Atanasyan <simon@atanasyan.com> | 2013-12-15 12:57:28 +0000 |
commit | 9931f95bac43c621d0343f9ef8777a60f5030b37 (patch) | |
tree | 50d16c2551e41d2305d352b6519f889522357b08 /lld/lib/ReaderWriter/ELF/Mips | |
parent | 7631b0eba40b0996cfd0b7fa614fbde0bcdb872a (diff) | |
download | bcm5719-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.txt | 9 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp | 230 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h | 38 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp | 189 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h | 49 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h | 80 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsTarget.h | 10 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp | 175 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h | 74 |
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 |