summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h')
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h257
1 files changed, 257 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
new file mode 100644
index 000000000000..79509addf40b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
@@ -0,0 +1,257 @@
+//===- 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 ELFT> class MipsTargetLayout final : public TargetLayout<ELFT> {
+public:
+ MipsTargetLayout(MipsLinkingContext &ctx)
+ : TargetLayout<ELFT>(ctx),
+ _gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)),
+ _pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {}
+
+ const MipsGOTSection<ELFT> &getGOTSection() const { return *_gotSection; }
+ const MipsPLTSection<ELFT> &getPLTSection() const { return *_pltSection; }
+
+ AtomSection<ELFT> *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<ELFT>::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<ELFT>::ORDER_TEXT;
+
+ return DefaultLayout<ELFT>::getSectionOrder(name, contentType,
+ contentPermissions);
+ }
+
+protected:
+ unique_bump_ptr<RelocationTable<ELFT>>
+ createRelocationTable(StringRef name, int32_t order) override {
+ return unique_bump_ptr<RelocationTable<ELFT>>(
+ new (this->_allocator)
+ MipsRelocationTable<ELFT>(this->_context, name, order));
+ }
+
+private:
+ MipsGOTSection<ELFT> *_gotSection;
+ MipsPLTSection<ELFT> *_pltSection;
+ llvm::Optional<AtomLayout *> _gpAtom;
+ llvm::Optional<AtomLayout *> _gpDispAtom;
+};
+
+/// \brief Mips Runtime file.
+template <class ELFT> class MipsRuntimeFile final : public RuntimeFile<ELFT> {
+public:
+ MipsRuntimeFile(MipsLinkingContext &ctx)
+ : RuntimeFile<ELFT>(ctx, "Mips runtime file") {}
+};
+
+/// \brief Auxiliary class holds relocation's names table.
+class MipsRelocationStringTable {
+ static const Registry::KindStrings kindStrings[];
+
+public:
+ static void registerTable(Registry &registry);
+};
+
+/// \brief TargetHandler for Mips
+template <class ELFT>
+class MipsTargetHandler final : public DefaultTargetHandler<ELFT> {
+public:
+ MipsTargetHandler(MipsLinkingContext &ctx)
+ : _ctx(ctx), _runtimeFile(new MipsRuntimeFile<ELFT>(ctx)),
+ _targetLayout(new MipsTargetLayout<ELFT>(ctx)),
+ _relocationHandler(createMipsRelocationHandler<ELFT>(ctx)) {}
+
+ MipsTargetLayout<ELFT> &getTargetLayout() override { return *_targetLayout; }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new MipsELFObjectReader<ELFT>(_ctx));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new MipsELFDSOReader<ELFT>(_ctx));
+ }
+
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
+ }
+
+ std::unique_ptr<Writer> getWriter() override {
+ switch (_ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new MipsExecutableWriter<ELFT>(_ctx, *_targetLayout));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new MipsDynamicLibraryWriter<ELFT>(_ctx, *_targetLayout));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+ }
+
+ void registerRelocationNames(Registry &registry) override {
+ MipsRelocationStringTable::registerTable(registry);
+ }
+
+private:
+ MipsLinkingContext &_ctx;
+ std::unique_ptr<MipsRuntimeFile<ELFT>> _runtimeFile;
+ std::unique_ptr<MipsTargetLayout<ELFT>> _targetLayout;
+ std::unique_ptr<TargetRelocationHandler> _relocationHandler;
+};
+
+template <class ELFT> class MipsSymbolTable : public SymbolTable<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ MipsSymbolTable(const ELFLinkingContext &ctx)
+ : SymbolTable<ELFT>(ctx, ".symtab",
+ DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+
+ void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) override {
+ SymbolTable<ELFT>::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<ELFT>::finalize(sort);
+
+ for (auto &ste : this->_symbolTable) {
+ if (!ste._atom)
+ continue;
+ if (const auto *da = dyn_cast<DefinedAtom>(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 ELFT>
+class MipsDynamicSymbolTable : public DynamicSymbolTable<ELFT> {
+public:
+ MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
+ MipsTargetLayout<ELFT> &layout)
+ : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
+ DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
+ _targetLayout(layout) {}
+
+ void sortSymbols() override {
+ typedef typename DynamicSymbolTable<ELFT>::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<ELFT>::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<DefinedAtom>(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<ELFT> &_targetLayout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif