| //===- 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 <class ELFT> |
| MipsELFWriter<ELFT>::MipsELFWriter(MipsLinkingContext &ctx, |
| MipsTargetLayout<ELFT> &targetLayout, |
| const MipsAbiInfoHandler<ELFT> &abiInfo) |
| : _ctx(ctx), _targetLayout(targetLayout), _abiInfo(abiInfo) {} |
| |
| template <class ELFT> |
| void MipsELFWriter<ELFT>::setELFHeader(ELFHeader<ELFT> &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 <class ELFT> |
| void MipsELFWriter<ELFT>::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 <class ELFT> |
| std::unique_ptr<RuntimeFile<ELFT>> MipsELFWriter<ELFT>::createRuntimeFile() { |
| auto file = llvm::make_unique<RuntimeFile<ELFT>>(_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 <class ELFT> |
| unique_bump_ptr<Section<ELFT>> |
| MipsELFWriter<ELFT>::createOptionsSection(llvm::BumpPtrAllocator &alloc) { |
| typedef unique_bump_ptr<Section<ELFT>> Ptr; |
| const auto ®Mask = _abiInfo.getRegistersMask(); |
| if (!regMask.hasValue()) |
| return Ptr(); |
| return ELFT::Is64Bits |
| ? Ptr(new (alloc) |
| MipsOptionsSection<ELFT>(_ctx, _targetLayout, *regMask)) |
| : Ptr(new (alloc) |
| MipsReginfoSection<ELFT>(_ctx, _targetLayout, *regMask)); |
| } |
| |
| template <class ELFT> |
| unique_bump_ptr<Section<ELFT>> |
| MipsELFWriter<ELFT>::createAbiFlagsSection(llvm::BumpPtrAllocator &alloc) { |
| typedef unique_bump_ptr<Section<ELFT>> Ptr; |
| const auto &abi = _abiInfo.getAbiFlags(); |
| if (!abi.hasValue()) |
| return Ptr(); |
| return Ptr(new (alloc) MipsAbiFlagsSection<ELFT>(_ctx, _targetLayout, *abi)); |
| } |
| |
| template <class ELFT> |
| void MipsELFWriter<ELFT>::setAtomValue(StringRef name, uint64_t value) { |
| AtomLayout *atom = _targetLayout.findAbsoluteAtom(name); |
| assert(atom); |
| atom->_virtualAddr = value; |
| } |
| |
| template <class ELFT> |
| MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter( |
| MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout, |
| const MipsAbiInfoHandler<ELFT> &abiInfo) |
| : DynamicLibraryWriter<ELFT>(ctx, layout), |
| _writeHelper(ctx, layout, abiInfo), _targetLayout(layout) {} |
| |
| template <class ELFT> |
| void MipsDynamicLibraryWriter<ELFT>::createImplicitFiles( |
| std::vector<std::unique_ptr<File>> &result) { |
| DynamicLibraryWriter<ELFT>::createImplicitFiles(result); |
| result.push_back(_writeHelper.createRuntimeFile()); |
| } |
| |
| template <class ELFT> |
| void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() { |
| DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues(); |
| _writeHelper.finalizeMipsRuntimeAtomValues(); |
| } |
| |
| template <class ELFT> |
| void MipsDynamicLibraryWriter<ELFT>::createDefaultSections() { |
| DynamicLibraryWriter<ELFT>::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 <class ELFT> |
| std::error_code MipsDynamicLibraryWriter<ELFT>::setELFHeader() { |
| DynamicLibraryWriter<ELFT>::setELFHeader(); |
| _writeHelper.setELFHeader(*this->_elfHeader); |
| return std::error_code(); |
| } |
| |
| template <class ELFT> |
| unique_bump_ptr<SymbolTable<ELFT>> |
| MipsDynamicLibraryWriter<ELFT>::createSymbolTable() { |
| return unique_bump_ptr<SymbolTable<ELFT>>( |
| new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx)); |
| } |
| |
| template <class ELFT> |
| unique_bump_ptr<DynamicTable<ELFT>> |
| MipsDynamicLibraryWriter<ELFT>::createDynamicTable() { |
| return unique_bump_ptr<DynamicTable<ELFT>>( |
| new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout)); |
| } |
| |
| template <class ELFT> |
| unique_bump_ptr<DynamicSymbolTable<ELFT>> |
| MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() { |
| return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new ( |
| this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout)); |
| } |
| |
| template class MipsDynamicLibraryWriter<ELF32BE>; |
| template class MipsDynamicLibraryWriter<ELF32LE>; |
| template class MipsDynamicLibraryWriter<ELF64BE>; |
| template class MipsDynamicLibraryWriter<ELF64LE>; |
| |
| template <class ELFT> |
| MipsExecutableWriter<ELFT>::MipsExecutableWriter( |
| MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout, |
| const MipsAbiInfoHandler<ELFT> &abiInfo) |
| : ExecutableWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout, abiInfo), |
| _targetLayout(layout) {} |
| |
| template <class ELFT> |
| std::error_code MipsExecutableWriter<ELFT>::setELFHeader() { |
| std::error_code ec = ExecutableWriter<ELFT>::setELFHeader(); |
| if (ec) |
| return ec; |
| |
| StringRef entryName = this->_ctx.entrySymbolName(); |
| if (const AtomLayout *al = this->_layout.findAtomLayoutByName(entryName)) { |
| const auto *ea = cast<DefinedAtom>(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 <class ELFT> |
| void MipsExecutableWriter<ELFT>::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<AtomSection<ELFT>>(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<const DefinedAtom>(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<ELFT>::buildDynamicSymbolTable because we replaced it |
| // with our own version. Call OutputELFWriter directly. |
| OutputELFWriter<ELFT>::buildDynamicSymbolTable(file); |
| } |
| |
| template <class ELFT> |
| void MipsExecutableWriter<ELFT>::createImplicitFiles( |
| std::vector<std::unique_ptr<File>> &result) { |
| ExecutableWriter<ELFT>::createImplicitFiles(result); |
| result.push_back(_writeHelper.createRuntimeFile()); |
| } |
| |
| template <class ELFT> |
| void MipsExecutableWriter<ELFT>::finalizeDefaultAtomValues() { |
| // Finalize the atom values that are part of the parent. |
| ExecutableWriter<ELFT>::finalizeDefaultAtomValues(); |
| _writeHelper.finalizeMipsRuntimeAtomValues(); |
| } |
| |
| template <class ELFT> void MipsExecutableWriter<ELFT>::createDefaultSections() { |
| ExecutableWriter<ELFT>::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 <class ELFT> |
| unique_bump_ptr<SymbolTable<ELFT>> |
| MipsExecutableWriter<ELFT>::createSymbolTable() { |
| return unique_bump_ptr<SymbolTable<ELFT>>( |
| new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx)); |
| } |
| |
| /// \brief create dynamic table |
| template <class ELFT> |
| unique_bump_ptr<DynamicTable<ELFT>> |
| MipsExecutableWriter<ELFT>::createDynamicTable() { |
| return unique_bump_ptr<DynamicTable<ELFT>>( |
| new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout)); |
| } |
| |
| /// \brief create dynamic symbol table |
| template <class ELFT> |
| unique_bump_ptr<DynamicSymbolTable<ELFT>> |
| MipsExecutableWriter<ELFT>::createDynamicSymbolTable() { |
| return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new ( |
| this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout)); |
| } |
| |
| template class MipsExecutableWriter<ELF32BE>; |
| template class MipsExecutableWriter<ELF32LE>; |
| template class MipsExecutableWriter<ELF64BE>; |
| template class MipsExecutableWriter<ELF64LE>; |
| |
| } // elf |
| } // lld |