diff options
| author | Simon Atanasyan <simon@atanasyan.com> | 2014-04-29 05:21:54 +0000 |
|---|---|---|
| committer | Simon Atanasyan <simon@atanasyan.com> | 2014-04-29 05:21:54 +0000 |
| commit | 8de2b8fb81ba8ded01f3b1a04edbc6550e65a435 (patch) | |
| tree | a0a3d01fbadd938d67e2a2232e08d61c95a7e2b4 /lld/lib/ReaderWriter/ELF/Mips | |
| parent | f293b3e52c57735bdcc2b9520d372ded86149ef6 (diff) | |
| download | bcm5719-llvm-8de2b8fb81ba8ded01f3b1a04edbc6550e65a435.tar.gz bcm5719-llvm-8de2b8fb81ba8ded01f3b1a04edbc6550e65a435.zip | |
[Mips] Implement emitting of R_MIPS_REL32 relocations:
1. Re-implement PLT entries and dynamic relocations emitting to keep PLT
and relocations table in a consistent state.
2. Initialize st_value and st_other fields for dynamic symbols table
entry if this entry corresponds to an external function which address is
taken in a non-PIC executable. In that case the st_value field holds an
address of the function's PLT entry. Also set STO_MIPS_PLT bit in the
st_other field.
llvm-svn: 207494
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/Mips')
7 files changed, 269 insertions, 25 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp index e2c290e27f8..b4f73ed6459 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp @@ -50,7 +50,14 @@ bool MipsLinkingContext::isDynamicRelocation(const DefinedAtom &, const Reference &r) const { if (r.kindNamespace() != Reference::KindNamespace::ELF) return false; - return r.kindValue() == llvm::ELF::R_MIPS_COPY; + assert(r.kindArch() == Reference::KindArch::Mips); + switch (r.kindValue()) { + case llvm::ELF::R_MIPS_COPY: + case llvm::ELF::R_MIPS_REL32: + return true; + default: + return false; + } } bool MipsLinkingContext::isPLTRelocation(const DefinedAtom &, diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h index 5d791a004ee..3d86a393cea 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h @@ -25,7 +25,9 @@ enum { /// \brief Setup hi 16 bits using the symbol this reference refers to. LLD_R_MIPS_HI16 = 1027, /// \brief Setup low 16 bits using the symbol this reference refers to. - LLD_R_MIPS_LO16 = 1028 + LLD_R_MIPS_LO16 = 1028, + /// \brief Represents a reference between PLT and dynamic symbol. + LLD_R_MIPS_STO_PLT = 1029 }; typedef llvm::object::ELFType<llvm::support::little, 2, false> Mips32ElELFType; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp index 7407ad58ed9..aa9f56ed78c 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -157,7 +157,9 @@ error_code MipsTargetRelocationHandler::applyRelocation( case R_MIPS_JALR: // We do not do JALR optimization now. break; + case R_MIPS_REL32: case R_MIPS_JUMP_SLOT: + case R_MIPS_COPY: // Ignore runtime relocations. break; case R_MIPS_PC32: @@ -178,6 +180,9 @@ error_code MipsTargetRelocationHandler::applyRelocation( case LLD_R_MIPS_LO16: relocLldLo16(location, targetVAddress); break; + case LLD_R_MIPS_STO_PLT: + // Do nothing. + break; default: { std::string str; llvm::raw_string_ostream s(str); diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp index 88bccf28f17..baa73fa4211 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp @@ -9,10 +9,13 @@ #include "MipsLinkingContext.h" #include "MipsRelocationPass.h" +#include "MipsTargetHandler.h" #include "Atoms.h" #include "MipsELFFile.h" +#include "llvm/ADT/DenseSet.h" + using namespace lld; using namespace lld::elf; using namespace llvm::ELF; @@ -170,6 +173,16 @@ private: /// \brief Map Atoms to their LA25 entries. llvm::DenseMap<const Atom *, LA25Atom *> _la25Map; + /// \brief Atoms referenced by static relocations. + llvm::DenseSet<const Atom *> _hasStaticRelocations; + + /// \brief Atoms require pointers equality. + llvm::DenseSet<const Atom *> _requiresPtrEquality; + + /// \brief References which are candidates for cconverting + /// to the R_MIPS_REL32 relocation. + std::vector<Reference *> _rel32Candidates; + /// \brief the list of PLT atoms. std::vector<PLTAtom *> _pltVector; @@ -185,20 +198,34 @@ private: /// \brief Handle a specific reference. void handleReference(Reference &ref); + /// \brief Collect information about the reference to use it + /// later in the handleReference() routine. + void collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom, + Reference &ref); + void handlePlain(Reference &ref); void handle26(Reference &ref); void handleGOT(Reference &ref); const GOTAtom *getLocalGOTEntry(const Reference &ref); const GOTAtom *getGlobalGOTEntry(const Atom *a); - const PLTAtom *getPLTEntry(const Atom *a); + PLTAtom *getPLTEntry(const Atom *a); const LA25Atom *getLA25Entry(const Atom *a); const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a); bool isLocal(const Atom *a) const; - bool requireLocalGOT(const Atom *a) const; + bool isLocalCall(const Atom *a) const; + bool isDynamic(const Atom *atom) const; bool requireLA25Stub(const Atom *a) const; + bool requirePLTEntry(Reference &ref); + bool requireCopy(Reference &ref); + void configurePLTReference(Reference &ref); void createPLTHeader(); + bool mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom, + const Reference &ref) const; + + static void addSingleReference(SimpleELFDefinedAtom *src, const Atom *tgt, + uint16_t relocType); }; template <typename ELFT> @@ -210,11 +237,27 @@ RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &context) template <typename ELFT> void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) { + for (const auto &atom : mf->defined()) + for (const auto &ref : *atom) + collectReferenceInfo(*cast<MipsELFDefinedAtom<ELFT>>(atom), + const_cast<Reference &>(*ref)); + // Process all references. for (const auto &atom : mf->defined()) for (const auto &ref : *atom) handleReference(const_cast<Reference &>(*ref)); + // Create R_MIPS_REL32 relocations. + for (auto *ref : _rel32Candidates) { + if (!isDynamic(ref->target())) + continue; + if (_pltMap.count(ref->target())) + continue; + ref->setKindValue(R_MIPS_REL32); + if (!isLocalCall(ref->target())) + getGlobalGOTEntry(ref->target()); + } + uint64_t ordinal = 0; for (auto &got : _localGotVector) { @@ -258,6 +301,8 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) { template <typename ELFT> void RelocationPass<ELFT>::handleReference(Reference &ref) { + if (!ref.target()) + return; if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) return; assert(ref.kindArch() == Reference::KindArch::Mips); @@ -280,6 +325,26 @@ void RelocationPass<ELFT>::handleReference(Reference &ref) { } template <typename ELFT> +void +RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom, + Reference &ref) { + if (!ref.target()) + return; + if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) + return; + if ((atom.section()->sh_flags & SHF_ALLOC) == 0) + return; + + if (mightBeDynamic(atom, ref)) + _rel32Candidates.push_back(&ref); + else + _hasStaticRelocations.insert(ref.target()); + + if (ref.kindValue() != R_MIPS_CALL16 && ref.kindValue() != R_MIPS_26) + _requiresPtrEquality.insert(ref.target()); +} + +template <typename ELFT> bool RelocationPass<ELFT>::isLocal(const Atom *a) const { if (auto *da = dyn_cast<DefinedAtom>(a)) return da->scope() == Atom::scopeTranslationUnit; @@ -287,23 +352,114 @@ bool RelocationPass<ELFT>::isLocal(const Atom *a) const { } template <typename ELFT> -void RelocationPass<ELFT>::handlePlain(Reference &ref) { - if (!ref.target()) - return; - auto sla = dyn_cast<SharedLibraryAtom>(ref.target()); - if (!sla) - return; - switch (sla->type()) { - case SharedLibraryAtom::Type::Data: - ref.setTarget(getObjectEntry(sla)); - break; - case SharedLibraryAtom::Type::Code: - ref.setTarget(getPLTEntry(sla)); - break; - default: - // Nothing to do. - break; +static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) { + auto secFlags = atom.section()->sh_flags; + auto secType = atom.section()->sh_type; + + if ((secFlags & SHF_ALLOC) == 0) + return false; + if (secType == SHT_NOBITS) + return false; + if ((secFlags & SHF_WRITE) != 0) + return false; + return true; +} + +template <typename ELFT> +bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom, + const Reference &ref) const { + auto refKind = ref.kindValue(); + + if (refKind == R_MIPS_CALL16 || refKind == R_MIPS_GOT16) + return true; + + if (refKind != R_MIPS_32) + return false; + if ((atom.section()->sh_flags & SHF_ALLOC) == 0) + return false; + + if (_context.getOutputELFType() == llvm::ELF::ET_DYN) + return true; + if (!isMipsReadonly(atom)) + return true; + if (atom.file().isPIC()) + return true; + + return false; +} + +template <typename ELFT> +bool RelocationPass<ELFT>::requirePLTEntry(Reference &ref) { + if (!_hasStaticRelocations.count(ref.target())) + return false; + const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(ref.target()); + if (sa && sa->type() != SharedLibraryAtom::Type::Code) + return false; + const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(ref.target()); + if (da && da->contentType() != DefinedAtom::typeCode) + return false; + if (isLocalCall(ref.target())) + return false; + return true; +} + +template <typename ELFT> +bool RelocationPass<ELFT>::requireCopy(Reference &ref) { + if (!_hasStaticRelocations.count(ref.target())) + return false; + const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(ref.target()); + if (sa && sa->type() != SharedLibraryAtom::Type::Data) + return false; + const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(ref.target()); + if (da && da->contentType() != DefinedAtom::typeData) + return false; + if (isLocalCall(ref.target())) + return false; + return true; +} + +template <typename ELFT> +void RelocationPass<ELFT>::configurePLTReference(Reference &ref) { + const Atom *atom = ref.target(); + + auto *plt = getPLTEntry(atom); + ref.setTarget(plt); + + if (_hasStaticRelocations.count(atom) && _requiresPtrEquality.count(atom)) + addSingleReference(plt, atom, LLD_R_MIPS_STO_PLT); +} + +template <typename ELFT> +bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const { + const auto *da = dyn_cast<const DefinedAtom>(atom); + if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways) + return true; + + const auto *sa = dyn_cast<SharedLibraryAtom>(atom); + if (sa) + return true; + + if (_context.getOutputELFType() == llvm::ELF::ET_DYN) { + if (da && da->scope() != DefinedAtom::scopeTranslationUnit) + return true; + + const auto *ua = dyn_cast<UndefinedAtom>(atom); + if (ua) + return true; } + + return false; +} + +template <typename ELFT> +void RelocationPass<ELFT>::handlePlain(Reference &ref) { + if (!isDynamic(ref.target())) + return; + + if (requirePLTEntry(ref)) + configurePLTReference(ref); + else if (requireCopy(ref)) + ref.setTarget(getObjectEntry(cast<SharedLibraryAtom>(ref.target()))); } template <typename ELFT> void RelocationPass<ELFT>::handle26(Reference &ref) { @@ -316,18 +472,18 @@ template <typename ELFT> void RelocationPass<ELFT>::handle26(Reference &ref) { const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target()); if (sla && sla->type() == SharedLibraryAtom::Type::Code) - ref.setTarget(getPLTEntry(sla)); + configurePLTReference(ref); } template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) { - if (requireLocalGOT(ref.target())) + if (isLocalCall(ref.target())) ref.setTarget(getLocalGOTEntry(ref)); else ref.setTarget(getGlobalGOTEntry(ref.target())); } template <typename ELFT> -bool RelocationPass<ELFT>::requireLocalGOT(const Atom *a) const { +bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const { Atom::Scope scope; if (auto *da = dyn_cast<DefinedAtom>(a)) scope = da->scope(); @@ -340,7 +496,7 @@ bool RelocationPass<ELFT>::requireLocalGOT(const Atom *a) const { if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit) return true; - // External symbol defined in an executable file requires a local GOT entry. + // Calls to external symbols defined in an executable file resolved locally. if (_context.getOutputELFType() == llvm::ELF::ET_EXEC) return true; @@ -433,7 +589,18 @@ template <typename ELFT> void RelocationPass<ELFT>::createPLTHeader() { } template <typename ELFT> -const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) { +void RelocationPass<ELFT>::addSingleReference(SimpleELFDefinedAtom *src, + const Atom *tgt, + uint16_t relocType) { + for (const auto &r : *src) + if (r->kindNamespace() == lld::Reference::KindNamespace::ELF && + r->kindValue() == relocType && r->target() == tgt) + break; + src->addReferenceELF_Mips(relocType, 0, tgt, 0); +} + +template <typename ELFT> +PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) { auto plt = _pltMap.find(a); if (plt != _pltMap.end()) return plt->second; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h index f64a5099466..a3fecc0da2d 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h @@ -79,6 +79,42 @@ private: llvm::DenseMap<const Atom *, std::size_t> _posMap; }; +/// \brief Handle Mips PLT section +template <class ELFType> class MipsPLTSection : public AtomSection<ELFType> { +public: + MipsPLTSection(const MipsLinkingContext &context) + : AtomSection<ELFType>(context, ".plt", DefinedAtom::typeGOT, + DefinedAtom::permR_X, + MipsTargetLayout<ELFType>::ORDER_PLT) {} + + const AtomLayout *findPLTLayout(const Atom *plt) const { + auto it = _pltLayoutMap.find(plt); + return it != _pltLayoutMap.end() ? it->second : nullptr; + } + + const lld::AtomLayout &appendAtom(const Atom *atom) override { + const auto &layout = AtomSection<ELFType>::appendAtom(atom); + + const DefinedAtom *da = cast<DefinedAtom>(atom); + + for (const auto &r : *da) { + if (r->kindNamespace() != lld::Reference::KindNamespace::ELF) + continue; + assert(r->kindArch() == Reference::KindArch::Mips); + if (r->kindValue() == LLD_R_MIPS_STO_PLT) { + _pltLayoutMap[r->target()] = &layout; + break; + } + } + + return layout; + } + +private: + /// \brief Map PLT Atoms to their layouts. + std::unordered_map<const Atom *, const AtomLayout *> _pltLayoutMap; +}; + } // elf } // lld diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp index 0e6c9918e9f..3a6dbbc88d3 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp @@ -49,6 +49,7 @@ void MipsTargetHandler::registerRelocationNames(Registry ®istry) { const Registry::KindStrings MipsTargetHandler::kindStrings[] = { LLD_KIND_STRING_ENTRY(R_MIPS_NONE), LLD_KIND_STRING_ENTRY(R_MIPS_32), + LLD_KIND_STRING_ENTRY(R_MIPS_REL32), LLD_KIND_STRING_ENTRY(R_MIPS_26), LLD_KIND_STRING_ENTRY(R_MIPS_HI16), LLD_KIND_STRING_ENTRY(R_MIPS_LO16), @@ -63,5 +64,6 @@ const Registry::KindStrings MipsTargetHandler::kindStrings[] = { LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26), LLD_KIND_STRING_ENTRY(LLD_R_MIPS_HI16), LLD_KIND_STRING_ENTRY(LLD_R_MIPS_LO16), + LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT), LLD_KIND_STRING_END }; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h index 010072f8f39..1e8253aebea 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -26,9 +26,11 @@ public: MipsTargetLayout(const MipsLinkingContext &ctx) : TargetLayout<ELFType>(ctx), _gotSection(new (_alloc) MipsGOTSection<ELFType>(ctx)), + _pltSection(new (_alloc) MipsPLTSection<ELFType>(ctx)), _cachedGP(false) {} const MipsGOTSection<ELFType> &getGOTSection() const { return *_gotSection; } + const MipsPLTSection<ELFType> &getPLTSection() const { return *_pltSection; } AtomSection<ELFType> * createSection(StringRef name, int32_t type, @@ -36,6 +38,8 @@ public: Layout::SectionOrder order) override { if (type == DefinedAtom::typeGOT && name == ".got") return _gotSection; + if (type == DefinedAtom::typeStub && name == ".plt") + return _pltSection; return DefaultLayout<ELFType>::createSection(name, type, permissions, order); } @@ -56,6 +60,7 @@ public: private: llvm::BumpPtrAllocator _alloc; MipsGOTSection<ELFType> *_gotSection; + MipsPLTSection<ELFType> *_pltSection; AtomLayout *_gp; bool _cachedGP; }; @@ -119,6 +124,26 @@ public: }); } + void finalize() override { + const auto &pltSection = _targetLayout.getPLTSection(); + + // Under some conditions a dynamic symbol table record should hold a symbol + // value of the corresponding PLT entry. For details look at the PLT entry + // creation code in the class MipsRelocationPass. Let's update atomLayout + // fields for such symbols. + for (auto &ste : this->_symbolTable) { + if (!ste._atom || ste._atomLayout) + continue; + auto *layout = pltSection.findPLTLayout(ste._atom); + if (layout) { + ste._symbol.st_value = layout->_virtualAddr; + ste._symbol.st_other |= ELF::STO_MIPS_PLT; + } + } + + DynamicSymbolTable<Mips32ElELFType>::finalize(); + } + private: MipsTargetLayout<ELFT> &_targetLayout; }; |

