//===- lib/ReaderWriter/ELF/Atoms.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_ATOMS_H #define LLD_READER_WRITER_ELF_ATOMS_H #include "TargetHandler.h" #include "lld/Core/LLVM.h" #include "lld/Core/Simple.h" #include "lld/ReaderWriter/ELFLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSwitch.h" #include #include namespace lld { namespace elf { template class DynamicFile; template class ELFFile; /// \brief Relocation References: Defined Atoms may contain references that will /// need to be patched before the executable is written. /// /// Construction of ELFReferences is two pass process. ELFReferences are /// instantiated while we are iterating over symbol tables to atomize /// symbols. At that time we only know the index of relocation target symbol /// (not target atom) about a relocation, so we store the index to /// ELFREference. In the second pass, ELFReferences are revisited to update /// target atoms by target symbol indexes. template class ELFReference : public Reference { typedef llvm::object::Elf_Rel_Impl Elf_Rel; typedef llvm::object::Elf_Rel_Impl Elf_Rela; typedef llvm::object::Elf_Sym_Impl Elf_Sym; public: ELFReference(const Elf_Rela *rela, uint64_t off, Reference::KindArch arch, Reference::KindValue relocType, uint32_t idx) : Reference(Reference::KindNamespace::ELF, arch, relocType), _targetSymbolIndex(idx), _offsetInAtom(off), _addend(rela->r_addend) {} ELFReference(uint64_t off, Reference::KindArch arch, Reference::KindValue relocType, uint32_t idx) : Reference(Reference::KindNamespace::ELF, arch, relocType), _targetSymbolIndex(idx), _offsetInAtom(off) {} ELFReference(uint32_t edgeKind) : Reference(Reference::KindNamespace::all, Reference::KindArch::all, edgeKind) {} uint64_t offsetInAtom() const override { return _offsetInAtom; } const Atom *target() const override { return _target; } /// \brief The symbol table index that contains the target reference. uint64_t targetSymbolIndex() const { return _targetSymbolIndex; } Addend addend() const override { return _addend; } virtual void setOffset(uint64_t off) { _offsetInAtom = off; } void setAddend(Addend A) override { _addend = A; } void setTarget(const Atom *newAtom) override { _target = newAtom; } private: const Atom *_target = nullptr; uint64_t _targetSymbolIndex = 0; uint64_t _offsetInAtom = 0; Addend _addend = 0; }; /// \brief These atoms store symbols that are fixed to a particular address. /// This atom has no content its address will be used by the writer to fixup /// references that point to it. template class ELFAbsoluteAtom : public AbsoluteAtom { typedef llvm::object::Elf_Sym_Impl Elf_Sym; public: ELFAbsoluteAtom(const ELFFile &file, StringRef name, const Elf_Sym *symbol, uint64_t value) : _owningFile(file), _name(name), _symbol(symbol), _value(value) {} const ELFFile &file() const override { return _owningFile; } Scope scope() const override; StringRef name() const override { return _name; } uint64_t value() const override { return _value; } private: const ELFFile &_owningFile; StringRef _name; const Elf_Sym *_symbol; uint64_t _value; }; /// \brief ELFUndefinedAtom: These atoms store undefined symbols and are place /// holders that will be replaced by defined atoms later in the linking process. template class ELFUndefinedAtom : public UndefinedAtom { typedef llvm::object::Elf_Sym_Impl Elf_Sym; public: ELFUndefinedAtom(const File &file, StringRef name, const Elf_Sym *symbol) : _owningFile(file), _name(name), _symbol(symbol) {} const File &file() const override { return _owningFile; } StringRef name() const override { return _name; } // A symbol in ELF can be undefined at build time if the symbol is a undefined // weak symbol. CanBeNull canBeNull() const override; private: const File &_owningFile; StringRef _name; const Elf_Sym *_symbol; }; /// \brief This atom stores defined symbols and will contain either data or /// code. template class ELFDefinedAtom : public DefinedAtom { typedef llvm::object::Elf_Sym_Impl Elf_Sym; typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; public: ELFDefinedAtom(const ELFFile &file, StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol, const Elf_Shdr *section, ArrayRef contentData, unsigned int referenceStart, unsigned int referenceEnd, std::vector *> &referenceList) : _owningFile(file), _symbolName(symbolName), _sectionName(sectionName), _symbol(symbol), _section(section), _contentData(contentData), _referenceStartIndex(referenceStart), _referenceEndIndex(referenceEnd), _referenceList(referenceList), _contentType(typeUnknown), _permissions(permUnknown) {} ~ELFDefinedAtom() override = default; const ELFFile &file() const override { return _owningFile; } StringRef name() const override { return _symbolName; } uint64_t ordinal() const override { return _ordinal; } const Elf_Sym *symbol() const { return _symbol; } const Elf_Shdr *section() const { return _section; } uint64_t size() const override; Scope scope() const override; // FIXME: Need to revisit this in future. Interposable interposable() const override { return interposeNo; } Merge merge() const override; ContentType contentType() const override; Alignment alignment() const override; SectionChoice sectionChoice() const override; StringRef customSectionName() const override; // It isn't clear that __attribute__((used)) is transmitted to the ELF object // file. DeadStripKind deadStrip() const override { return deadStripNormal; } ContentPermissions permissions() const override; ArrayRef rawContent() const override { return _contentData; } DefinedAtom::reference_iterator begin() const override; DefinedAtom::reference_iterator end() const override; const Reference *derefIterator(const void *It) const override; void incrementIterator(const void *&It) const override; void addReference(ELFReference *reference); virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } protected: /// Returns correct st_value for the symbol depending on the architecture. /// For most architectures it's just a regular st_value with no changes. virtual uint64_t getSymbolValue() const { return _symbol->st_value; } ContentType doContentType() const; const ELFFile &_owningFile; StringRef _symbolName; StringRef _sectionName; const Elf_Sym *_symbol; const Elf_Shdr *_section; /// \brief Holds the bits that make up the atom. ArrayRef _contentData; uint64_t _ordinal; unsigned int _referenceStartIndex; unsigned int _referenceEndIndex; std::vector *> &_referenceList; mutable ContentType _contentType; mutable ContentPermissions _permissions; }; /// \brief This atom stores mergeable Strings template class ELFMergeAtom : public DefinedAtom { typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; public: ELFMergeAtom(const ELFFile &file, StringRef sectionName, const Elf_Shdr *section, ArrayRef contentData, uint64_t offset) : _owningFile(file), _sectionName(sectionName), _section(section), _contentData(contentData), _offset(offset) { } const ELFFile &file() const override { return _owningFile; } StringRef name() const override { return ""; } virtual uint64_t section() const { return _section->sh_name; } virtual uint64_t offset() const { return _offset; } virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } uint64_t ordinal() const override { return _ordinal; } uint64_t size() const override { return _contentData.size(); } Scope scope() const override { return scopeTranslationUnit; } Interposable interposable() const override { return interposeNo; } Merge merge() const override { return mergeByContent; } ContentType contentType() const override { return typeConstant; } Alignment alignment() const override { return Alignment(_section->sh_addralign); } SectionChoice sectionChoice() const override { return sectionCustomRequired; } StringRef customSectionName() const override { return _sectionName; } DeadStripKind deadStrip() const override { return deadStripNormal; } ContentPermissions permissions() const override { return permR__; } ArrayRef rawContent() const override { return _contentData; } DefinedAtom::reference_iterator begin() const override { uintptr_t index = 0; const void *it = reinterpret_cast(index); return reference_iterator(*this, it); } DefinedAtom::reference_iterator end() const override { uintptr_t index = 0; const void *it = reinterpret_cast(index); return reference_iterator(*this, it); } const Reference *derefIterator(const void *It) const override { return nullptr; } void incrementIterator(const void *&It) const override {} private: const ELFFile &_owningFile; StringRef _sectionName; const Elf_Shdr *_section; /// \brief Holds the bits that make up the atom. ArrayRef _contentData; uint64_t _ordinal; uint64_t _offset; }; template class ELFCommonAtom : public DefinedAtom { typedef llvm::object::Elf_Sym_Impl Elf_Sym; public: ELFCommonAtom(const ELFFile &file, StringRef symbolName, const Elf_Sym *symbol) : _owningFile(file), _symbolName(symbolName), _symbol(symbol) {} const ELFFile &file() const override { return _owningFile; } StringRef name() const override { return _symbolName; } uint64_t ordinal() const override { return _ordinal; } virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } uint64_t size() const override { return _symbol->st_size; } Scope scope() const override { if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) return scopeLinkageUnit; if (_symbol->getBinding() != llvm::ELF::STB_LOCAL) return scopeGlobal; return scopeTranslationUnit; } Interposable interposable() const override { return interposeNo; } Merge merge() const override { return mergeAsTentative; } ContentType contentType() const override { return typeZeroFill; } Alignment alignment() const override { return Alignment(_symbol->st_value); } SectionChoice sectionChoice() const override { return sectionBasedOnContent; } StringRef customSectionName() const override { return ".bss"; } DeadStripKind deadStrip() const override { return deadStripNormal; } ContentPermissions permissions() const override { return permRW_; } ArrayRef rawContent() const override { return ArrayRef(); } DefinedAtom::reference_iterator begin() const override { uintptr_t index = 0; const void *it = reinterpret_cast(index); return reference_iterator(*this, it); } DefinedAtom::reference_iterator end() const override { uintptr_t index = 0; const void *it = reinterpret_cast(index); return reference_iterator(*this, it); } protected: const Reference *derefIterator(const void *iter) const override { return nullptr; } void incrementIterator(const void *&iter) const override {} const ELFFile &_owningFile; StringRef _symbolName; const Elf_Sym *_symbol; uint64_t _ordinal; }; /// \brief An atom from a shared library. template class ELFDynamicAtom : public SharedLibraryAtom { typedef llvm::object::Elf_Sym_Impl Elf_Sym; public: ELFDynamicAtom(const DynamicFile &file, StringRef symbolName, StringRef loadName, const Elf_Sym *symbol) : _owningFile(file), _symbolName(symbolName), _loadName(loadName), _symbol(symbol) {} const DynamicFile &file() const override { return _owningFile; } StringRef name() const override { return _symbolName; } virtual Scope scope() const; StringRef loadName() const override { return _loadName; } bool canBeNullAtRuntime() const override { return _symbol->getBinding() == llvm::ELF::STB_WEAK; } Type type() const override; uint64_t size() const override { return _symbol->st_size; } private: const DynamicFile &_owningFile; StringRef _symbolName; StringRef _loadName; const Elf_Sym *_symbol; }; class SimpleELFDefinedAtom : public SimpleDefinedAtom { public: SimpleELFDefinedAtom(const File &f) : SimpleDefinedAtom(f) {} void addReferenceELF(Reference::KindArch arch, Reference::KindValue kindValue, uint64_t off, const Atom *t, Reference::Addend a) { addReference(Reference::KindNamespace::ELF, arch, kindValue, off, t, a); } void addReferenceELF_Hexagon(Reference::KindValue relocType, uint64_t off, const Atom *t, Reference::Addend a) { addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, a); } void addReferenceELF_x86_64(Reference::KindValue relocType, uint64_t off, const Atom *t, Reference::Addend a) { addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, a); } void addReferenceELF_Mips(Reference::KindValue relocType, uint64_t off, const Atom *t, Reference::Addend a) { addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a); } void addReferenceELF_AArch64(Reference::KindValue relocType, uint64_t off, const Atom *t, Reference::Addend a) { addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a); } void addReferenceELF_ARM(Reference::KindValue relocType, uint64_t off, const Atom *t, Reference::Addend a) { addReferenceELF(Reference::KindArch::ARM, relocType, off, t, a); } }; /// \brief Atom which represents an object for which a COPY relocation will be /// generated. class ObjectAtom : public SimpleELFDefinedAtom { public: ObjectAtom(const File &f) : SimpleELFDefinedAtom(f) {} Scope scope() const override { return scopeGlobal; } SectionChoice sectionChoice() const override { return sectionBasedOnContent; } ContentType contentType() const override { return typeZeroFill; } uint64_t size() const override { return _size; } DynamicExport dynamicExport() const override { return dynamicExportAlways; } ContentPermissions permissions() const override { return permRW_; } ArrayRef rawContent() const override { return ArrayRef(); } Alignment alignment() const override { return 8; } StringRef name() const override { return _name; } std::string _name; uint64_t _size; }; class GOTAtom : public SimpleELFDefinedAtom { StringRef _section; public: GOTAtom(const File &f, StringRef secName) : SimpleELFDefinedAtom(f), _section(secName) {} Scope scope() const override { return scopeTranslationUnit; } SectionChoice sectionChoice() const override { return sectionCustomRequired; } StringRef customSectionName() const override { return _section; } ContentType contentType() const override { return typeGOT; } uint64_t size() const override { return rawContent().size(); } ContentPermissions permissions() const override { return permRW_; } Alignment alignment() const override { return 8; } #ifndef NDEBUG StringRef name() const override { return _name; } std::string _name; #else StringRef name() const override { return ""; } #endif }; class PLTAtom : public SimpleELFDefinedAtom { StringRef _section; public: PLTAtom(const File &f, StringRef secName) : SimpleELFDefinedAtom(f), _section(secName) {} Scope scope() const override { return scopeTranslationUnit; } SectionChoice sectionChoice() const override { return sectionCustomRequired; } StringRef customSectionName() const override { return _section; } ContentType contentType() const override { return typeStub; } uint64_t size() const override { return rawContent().size(); } ContentPermissions permissions() const override { return permR_X; } Alignment alignment() const override { return 16; } #ifndef NDEBUG StringRef name() const override { return _name; } std::string _name; #else StringRef name() const override { return ""; } #endif }; class PLT0Atom : public PLTAtom { public: PLT0Atom(const File &f) : PLTAtom(f, ".plt") { #ifndef NDEBUG _name = ".PLT0"; #endif } }; class GlobalOffsetTableAtom : public SimpleELFDefinedAtom { public: GlobalOffsetTableAtom(const File &f) : SimpleELFDefinedAtom(f) {} StringRef name() const override { return "_GLOBAL_OFFSET_TABLE_"; } Scope scope() const override { return scopeLinkageUnit; } SectionChoice sectionChoice() const override { return sectionCustomRequired; } StringRef customSectionName() const override { return ".got.plt"; } ContentType contentType() const override { return typeGOT; } uint64_t size() const override { return 0; } ContentPermissions permissions() const override { return permRW_; } Alignment alignment() const override { return 8; } ArrayRef rawContent() const override { return ArrayRef(); } }; class DynamicAtom : public SimpleELFDefinedAtom { public: DynamicAtom(const File &f) : SimpleELFDefinedAtom(f) {} StringRef name() const override { return "_DYNAMIC"; } Scope scope() const override { return scopeLinkageUnit; } Merge merge() const override { return mergeNo; } SectionChoice sectionChoice() const override { return sectionCustomRequired; } StringRef customSectionName() const override { return ".dynamic"; } ContentType contentType() const override { return typeData; } uint64_t size() const override { return 0; } ContentPermissions permissions() const override { return permRW_; } Alignment alignment() const override { return 1; } ArrayRef rawContent() const override { return ArrayRef(); } }; } // end namespace elf } // end namespace lld #endif // LLD_READER_WRITER_ELF_ATOMS_H