//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp -------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Atoms.h" #include "MipsCtorsOrderPass.h" #include "MipsLinkingContext.h" #include "MipsRelocationPass.h" #include "MipsTargetHandler.h" using namespace lld; using namespace lld::elf; std::unique_ptr elf::createMipsLinkingContext(llvm::Triple triple) { if (triple.getArch() == llvm::Triple::mips || triple.getArch() == llvm::Triple::mipsel || triple.getArch() == llvm::Triple::mips64 || triple.getArch() == llvm::Triple::mips64el) return llvm::make_unique(triple); return nullptr; } static std::unique_ptr createTarget(llvm::Triple triple, MipsLinkingContext &ctx) { switch (triple.getArch()) { case llvm::Triple::mips: return llvm::make_unique>(ctx); case llvm::Triple::mipsel: return llvm::make_unique>(ctx); case llvm::Triple::mips64: return llvm::make_unique>(ctx); case llvm::Triple::mips64el: return llvm::make_unique>(ctx); default: llvm_unreachable("Unhandled arch"); } } MipsLinkingContext::MipsLinkingContext(llvm::Triple triple) : ELFLinkingContext(triple, createTarget(triple, *this)) {} uint64_t MipsLinkingContext::getBaseAddress() const { if (_baseAddress != 0 || getOutputELFType() != llvm::ELF::ET_EXEC) return _baseAddress; switch (getAbi()) { case MipsAbi::O32: return 0x0400000; case MipsAbi::N32: return 0x10000000; case MipsAbi::N64: return 0x120000000; } } StringRef MipsLinkingContext::entrySymbolName() const { if (_outputELFType == elf::ET_EXEC && _entrySymbolName.empty()) return "__start"; return _entrySymbolName; } StringRef MipsLinkingContext::getDefaultInterpreter() const { switch (getAbi()) { case MipsAbi::O32: return "/lib/ld.so.1"; case MipsAbi::N32: return "/lib32/ld.so.1"; case MipsAbi::N64: return "/lib64/ld.so.1"; } } void MipsLinkingContext::addPasses(PassManager &pm) { auto pass = createMipsRelocationPass(*this); if (pass) pm.add(std::move(pass)); ELFLinkingContext::addPasses(pm); pm.add(llvm::make_unique()); } bool MipsLinkingContext::isDynamicRelocation(const Reference &r) const { if (r.kindNamespace() != Reference::KindNamespace::ELF) return false; assert(r.kindArch() == Reference::KindArch::Mips); switch (r.kindValue()) { case llvm::ELF::R_MIPS_COPY: case llvm::ELF::R_MIPS_REL32: return true; case llvm::ELF::R_MIPS_TLS_DTPMOD32: case llvm::ELF::R_MIPS_TLS_DTPREL32: case llvm::ELF::R_MIPS_TLS_TPREL32: case llvm::ELF::R_MIPS_TLS_DTPMOD64: case llvm::ELF::R_MIPS_TLS_DTPREL64: case llvm::ELF::R_MIPS_TLS_TPREL64: return isDynamic(); default: return false; } } bool MipsLinkingContext::isCopyRelocation(const Reference &r) const { if (r.kindNamespace() != Reference::KindNamespace::ELF) return false; assert(r.kindArch() == Reference::KindArch::Mips); if (r.kindValue() == llvm::ELF::R_MIPS_COPY) return true; return false; } bool MipsLinkingContext::isPLTRelocation(const Reference &r) const { if (r.kindNamespace() != Reference::KindNamespace::ELF) return false; assert(r.kindArch() == Reference::KindArch::Mips); switch (r.kindValue()) { case llvm::ELF::R_MIPS_JUMP_SLOT: return true; default: return false; } } bool MipsLinkingContext::isRelativeReloc(const Reference &r) const { if (r.kindNamespace() != Reference::KindNamespace::ELF) return false; assert(r.kindArch() == Reference::KindArch::Mips); switch (r.kindValue()) { case llvm::ELF::R_MIPS_REL32: case llvm::ELF::R_MIPS_GPREL16: case llvm::ELF::R_MIPS_GPREL32: return true; default: return false; } } MipsAbi MipsLinkingContext::getAbi() const { auto &handler = static_cast(getTargetHandler()); return handler.getAbi(); } const Registry::KindStrings kindStrings[] = { #define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), #include "llvm/Support/ELFRelocs/Mips.def" #undef ELF_RELOC LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT), LLD_KIND_STRING_ENTRY(LLD_R_MIPS_32_HI16), LLD_KIND_STRING_ENTRY(LLD_R_MIPS_64_HI16), LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26), LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT), LLD_KIND_STRING_ENTRY(LLD_R_MICROMIPS_GLOBAL_26_S1), LLD_KIND_STRING_END }; void MipsLinkingContext::registerRelocationNames(Registry ®istry) { registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::Mips, kindStrings); }