aboutsummaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/Atoms.h
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-03-24 21:31:36 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-03-24 21:31:36 +0000
commitfb911942f1434f3d1750f83f25f5e42c80e60638 (patch)
tree1678c4a4f0182e4029a86d135aa4a1b7d09e3c41 /lib/ReaderWriter/ELF/Atoms.h
downloadsrc-fb911942f1434f3d1750f83f25f5e42c80e60638.tar.gz
src-fb911942f1434f3d1750f83f25f5e42c80e60638.zip
Vendor import of lld trunk r233088:vendor/lld/lld-trunk-r233088
Notes
Notes: svn path=/vendor/lld/dist/; revision=280461 svn path=/vendor/lld/lld-trunk-r233088/; revision=280462; tag=vendor/lld/lld-trunk-r233088
Diffstat (limited to 'lib/ReaderWriter/ELF/Atoms.h')
-rw-r--r--lib/ReaderWriter/ELF/Atoms.h849
1 files changed, 849 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/Atoms.h b/lib/ReaderWriter/ELF/Atoms.h
new file mode 100644
index 000000000000..6a506d21d938
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Atoms.h
@@ -0,0 +1,849 @@
+//===- 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 "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),
+ _target(nullptr), _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),
+ _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off),
+ _addend(0) {}
+
+ ELFReference(uint32_t edgeKind)
+ : Reference(Reference::KindNamespace::all, Reference::KindArch::all,
+ edgeKind),
+ _target(nullptr), _targetSymbolIndex(0), _offsetInAtom(0), _addend(0) {}
+
+ 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;
+ uint64_t _targetSymbolIndex;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+};
+
+/// \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 {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() == llvm::ELF::STB_LOCAL)
+ return scopeTranslationUnit;
+ return scopeGlobal;
+ }
+
+ 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 lld::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 {
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return CanBeNull::canBeNullAtBuildtime;
+ return CanBeNull::canBeNullNever;
+ }
+
+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() {}
+
+ 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 {
+ // Common symbols are not allocated in object files,
+ // so use st_size to tell how many bytes are required.
+ if (_symbol && (_symbol->getType() == llvm::ELF::STT_COMMON ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON))
+ return (uint64_t) _symbol->st_size;
+
+ return _contentData.size();
+ }
+
+ Scope scope() const override {
+ if (!_symbol)
+ return scopeGlobal;
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ // FIXME: Need to revisit this in future.
+ Interposable interposable() const override { return interposeNo; }
+
+ Merge merge() const override {
+ if (!_symbol)
+ return mergeNo;
+
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return mergeAsWeak;
+
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return mergeAsTentative;
+
+ return mergeNo;
+ }
+
+ ContentType contentType() const override {
+ if (_contentType != typeUnknown)
+ return _contentType;
+
+ ContentType ret = typeUnknown;
+ uint64_t flags = _section->sh_flags;
+
+ if (_section->sh_type == llvm::ELF::SHT_GROUP)
+ return typeGroupComdat;
+
+ if (!_symbol && _sectionName.startswith(".gnu.linkonce"))
+ return typeGnuLinkOnce;
+
+ if (!(flags & llvm::ELF::SHF_ALLOC))
+ return _contentType = typeNoAlloc;
+
+ if (_section->sh_flags ==
+ (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_TLS)) {
+ return _contentType = _section->sh_type == llvm::ELF::SHT_NOBITS ? typeThreadZeroFill
+ : typeThreadData;
+ }
+
+ if ((_section->sh_flags == llvm::ELF::SHF_ALLOC) &&
+ (_section->sh_type == llvm::ELF::SHT_PROGBITS))
+ return _contentType = typeConstant;
+
+ if (_symbol->getType() == llvm::ELF::STT_GNU_IFUNC)
+ return _contentType = typeResolver;
+
+ if (_symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return _contentType = typeZeroFill;
+
+ switch (_section->sh_type) {
+ case llvm::ELF::SHT_PROGBITS:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ flags &= ~llvm::ELF::SHF_GROUP;
+ switch (flags) {
+ case llvm::ELF::SHF_EXECINSTR:
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ ret = typeCode;
+ break;
+ case llvm::ELF::SHF_WRITE:
+ ret = typeData;
+ break;
+ case (llvm::ELF::SHF_MERGE|llvm::ELF::SHF_STRINGS):
+ case llvm::ELF::SHF_STRINGS:
+ case llvm::ELF::SHF_MERGE:
+ ret = typeConstant;
+ break;
+ default:
+ ret = typeCode;
+ break;
+ }
+ break;
+ case llvm::ELF::SHT_NOTE:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ switch (flags) {
+ case llvm::ELF::SHF_WRITE:
+ ret = typeRWNote;
+ break;
+ default:
+ ret = typeRONote;
+ break;
+ }
+ break;
+ case llvm::ELF::SHT_NOBITS:
+ ret = typeZeroFill;
+ break;
+ case llvm::ELF::SHT_NULL:
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON)
+ || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ ret = typeZeroFill;
+ break;
+ case llvm::ELF::SHT_INIT_ARRAY:
+ case llvm::ELF::SHT_FINI_ARRAY:
+ ret = typeData;
+ break;
+ }
+
+ return _contentType = ret;
+ }
+
+ Alignment alignment() const override {
+ if (!_symbol)
+ return Alignment(0);
+
+ // Obtain proper value of st_value field.
+ const auto symValue = getSymbolValue(_symbol);
+
+ // Unallocated common symbols specify their alignment constraints in
+ // st_value.
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON) {
+ return Alignment(llvm::Log2_64(symValue));
+ }
+ if (_section->sh_addralign == 0) {
+ // sh_addralign of 0 means no alignment
+ return Alignment(0, symValue);
+ }
+ return Alignment(llvm::Log2_64(_section->sh_addralign),
+ symValue % _section->sh_addralign);
+ }
+
+ // Do we have a choice for ELF? All symbols live in explicit sections.
+ SectionChoice sectionChoice() const override {
+ switch (contentType()) {
+ case typeCode:
+ case typeData:
+ case typeZeroFill:
+ case typeThreadZeroFill:
+ case typeThreadData:
+ case typeConstant:
+ if ((_sectionName == ".text") || (_sectionName == ".data") ||
+ (_sectionName == ".bss") || (_sectionName == ".rodata") ||
+ (_sectionName == ".tdata") || (_sectionName == ".tbss"))
+ return sectionBasedOnContent;
+ default:
+ break;
+ }
+ return sectionCustomRequired;
+ }
+
+ StringRef customSectionName() const override {
+ if ((contentType() == typeZeroFill) ||
+ (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON))
+ return ".bss";
+ return _sectionName;
+ }
+
+ // It isn't clear that __attribute__((used)) is transmitted to the ELF object
+ // file.
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ ContentPermissions permissions() const override {
+ if (_permissions != permUnknown)
+ return _permissions;
+
+ uint64_t flags = _section->sh_flags;
+
+ if (!(flags & llvm::ELF::SHF_ALLOC))
+ return _permissions = perm___;
+
+ switch (_section->sh_type) {
+ // permRW_L is for sections modified by the runtime
+ // loader.
+ case llvm::ELF::SHT_REL:
+ case llvm::ELF::SHT_RELA:
+ return _permissions = permRW_L;
+
+ case llvm::ELF::SHT_DYNAMIC:
+ case llvm::ELF::SHT_PROGBITS:
+ case llvm::ELF::SHT_NOTE:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ flags &= ~llvm::ELF::SHF_GROUP;
+ switch (flags) {
+ // Code
+ case llvm::ELF::SHF_EXECINSTR:
+ return _permissions = permR_X;
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ return _permissions = permRWX;
+ // Data
+ case llvm::ELF::SHF_WRITE:
+ return _permissions = permRW_;
+ // Strings
+ case llvm::ELF::SHF_MERGE:
+ case llvm::ELF::SHF_STRINGS:
+ return _permissions = permR__;
+
+ default:
+ if (flags & llvm::ELF::SHF_WRITE)
+ return _permissions = permRW_;
+ return _permissions = permR__;
+ }
+
+ case llvm::ELF::SHT_NOBITS:
+ return _permissions = permRW_;
+
+ case llvm::ELF::SHT_INIT_ARRAY:
+ case llvm::ELF::SHT_FINI_ARRAY:
+ return _permissions = permRW_;
+
+ default:
+ return _permissions = perm___;
+ }
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return _contentData; }
+
+ DefinedAtom::reference_iterator begin() const override {
+ uintptr_t index = _referenceStartIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ uintptr_t index = _referenceEndIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *It) const override {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ assert(index >= _referenceStartIndex);
+ assert(index < _referenceEndIndex);
+ return ((_referenceList)[index]);
+ }
+
+ void incrementIterator(const void *&It) const override {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ ++index;
+ It = reinterpret_cast<const void *>(index);
+ }
+
+ void addReference(ELFReference<ELFT> *reference) {
+ _referenceList.push_back(reference);
+ _referenceEndIndex = _referenceList.size();
+ }
+
+ 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 Elf_Sym *symbol) const {
+ return symbol->st_value;
+ }
+
+protected:
+ 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(llvm::Log2_64(_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(llvm::Log2_64(_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 {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ StringRef loadName() const override { return _loadName; }
+
+ bool canBeNullAtRuntime() const override {
+ return _symbol->getBinding() == llvm::ELF::STB_WEAK;
+ }
+
+ Type type() const override {
+ switch (_symbol->getType()) {
+ case llvm::ELF::STT_FUNC:
+ case llvm::ELF::STT_GNU_IFUNC:
+ return Type::Code;
+ case llvm::ELF::STT_OBJECT:
+ return Type::Data;
+ default:
+ return Type::Unknown;
+ }
+ }
+
+ 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 *target,
+ Reference::Addend addend) {
+ this->addReference(Reference::KindNamespace::ELF, arch, kindValue, off,
+ target, addend);
+ }
+
+ void addReferenceELF_Hexagon(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, a);
+ }
+
+ void addReferenceELF_x86_64(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, a);
+ }
+
+ void addReferenceELF_Mips(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a);
+ }
+
+ void addReferenceELF_AArch64(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a);
+ }
+
+ void addReferenceELF_ARM(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->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 {
+ // The alignment should be 8 byte aligned
+ return Alignment(3);
+ }
+
+ 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 {
+ // The alignment should be 8 byte aligned
+ return Alignment(3);
+ }
+
+#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 Alignment(4); // 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 GLOBAL_OFFSET_TABLEAtom : public SimpleELFDefinedAtom {
+public:
+ GLOBAL_OFFSET_TABLEAtom(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 {
+ // Needs 8 byte alignment
+ return Alignment(3);
+ }
+
+ 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 Alignment(0); }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif