//===- 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_MIPS_TARGET_HANDLER_H #define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H #include "DefaultTargetHandler.h" #include "MipsDynamicLibraryWriter.h" #include "MipsELFReader.h" #include "MipsExecutableWriter.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(MipsLinkingContext &ctx) : TargetLayout(ctx), _gotSection(new (this->_allocator) MipsGOTSection(ctx)), _pltSection(new (this->_allocator) 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); } /// \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; } /// \brief Return the section order for a input section Layout::SectionOrder getSectionOrder(StringRef name, int32_t contentType, int32_t contentPermissions) override { if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text"))) return DefaultLayout::ORDER_TEXT; return DefaultLayout::getSectionOrder(name, contentType, contentPermissions); } protected: unique_bump_ptr> createRelocationTable(StringRef name, int32_t order) override { return unique_bump_ptr>( new (this->_allocator) MipsRelocationTable(this->_context, name, order)); } private: MipsGOTSection *_gotSection; MipsPLTSection *_pltSection; llvm::Optional _gpAtom; llvm::Optional _gpDispAtom; }; /// \brief Mips Runtime file. template class MipsRuntimeFile final : public RuntimeFile { public: MipsRuntimeFile(MipsLinkingContext &ctx) : RuntimeFile(ctx, "Mips runtime file") {} }; /// \brief Auxiliary class holds relocation's names table. class MipsRelocationStringTable { static const Registry::KindStrings kindStrings[]; public: static void registerTable(Registry ®istry); }; /// \brief TargetHandler for Mips template class MipsTargetHandler final : public DefaultTargetHandler { public: MipsTargetHandler(MipsLinkingContext &ctx) : _ctx(ctx), _runtimeFile(new MipsRuntimeFile(ctx)), _targetLayout(new MipsTargetLayout(ctx)), _relocationHandler(createMipsRelocationHandler(ctx)) {} MipsTargetLayout &getTargetLayout() override { return *_targetLayout; } std::unique_ptr getObjReader() override { return std::unique_ptr(new MipsELFObjectReader(_ctx)); } std::unique_ptr getDSOReader() override { return std::unique_ptr(new MipsELFDSOReader(_ctx)); } const TargetRelocationHandler &getRelocationHandler() const override { return *_relocationHandler; } std::unique_ptr getWriter() override { switch (_ctx.getOutputELFType()) { case llvm::ELF::ET_EXEC: return std::unique_ptr( new MipsExecutableWriter(_ctx, *_targetLayout)); case llvm::ELF::ET_DYN: return std::unique_ptr( new MipsDynamicLibraryWriter(_ctx, *_targetLayout)); case llvm::ELF::ET_REL: llvm_unreachable("TODO: support -r mode"); default: llvm_unreachable("unsupported output type"); } } void registerRelocationNames(Registry ®istry) override { MipsRelocationStringTable::registerTable(registry); } private: MipsLinkingContext &_ctx; std::unique_ptr> _runtimeFile; std::unique_ptr> _targetLayout; std::unique_ptr _relocationHandler; }; template class MipsSymbolTable : public SymbolTable { public: typedef llvm::object::Elf_Sym_Impl Elf_Sym; MipsSymbolTable(const ELFLinkingContext &ctx) : SymbolTable(ctx, ".symtab", DefaultLayout::ORDER_SYMBOL_TABLE) {} void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, int64_t addr) override { SymbolTable::addDefinedAtom(sym, da, addr); switch (da->codeModel()) { case DefinedAtom::codeMipsMicro: sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS; break; case DefinedAtom::codeMipsMicroPIC: sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC; break; default: break; } } void finalize(bool sort) override { SymbolTable::finalize(sort); for (auto &ste : this->_symbolTable) { if (!ste._atom) continue; if (const auto *da = dyn_cast(ste._atom)) { if (da->codeModel() == DefinedAtom::codeMipsMicro || da->codeModel() == DefinedAtom::codeMipsMicroPIC) { // Adjust dynamic microMIPS symbol value. That allows a dynamic // linker to recognize and handle this symbol correctly. ste._symbol.st_value = ste._symbol.st_value | 1; } } } } }; template class MipsDynamicSymbolTable : public DynamicSymbolTable { public: MipsDynamicSymbolTable(const ELFLinkingContext &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 { DynamicSymbolTable::finalize(); const auto &pltSection = _targetLayout.getPLTSection(); for (auto &ste : this->_symbolTable) { const Atom *a = ste._atom; if (!a) continue; if (auto *layout = pltSection.findPLTLayout(a)) { a = layout->_atom; // 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. assert(!ste._atomLayout); ste._symbol.st_value = layout->_virtualAddr; ste._symbol.st_other |= ELF::STO_MIPS_PLT; } if (const auto *da = dyn_cast(a)) { if (da->codeModel() == DefinedAtom::codeMipsMicro || da->codeModel() == DefinedAtom::codeMipsMicroPIC) { // Adjust dynamic microMIPS symbol value. That allows a dynamic // linker to recognize and handle this symbol correctly. ste._symbol.st_value = ste._symbol.st_value | 1; } } } } private: MipsTargetLayout &_targetLayout; }; } // end namespace elf } // end namespace lld #endif