//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler32EL.cpp ----------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ELFReader.h" #include "MipsELFFile.h" #include "MipsELFWriters.h" #include "MipsTargetHandler.h" namespace lld { namespace elf { template MipsTargetHandler::MipsTargetHandler(MipsLinkingContext &ctx) : _ctx(ctx), _targetLayout(new MipsTargetLayout(ctx, _abiInfoHandler)), _relocationHandler( createMipsRelocationHandler(ctx, *_targetLayout)) {} template std::unique_ptr MipsTargetHandler::getObjReader() { return llvm::make_unique>>(_ctx); } template std::unique_ptr MipsTargetHandler::getDSOReader() { return llvm::make_unique>>(_ctx); } template const TargetRelocationHandler & MipsTargetHandler::getRelocationHandler() const { return *_relocationHandler; } template std::unique_ptr MipsTargetHandler::getWriter() { switch (_ctx.getOutputELFType()) { case llvm::ELF::ET_EXEC: return llvm::make_unique>(_ctx, *_targetLayout, _abiInfoHandler); case llvm::ELF::ET_DYN: return llvm::make_unique>( _ctx, *_targetLayout, _abiInfoHandler); case llvm::ELF::ET_REL: llvm_unreachable("TODO: support -r mode"); default: llvm_unreachable("unsupported output type"); } } template MipsAbi MipsTargetHandler::getAbi() const { return _abiInfoHandler.getAbi(); } template class MipsTargetHandler; template class MipsTargetHandler; template class MipsTargetHandler; template class MipsTargetHandler; template MipsSymbolTable::MipsSymbolTable(const ELFLinkingContext &ctx) : SymbolTable(ctx, ".symtab", TargetLayout::ORDER_SYMBOL_TABLE) {} template void MipsSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, int64_t addr) { 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; } } template void MipsSymbolTable::finalize(bool sort) { 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 MipsSymbolTable; template class MipsSymbolTable; template class MipsSymbolTable; template class MipsSymbolTable; template MipsDynamicSymbolTable::MipsDynamicSymbolTable( const ELFLinkingContext &ctx, MipsTargetLayout &layout) : DynamicSymbolTable(ctx, layout, ".dynsym", TargetLayout::ORDER_DYNAMIC_SYMBOLS), _targetLayout(layout) {} template void MipsDynamicSymbolTable::sortSymbols() { 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); }); } template void MipsDynamicSymbolTable::finalize() { 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; } } } } template class MipsDynamicSymbolTable; template class MipsDynamicSymbolTable; template class MipsDynamicSymbolTable; template class MipsDynamicSymbolTable; } }