//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.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_TARGET_HANDLER_H #define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H #include "ARMELFFile.h" #include "ARMRelocationHandler.h" #include "ELFReader.h" #include "TargetLayout.h" namespace lld { class ELFLinkingContext; namespace elf { /// \brief ARM specific section (.ARM.exidx) with indexes to exception handlers class ARMExidxSection : public AtomSection { typedef AtomSection Base; public: ARMExidxSection(const ELFLinkingContext &ctx, StringRef sectionName, int32_t permissions, int32_t order) : Base(ctx, sectionName, ARMELFDefinedAtom::typeARMExidx, permissions, order) { this->_type = SHT_ARM_EXIDX; this->_isLoadedInMemory = true; } bool hasOutputSegment() const override { return true; } const AtomLayout *appendAtom(const Atom *atom) override { const DefinedAtom *definedAtom = cast(atom); assert((ARMELFDefinedAtom::ARMContentType)definedAtom->contentType() == ARMELFDefinedAtom::typeARMExidx && "atom content type for .ARM.exidx section has to be typeARMExidx"); DefinedAtom::Alignment atomAlign = definedAtom->alignment(); uint64_t fOffset = alignOffset(this->fileSize(), atomAlign); uint64_t mOffset = alignOffset(this->memSize(), atomAlign); _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); this->_fsize = fOffset + definedAtom->size(); this->_msize = mOffset + definedAtom->size(); DEBUG_WITH_TYPE("Section", llvm::dbgs() << "[" << this->name() << " " << this << "] " << "Adding atom: " << atom->name() << "@" << fOffset << "\n"); uint64_t alignment = atomAlign.value; if (this->_alignment < alignment) this->_alignment = alignment; return _atoms.back(); } }; class ARMTargetLayout : public TargetLayout { public: enum ARMSectionOrder { ORDER_ARM_EXIDX = TargetLayout::ORDER_EH_FRAME + 1, }; ARMTargetLayout(ELFLinkingContext &ctx) : TargetLayout(ctx) {} SectionOrder getSectionOrder(StringRef name, int32_t contentType, int32_t contentPermissions) override { switch (contentType) { case ARMELFDefinedAtom::typeARMExidx: return ORDER_ARM_EXIDX; default: return TargetLayout::getSectionOrder(name, contentType, contentPermissions); } } StringRef getOutputSectionName(StringRef archivePath, StringRef memberPath, StringRef inputSectionName) const override { return llvm::StringSwitch(inputSectionName) .StartsWith(".ARM.exidx", ".ARM.exidx") .StartsWith(".ARM.extab", ".ARM.extab") .Default(TargetLayout::getOutputSectionName(archivePath, memberPath, inputSectionName)); } SegmentType getSegmentType(const Section *section) const override { switch (section->order()) { case ORDER_ARM_EXIDX: return llvm::ELF::PT_ARM_EXIDX; default: return TargetLayout::getSegmentType(section); } } AtomSection * createSection(StringRef name, int32_t contentType, DefinedAtom::ContentPermissions contentPermissions, SectionOrder sectionOrder) override { if ((ARMELFDefinedAtom::ARMContentType)contentType == ARMELFDefinedAtom::typeARMExidx) return new ARMExidxSection(_ctx, name, contentPermissions, sectionOrder); return TargetLayout::createSection(name, contentType, contentPermissions, sectionOrder); } uint64_t getGOTSymAddr() { std::call_once(_gotSymOnce, [this]() { if (AtomLayout *gotAtom = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_")) _gotSymAddr = gotAtom->_virtualAddr; }); return _gotSymAddr; } uint64_t getTPOffset() { std::call_once(_tpOffOnce, [this]() { for (const auto &phdr : *_programHeader) { if (phdr->p_type == llvm::ELF::PT_TLS) { _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align); break; } } assert(_tpOff != 0 && "TLS segment not found"); }); return _tpOff; } bool target1Rel() const { return _ctx.armTarget1Rel(); } private: // TCB block size of the TLS. enum { TCB_SIZE = 0x8 }; private: uint64_t _gotSymAddr = 0; uint64_t _tpOff = 0; std::once_flag _gotSymOnce; std::once_flag _tpOffOnce; }; class ARMTargetHandler final : public TargetHandler { public: ARMTargetHandler(ARMLinkingContext &ctx); const TargetRelocationHandler &getRelocationHandler() const override { return *_relocationHandler; } std::unique_ptr getObjReader() override { return llvm::make_unique>(_ctx); } std::unique_ptr getDSOReader() override { return llvm::make_unique>>(_ctx); } std::unique_ptr getWriter() override; private: ARMLinkingContext &_ctx; std::unique_ptr _targetLayout; std::unique_ptr _relocationHandler; }; } // end namespace elf } // end namespace lld #endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H