//===- lib/ReaderWriter/ELF/ARM/ARMELFWriters.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_ARM_ARM_ELF_WRITERS_H #define LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H #include "ARMLinkingContext.h" #include "ARMSymbolTable.h" #include "llvm/Support/ELF.h" namespace lld { namespace elf { template class ARMELFWriter : public WriterT { public: ARMELFWriter(ARMLinkingContext &ctx, TargetLayout &layout); void finalizeDefaultAtomValues() override; /// \brief Create symbol table. unique_bump_ptr> createSymbolTable() override; // Setup the ELF header. std::error_code setELFHeader() override; protected: static const char *gotSymbol; static const char *dynamicSymbol; private: ARMLinkingContext &_ctx; TargetLayout &_armLayout; }; template const char *ARMELFWriter::gotSymbol = "_GLOBAL_OFFSET_TABLE_"; template const char *ARMELFWriter::dynamicSymbol = "_DYNAMIC"; template ARMELFWriter::ARMELFWriter(ARMLinkingContext &ctx, TargetLayout &layout) : WriterT(ctx, layout), _ctx(ctx), _armLayout(layout) {} template void ARMELFWriter::finalizeDefaultAtomValues() { // Finalize the atom values that are part of the parent. WriterT::finalizeDefaultAtomValues(); if (auto *gotAtom = _armLayout.findAbsoluteAtom(gotSymbol)) { if (auto gotpltSection = _armLayout.findOutputSection(".got.plt")) gotAtom->_virtualAddr = gotpltSection->virtualAddr(); else if (auto gotSection = _armLayout.findOutputSection(".got")) gotAtom->_virtualAddr = gotSection->virtualAddr(); else gotAtom->_virtualAddr = 0; } if (auto *dynamicAtom = _armLayout.findAbsoluteAtom(dynamicSymbol)) { if (auto dynamicSection = _armLayout.findOutputSection(".dynamic")) dynamicAtom->_virtualAddr = dynamicSection->virtualAddr(); else dynamicAtom->_virtualAddr = 0; } // Set required by gcc libc __ehdr_start symbol with pointer to ELF header if (auto ehdr = _armLayout.findAbsoluteAtom("__ehdr_start")) ehdr->_virtualAddr = this->_elfHeader->virtualAddr(); // Set required by gcc libc symbols __exidx_start/__exidx_end this->updateScopeAtomValues("exidx", ".ARM.exidx"); } template unique_bump_ptr> ARMELFWriter::createSymbolTable() { return unique_bump_ptr>(new (this->_alloc) ARMSymbolTable(_ctx)); } template std::error_code ARMELFWriter::setELFHeader() { if (std::error_code ec = WriterT::setELFHeader()) return ec; // Set ARM-specific flags. this->_elfHeader->e_flags(llvm::ELF::EF_ARM_EABI_VER5 | llvm::ELF::EF_ARM_VFP_FLOAT); StringRef entryName = _ctx.entrySymbolName(); if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) { if (const auto *ea = dyn_cast(al->_atom)) { switch (ea->codeModel()) { case DefinedAtom::codeNA: if (al->_virtualAddr & 0x3) { llvm::report_fatal_error( "Two least bits must be zero for ARM entry point"); } break; case DefinedAtom::codeARMThumb: // Fixup entry point for Thumb code. this->_elfHeader->e_entry(al->_virtualAddr | 0x1); break; default: llvm_unreachable("Wrong code model of entry point atom"); } } } return std::error_code(); } } // namespace elf } // namespace lld #endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H