//===--------- lib/ReaderWriter/ELF/ARM/ARMELFFile.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_FILE_H #define LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H #include "ELFReader.h" namespace lld { namespace elf { class ARMLinkingContext; class ARMELFBaseDefinedAtom : public ELFDefinedAtom { public: /// The values of custom content type enum must not interfere /// with ones in base defined atom class' enum. enum ARMContentType { typeARMExidx = 0x1000, // Identifies ARM_EXIDX section }; template ARMELFBaseDefinedAtom(T &&... args) : ELFDefinedAtom(std::forward(args)...) {} DefinedAtom::ContentPermissions permissions() const override { if (_permissions != DefinedAtom::permUnknown) return _permissions; switch (_section->sh_type) { case llvm::ELF::SHT_ARM_EXIDX: return _permissions = permR__; } return ELFDefinedAtom::permissions(); } DefinedAtom::ContentType contentType() const override { if (_contentType != DefinedAtom::typeUnknown) return _contentType; switch (_section->sh_type) { case llvm::ELF::SHT_ARM_EXIDX: return _contentType = (DefinedAtom::ContentType)typeARMExidx; } return ELFDefinedAtom::contentType(); } }; class ARMELFMappingAtom : public ARMELFBaseDefinedAtom { public: template ARMELFMappingAtom(DefinedAtom::CodeModel model, T &&... args) : ARMELFBaseDefinedAtom(std::forward(args)...), _model(model) {} DefinedAtom::CodeModel codeModel() const override { return _model; } private: DefinedAtom::CodeModel _model; }; class ARMELFDefinedAtom : public ARMELFBaseDefinedAtom { public: template ARMELFDefinedAtom(T &&... args) : ARMELFBaseDefinedAtom(std::forward(args)...) {} bool isThumbFunc() const { const auto *symbol = _symbol; return symbol->getType() == llvm::ELF::STT_FUNC && (static_cast(symbol->st_value) & 0x1); } /// Correct st_value for symbols addressing Thumb instructions /// by removing its zero bit. uint64_t getSymbolValue() const override { const auto value = static_cast(_symbol->st_value); return isThumbFunc() ? value & ~0x1 : value; } DefinedAtom::CodeModel codeModel() const override { return isThumbFunc() ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA; } }; class ARMELFFile : public ELFFile { typedef llvm::object::Elf_Rel_Impl Elf_Rel; public: ARMELFFile(std::unique_ptr mb, ELFLinkingContext &ctx) : ELFFile(std::move(mb), ctx) {} protected: /// Returns initial addend; for ARM it is 0, because it is read /// during the relocations applying Reference::Addend getInitialAddend(ArrayRef, uint64_t, const Elf_Rel &) const override { return 0; } private: typedef llvm::object::Elf_Sym_Impl Elf_Sym; typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; /// Correct st_value for symbols addressing Thumb instructions /// by removing its zero bit. uint64_t getSymbolValue(const Elf_Sym *symbol) const override { const auto value = static_cast(symbol->st_value); return symbol->getType() == llvm::ELF::STT_FUNC ? value & ~0x1 : value; } /// Process the Defined symbol and create an atom for it. ELFDefinedAtom *createDefinedAtom( StringRef symName, StringRef sectionName, const Elf_Sym *sym, const Elf_Shdr *sectionHdr, ArrayRef contentData, unsigned int referenceStart, unsigned int referenceEnd, std::vector *> &referenceList) override { if (symName.size() >= 2 && symName[0] == '$') { switch (symName[1]) { case 'a': return new (_readerStorage) ARMELFMappingAtom(DefinedAtom::codeARM_a, *this, symName, sectionName, sym, sectionHdr, contentData, referenceStart, referenceEnd, referenceList); case 'd': return new (_readerStorage) ARMELFMappingAtom(DefinedAtom::codeARM_d, *this, symName, sectionName, sym, sectionHdr, contentData, referenceStart, referenceEnd, referenceList); case 't': return new (_readerStorage) ARMELFMappingAtom(DefinedAtom::codeARM_t, *this, symName, sectionName, sym, sectionHdr, contentData, referenceStart, referenceEnd, referenceList); default: // Fall through and create regular defined atom. break; } } return new (_readerStorage) ARMELFDefinedAtom( *this, symName, sectionName, sym, sectionHdr, contentData, referenceStart, referenceEnd, referenceList); } }; } // elf } // lld #endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H