diff --git a/lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt index 5893a76e95a4..9101ac1b8a82 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt +++ b/lld/lib/ReaderWriter/ELF/Mips/CMakeLists.txt @@ -1,6 +1,7 @@ add_lld_library(lldMipsELFTarget MipsLinkingContext.cpp MipsRelocationHandler.cpp + MipsRelocationPass.cpp MipsTargetHandler.cpp ) diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp index 6d7b6a162511..a6c52d9c51f8 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp @@ -9,6 +9,7 @@ #include "Atoms.h" #include "MipsLinkingContext.h" +#include "MipsRelocationPass.h" #include "MipsTargetHandler.h" #include "llvm/ADT/StringSwitch.h" @@ -16,151 +17,6 @@ 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("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) { - if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::Mips); - switch (ref.kindValue()) { - 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->addReferenceELF_Mips(R_MIPS_32, 0, a, 0); - else - ga->addReferenceELF_Mips(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))) {} @@ -181,13 +37,8 @@ bool MipsLinkingContext::isLittleEndian() const { } 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"); - } - + auto pass = createMipsRelocationPass(*this); + if (pass) + pm.add(std::move(pass)); ELFLinkingContext::addPasses(pm); } diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp new file mode 100644 index 000000000000..ad9c14c65d09 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp @@ -0,0 +1,175 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp -------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsLinkingContext.h" +#include "MipsRelocationPass.h" + +#include "Atoms.h" + +namespace { + +using namespace lld; +using namespace lld::elf; +using namespace llvm::ELF; + +// 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("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) { + if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) + return; + assert(ref.kindArch() == Reference::KindArch::Mips); + switch (ref.kindValue()) { + 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->addReferenceELF_Mips(R_MIPS_32, 0, a, 0); + else + ga->addReferenceELF_Mips(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 + +std::unique_ptr<Pass> +lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) { + switch (ctx.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + case llvm::ELF::ET_DYN: + return std::unique_ptr<Pass>(new MipsGOTPass(ctx)); + case llvm::ELF::ET_REL: + return std::unique_ptr<Pass>(); + default: + llvm_unreachable("Unhandled output file type"); + } +} diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h new file mode 100644 index 000000000000..7b2481a9f043 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h @@ -0,0 +1,25 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.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_PASS_H +#define LLD_READER_WRITER_ELF_MIPS_RELOCATION_PASS_H + +#include <memory> + +namespace lld { +class Pass; + +namespace elf { +class MipsLinkingContext; + +std::unique_ptr<Pass> createMipsRelocationPass(MipsLinkingContext &ctx); + +} // end namespace elf +} // end namespace lld + +#endif