//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp -----------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MipsDynamicTable.h" #include "MipsELFWriters.h" #include "MipsLinkingContext.h" #include "MipsTargetHandler.h" #include "MipsTargetLayout.h" namespace { class MipsDynamicAtom : public lld::elf::DynamicAtom { public: MipsDynamicAtom(const lld::File &f) : DynamicAtom(f) {} ContentPermissions permissions() const override { return permR__; } }; } namespace lld { namespace elf { template MipsELFWriter::MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout &targetLayout, const MipsAbiInfoHandler &abiInfo) : _ctx(ctx), _targetLayout(targetLayout), _abiInfo(abiInfo) {} template void MipsELFWriter::setELFHeader(ELFHeader &elfHeader) { elfHeader.e_version(1); elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT); elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE); unsigned char abiVer = 0; if (_ctx.getOutputELFType() == ET_EXEC && _abiInfo.isCPicOnly()) abiVer = 1; if (_abiInfo.isFp64()) abiVer = 3; elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, abiVer); elfHeader.e_flags(_abiInfo.getFlags()); } template void MipsELFWriter::finalizeMipsRuntimeAtomValues() { auto gotSection = _targetLayout.findOutputSection(".got"); auto got = gotSection ? gotSection->virtualAddr() : 0; auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0; setAtomValue("_gp", gp); setAtomValue("_gp_disp", gp); setAtomValue("__gnu_local_gp", gp); if (_ctx.isDynamic() && _ctx.getOutputELFType() == ET_EXEC) setAtomValue("_DYNAMIC_LINKING", 1); } template std::unique_ptr> MipsELFWriter::createRuntimeFile() { auto file = llvm::make_unique>(_ctx, "Mips runtime file"); file->addAbsoluteAtom("_gp"); file->addAbsoluteAtom("_gp_disp"); file->addAbsoluteAtom("__gnu_local_gp"); if (_ctx.isDynamic()) { file->addAtom(*new (file->allocator()) MipsDynamicAtom(*file)); if (_ctx.getOutputELFType() == ET_EXEC) file->addAbsoluteAtom("_DYNAMIC_LINKING"); } return file; } template unique_bump_ptr> MipsELFWriter::createOptionsSection(llvm::BumpPtrAllocator &alloc) { typedef unique_bump_ptr> Ptr; const auto ®Mask = _abiInfo.getRegistersMask(); if (!regMask.hasValue()) return Ptr(); return ELFT::Is64Bits ? Ptr(new (alloc) MipsOptionsSection(_ctx, _targetLayout, *regMask)) : Ptr(new (alloc) MipsReginfoSection(_ctx, _targetLayout, *regMask)); } template unique_bump_ptr> MipsELFWriter::createAbiFlagsSection(llvm::BumpPtrAllocator &alloc) { typedef unique_bump_ptr> Ptr; const auto &abi = _abiInfo.getAbiFlags(); if (!abi.hasValue()) return Ptr(); return Ptr(new (alloc) MipsAbiFlagsSection(_ctx, _targetLayout, *abi)); } template void MipsELFWriter::setAtomValue(StringRef name, uint64_t value) { AtomLayout *atom = _targetLayout.findAbsoluteAtom(name); assert(atom); atom->_virtualAddr = value; } template MipsDynamicLibraryWriter::MipsDynamicLibraryWriter( MipsLinkingContext &ctx, MipsTargetLayout &layout, const MipsAbiInfoHandler &abiInfo) : DynamicLibraryWriter(ctx, layout), _writeHelper(ctx, layout, abiInfo), _targetLayout(layout) {} template void MipsDynamicLibraryWriter::createImplicitFiles( std::vector> &result) { DynamicLibraryWriter::createImplicitFiles(result); result.push_back(_writeHelper.createRuntimeFile()); } template void MipsDynamicLibraryWriter::finalizeDefaultAtomValues() { DynamicLibraryWriter::finalizeDefaultAtomValues(); _writeHelper.finalizeMipsRuntimeAtomValues(); } template void MipsDynamicLibraryWriter::createDefaultSections() { DynamicLibraryWriter::createDefaultSections(); _reginfo = _writeHelper.createOptionsSection(this->_alloc); if (_reginfo) this->_layout.addSection(_reginfo.get()); _abiFlags = _writeHelper.createAbiFlagsSection(this->_alloc); if (_abiFlags) this->_layout.addSection(_abiFlags.get()); } template std::error_code MipsDynamicLibraryWriter::setELFHeader() { DynamicLibraryWriter::setELFHeader(); _writeHelper.setELFHeader(*this->_elfHeader); return std::error_code(); } template unique_bump_ptr> MipsDynamicLibraryWriter::createSymbolTable() { return unique_bump_ptr>( new (this->_alloc) MipsSymbolTable(this->_ctx)); } template unique_bump_ptr> MipsDynamicLibraryWriter::createDynamicTable() { return unique_bump_ptr>( new (this->_alloc) MipsDynamicTable(this->_ctx, _targetLayout)); } template unique_bump_ptr> MipsDynamicLibraryWriter::createDynamicSymbolTable() { return unique_bump_ptr>(new ( this->_alloc) MipsDynamicSymbolTable(this->_ctx, _targetLayout)); } template class MipsDynamicLibraryWriter; template class MipsDynamicLibraryWriter; template class MipsDynamicLibraryWriter; template class MipsDynamicLibraryWriter; template MipsExecutableWriter::MipsExecutableWriter( MipsLinkingContext &ctx, MipsTargetLayout &layout, const MipsAbiInfoHandler &abiInfo) : ExecutableWriter(ctx, layout), _writeHelper(ctx, layout, abiInfo), _targetLayout(layout) {} template std::error_code MipsExecutableWriter::setELFHeader() { std::error_code ec = ExecutableWriter::setELFHeader(); if (ec) return ec; StringRef entryName = this->_ctx.entrySymbolName(); if (const AtomLayout *al = this->_layout.findAtomLayoutByName(entryName)) { const auto *ea = cast(al->_atom); if (ea->codeModel() == DefinedAtom::codeMipsMicro || ea->codeModel() == DefinedAtom::codeMipsMicroPIC) // Adjust entry symbol value if this symbol is microMIPS encoded. this->_elfHeader->e_entry(al->_virtualAddr | 1); } _writeHelper.setELFHeader(*this->_elfHeader); return std::error_code(); } template void MipsExecutableWriter::buildDynamicSymbolTable(const File &file) { // MIPS ABI requires to add to dynsym even undefined symbols // if they have a corresponding entries in a global part of GOT. for (auto sec : this->_layout.sections()) if (auto section = dyn_cast>(sec)) for (const auto &atom : section->atoms()) { if (_targetLayout.getGOTSection().hasGlobalGOTEntry(atom->_atom)) { this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr, atom); continue; } const DefinedAtom *da = dyn_cast(atom->_atom); if (!da) continue; if (da->dynamicExport() != DefinedAtom::dynamicExportAlways && !this->_ctx.isDynamicallyExportedSymbol(da->name()) && !(this->_ctx.shouldExportDynamic() && da->scope() == Atom::Scope::scopeGlobal)) continue; this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr, atom); } for (const UndefinedAtom *a : file.undefined()) // FIXME (simon): Consider to move this check to the // MipsELFUndefinedAtom class method. That allows to // handle more complex coditions in the future. if (_targetLayout.getGOTSection().hasGlobalGOTEntry(a)) this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF); // Skip our immediate parent class method // ExecutableWriter::buildDynamicSymbolTable because we replaced it // with our own version. Call OutputELFWriter directly. OutputELFWriter::buildDynamicSymbolTable(file); } template void MipsExecutableWriter::createImplicitFiles( std::vector> &result) { ExecutableWriter::createImplicitFiles(result); result.push_back(_writeHelper.createRuntimeFile()); } template void MipsExecutableWriter::finalizeDefaultAtomValues() { // Finalize the atom values that are part of the parent. ExecutableWriter::finalizeDefaultAtomValues(); _writeHelper.finalizeMipsRuntimeAtomValues(); } template void MipsExecutableWriter::createDefaultSections() { ExecutableWriter::createDefaultSections(); _reginfo = _writeHelper.createOptionsSection(this->_alloc); if (_reginfo) this->_layout.addSection(_reginfo.get()); _abiFlags = _writeHelper.createAbiFlagsSection(this->_alloc); if (_abiFlags) this->_layout.addSection(_abiFlags.get()); } template unique_bump_ptr> MipsExecutableWriter::createSymbolTable() { return unique_bump_ptr>( new (this->_alloc) MipsSymbolTable(this->_ctx)); } /// \brief create dynamic table template unique_bump_ptr> MipsExecutableWriter::createDynamicTable() { return unique_bump_ptr>( new (this->_alloc) MipsDynamicTable(this->_ctx, _targetLayout)); } /// \brief create dynamic symbol table template unique_bump_ptr> MipsExecutableWriter::createDynamicSymbolTable() { return unique_bump_ptr>(new ( this->_alloc) MipsDynamicSymbolTable(this->_ctx, _targetLayout)); } template class MipsExecutableWriter; template class MipsExecutableWriter; template class MipsExecutableWriter; template class MipsExecutableWriter; } // elf } // lld