| //===- 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 <memory> |
| #include <vector> |
| |
| namespace lld { |
| namespace elf { |
| template <class ELFT> class DynamicFile; |
| template <typename ELFT> 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 ELFT> class ELFReference : public Reference { |
| typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; |
| typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; |
| typedef llvm::object::Elf_Sym_Impl<ELFT> 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 ELFT> class ELFAbsoluteAtom : public AbsoluteAtom { |
| typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; |
| |
| public: |
| ELFAbsoluteAtom(const ELFFile<ELFT> &file, StringRef name, |
| const Elf_Sym *symbol, uint64_t value) |
| : _owningFile(file), _name(name), _symbol(symbol), _value(value) {} |
| |
| const ELFFile<ELFT> &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<ELFT> &_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 ELFT> class ELFUndefinedAtom : public UndefinedAtom { |
| typedef llvm::object::Elf_Sym_Impl<ELFT> 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 ELFT> class ELFDefinedAtom : public DefinedAtom { |
| typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; |
| typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; |
| |
| public: |
| ELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName, |
| StringRef sectionName, const Elf_Sym *symbol, |
| const Elf_Shdr *section, ArrayRef<uint8_t> contentData, |
| unsigned int referenceStart, unsigned int referenceEnd, |
| std::vector<ELFReference<ELFT> *> &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<ELFT> &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<uint8_t> 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<ELFT> *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<ELFT> &_owningFile; |
| StringRef _symbolName; |
| StringRef _sectionName; |
| const Elf_Sym *_symbol; |
| const Elf_Shdr *_section; |
| /// \brief Holds the bits that make up the atom. |
| ArrayRef<uint8_t> _contentData; |
| |
| uint64_t _ordinal; |
| unsigned int _referenceStartIndex; |
| unsigned int _referenceEndIndex; |
| std::vector<ELFReference<ELFT> *> &_referenceList; |
| mutable ContentType _contentType; |
| mutable ContentPermissions _permissions; |
| }; |
| |
| /// \brief This atom stores mergeable Strings |
| template <class ELFT> class ELFMergeAtom : public DefinedAtom { |
| typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr; |
| |
| public: |
| ELFMergeAtom(const ELFFile<ELFT> &file, StringRef sectionName, |
| const Elf_Shdr *section, ArrayRef<uint8_t> contentData, |
| uint64_t offset) |
| : _owningFile(file), _sectionName(sectionName), _section(section), |
| _contentData(contentData), _offset(offset) { |
| } |
| |
| const ELFFile<ELFT> &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<uint8_t> rawContent() const override { return _contentData; } |
| |
| DefinedAtom::reference_iterator begin() const override { |
| uintptr_t index = 0; |
| const void *it = reinterpret_cast<const void *>(index); |
| return reference_iterator(*this, it); |
| } |
| |
| DefinedAtom::reference_iterator end() const override { |
| uintptr_t index = 0; |
| const void *it = reinterpret_cast<const void *>(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<ELFT> &_owningFile; |
| StringRef _sectionName; |
| const Elf_Shdr *_section; |
| /// \brief Holds the bits that make up the atom. |
| ArrayRef<uint8_t> _contentData; |
| uint64_t _ordinal; |
| uint64_t _offset; |
| }; |
| |
| template <class ELFT> class ELFCommonAtom : public DefinedAtom { |
| typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; |
| public: |
| ELFCommonAtom(const ELFFile<ELFT> &file, StringRef symbolName, |
| const Elf_Sym *symbol) |
| : _owningFile(file), _symbolName(symbolName), _symbol(symbol) {} |
| |
| const ELFFile<ELFT> &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<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } |
| |
| DefinedAtom::reference_iterator begin() const override { |
| uintptr_t index = 0; |
| const void *it = reinterpret_cast<const void *>(index); |
| return reference_iterator(*this, it); |
| } |
| |
| DefinedAtom::reference_iterator end() const override { |
| uintptr_t index = 0; |
| const void *it = reinterpret_cast<const void *>(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<ELFT> &_owningFile; |
| StringRef _symbolName; |
| const Elf_Sym *_symbol; |
| uint64_t _ordinal; |
| }; |
| |
| /// \brief An atom from a shared library. |
| template <class ELFT> class ELFDynamicAtom : public SharedLibraryAtom { |
| typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; |
| |
| public: |
| ELFDynamicAtom(const DynamicFile<ELFT> &file, StringRef symbolName, |
| StringRef loadName, const Elf_Sym *symbol) |
| : _owningFile(file), _symbolName(symbolName), _loadName(loadName), |
| _symbol(symbol) {} |
| |
| const DynamicFile<ELFT> &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<ELFT> &_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<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } |
| 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<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } |
| }; |
| |
| 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<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } |
| }; |
| |
| } // end namespace elf |
| } // end namespace lld |
| |
| #endif // LLD_READER_WRITER_ELF_ATOMS_H |