//===- 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 "MipsELFReader.h" #include "MipsLinkingContext.h" #include "MipsRelocationHandler.h" #include "MipsSectionChunks.h" #include "TargetLayout.h" #include "llvm/ADT/DenseSet.h" namespace lld { namespace elf { /// \brief TargetLayout for Mips template class MipsTargetLayout final : public TargetLayout { public: MipsTargetLayout(const MipsLinkingContext &ctx) : TargetLayout(ctx), _gotSection(new (_alloc) MipsGOTSection(ctx)), _pltSection(new (_alloc) MipsPLTSection(ctx)) {} const MipsGOTSection &getGOTSection() const { return *_gotSection; } const MipsPLTSection &getPLTSection() const { return *_pltSection; } AtomSection * createSection(StringRef name, int32_t type, DefinedAtom::ContentPermissions permissions, Layout::SectionOrder order) override { if (type == DefinedAtom::typeGOT && name == ".got") return _gotSection; if (type == DefinedAtom::typeStub && name == ".plt") return _pltSection; return DefaultLayout::createSection(name, type, permissions, order); } StringRef getSectionName(const DefinedAtom *da) const override { return llvm::StringSwitch(da->customSectionName()) .StartsWith(".ctors", ".ctors") .StartsWith(".dtors", ".dtors") .Default(TargetLayout::getSectionName(da)); } Layout::SegmentType getSegmentType(Section *section) const override { switch (section->order()) { case DefaultLayout::ORDER_CTORS: case DefaultLayout::ORDER_DTORS: return llvm::ELF::PT_LOAD; default: return TargetLayout::getSegmentType(section); } } ErrorOr addAtom(const Atom *atom) override { // Maintain: // 1. Set of shared library atoms referenced by regular defined atoms. // 2. Set of shared library atoms have corresponding R_MIPS_COPY copies. if (const auto *da = dyn_cast(atom)) for (const Reference *ref : *da) { if (ref->kindNamespace() == lld::Reference::KindNamespace::ELF) { assert(ref->kindArch() == Reference::KindArch::Mips); if (ref->kindValue() == llvm::ELF::R_MIPS_COPY) _copiedDynSymNames.insert(atom->name()); } } return TargetLayout::addAtom(atom); } bool isCopied(const SharedLibraryAtom *sla) const { return _copiedDynSymNames.count(sla->name()); } /// \brief GP offset relative to .got section. uint64_t getGPOffset() const { return 0x7FF0; } /// \brief Get '_gp' symbol atom layout. AtomLayout *getGP() { if (!_gpAtom.hasValue()) { auto atom = this->findAbsoluteAtom("_gp"); _gpAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr; } return *_gpAtom; } /// \brief Get '_gp_disp' symbol atom layout. AtomLayout *getGPDisp() { if (!_gpDispAtom.hasValue()) { auto atom = this->findAbsoluteAtom("_gp_disp"); _gpDispAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr; } return *_gpDispAtom; } private: llvm::BumpPtrAllocator _alloc; MipsGOTSection *_gotSection; MipsPLTSection *_pltSection; llvm::Optional _gpAtom; llvm::Optional _gpDispAtom; llvm::StringSet<> _copiedDynSymNames; }; /// \brief Mips Runtime file. template class MipsRuntimeFile final : public CRuntimeFile { public: MipsRuntimeFile(const MipsLinkingContext &ctx) : CRuntimeFile(ctx, "Mips runtime file") {} }; /// \brief TargetHandler for Mips class MipsTargetHandler final : public DefaultTargetHandler { public: MipsTargetHandler(MipsLinkingContext &ctx); MipsTargetLayout &getTargetLayout() override { return *_targetLayout; } std::unique_ptr getObjReader(bool atomizeStrings) override { return std::unique_ptr(new MipsELFObjectReader(atomizeStrings)); } const MipsTargetRelocationHandler &getRelocationHandler() const override { return *_relocationHandler; } std::unique_ptr getWriter() override; void registerRelocationNames(Registry ®istry) override; private: static const Registry::KindStrings kindStrings[]; MipsLinkingContext &_ctx; std::unique_ptr> _runtimeFile; std::unique_ptr> _targetLayout; std::unique_ptr _relocationHandler; }; template class MipsDynamicSymbolTable : public DynamicSymbolTable { public: MipsDynamicSymbolTable(const MipsLinkingContext &ctx, MipsTargetLayout &layout) : DynamicSymbolTable(ctx, layout, ".dynsym", DefaultLayout::ORDER_DYNAMIC_SYMBOLS), _targetLayout(layout) {} void sortSymbols() override { typedef typename DynamicSymbolTable::SymbolEntry SymbolEntry; std::stable_sort(this->_symbolTable.begin(), this->_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 _targetLayout.getGOTSection().compare(A._atom, B._atom); }); } 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::finalize(); } private: MipsTargetLayout &_targetLayout; }; } // end namespace elf } // end namespace lld #endif