diff options
Diffstat (limited to 'lib/ReaderWriter/ELF/Atoms.cpp')
| -rw-r--r-- | lib/ReaderWriter/ELF/Atoms.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/Atoms.cpp b/lib/ReaderWriter/ELF/Atoms.cpp new file mode 100644 index 000000000000..639633393161 --- /dev/null +++ b/lib/ReaderWriter/ELF/Atoms.cpp @@ -0,0 +1,297 @@ +//===- lib/ReaderWriter/ELF/Atoms.cpp -------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Atoms.h" +#include "DynamicFile.h" +#include "ELFFile.h" +#include "TargetHandler.h" + +namespace lld { +namespace elf { + +template <class ELFT> AbsoluteAtom::Scope ELFAbsoluteAtom<ELFT>::scope() const { + if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) + return scopeLinkageUnit; + if (_symbol->getBinding() == llvm::ELF::STB_LOCAL) + return scopeTranslationUnit; + return scopeGlobal; +} + +template <class ELFT> +UndefinedAtom::CanBeNull ELFUndefinedAtom<ELFT>::canBeNull() const { + if (_symbol->getBinding() == llvm::ELF::STB_WEAK) + return CanBeNull::canBeNullAtBuildtime; + return CanBeNull::canBeNullNever; +} + +template <class ELFT> uint64_t ELFDefinedAtom<ELFT>::size() const { + // 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(); +} + +template <class ELFT> AbsoluteAtom::Scope ELFDefinedAtom<ELFT>::scope() const { + if (!_symbol) + return scopeGlobal; + if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) + return scopeLinkageUnit; + if (_symbol->getBinding() != llvm::ELF::STB_LOCAL) + return scopeGlobal; + return scopeTranslationUnit; +} + +template <class ELFT> DefinedAtom::Merge ELFDefinedAtom<ELFT>::merge() const { + 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; +} + +template <class ELFT> +DefinedAtom::ContentType ELFDefinedAtom<ELFT>::doContentType() const { + using namespace llvm::ELF; + + if (_section->sh_type == SHT_GROUP) + return typeGroupComdat; + if (!_symbol && _sectionName.startswith(".gnu.linkonce")) + return typeGnuLinkOnce; + + uint64_t flags = _section->sh_flags; + + if (!(flags & SHF_ALLOC)) { + if (_section->sh_type == SHT_NOTE) + return (flags == SHF_WRITE) ? typeRWNote : typeRONote; + return _contentType = typeNoAlloc; + } + + if (_section->sh_flags == (SHF_ALLOC | SHF_WRITE | SHF_TLS)) + return _section->sh_type == SHT_NOBITS ? typeThreadZeroFill + : typeThreadData; + + if (_section->sh_flags == SHF_ALLOC && _section->sh_type == SHT_PROGBITS) + return _contentType = typeConstant; + if (_symbol->getType() == STT_GNU_IFUNC) + return _contentType = typeResolver; + if (_symbol->st_shndx == SHN_COMMON) + return _contentType = typeZeroFill; + + if (_section->sh_type == SHT_PROGBITS) { + flags &= ~SHF_ALLOC; + flags &= ~SHF_GROUP; + if ((flags & SHF_STRINGS) || (flags & SHF_MERGE)) + return typeConstant; + if (flags == SHF_WRITE) + return typeData; + return typeCode; + } + if (_section->sh_type == SHT_NOTE) { + flags &= ~SHF_ALLOC; + return (flags == SHF_WRITE) ? typeRWNote : typeRONote; + } + if (_section->sh_type == SHT_NOBITS) + return typeZeroFill; + + if (_section->sh_type == SHT_NULL) + if (_symbol->getType() == STT_COMMON || _symbol->st_shndx == SHN_COMMON) + return typeZeroFill; + + if (_section->sh_type == SHT_INIT_ARRAY || + _section->sh_type == SHT_FINI_ARRAY) + return typeData; + return typeUnknown; +} + +template <class ELFT> +DefinedAtom::ContentType ELFDefinedAtom<ELFT>::contentType() const { + if (_contentType != typeUnknown) + return _contentType; + _contentType = doContentType(); + return _contentType; +} + +template <class ELFT> +DefinedAtom::Alignment ELFDefinedAtom<ELFT>::alignment() const { + if (!_symbol) + return 1; + + // Obtain proper value of st_value field. + const auto symValue = getSymbolValue(); + + // 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 symValue; + } + if (_section->sh_addralign == 0) { + // sh_addralign of 0 means no alignment + return Alignment(1, symValue); + } + return Alignment(_section->sh_addralign, symValue % _section->sh_addralign); +} + +// Do we have a choice for ELF? All symbols live in explicit sections. +template <class ELFT> +DefinedAtom::SectionChoice ELFDefinedAtom<ELFT>::sectionChoice() const { + 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; +} + +template <class ELFT> +StringRef ELFDefinedAtom<ELFT>::customSectionName() const { + if ((contentType() == typeZeroFill) || + (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON)) + return ".bss"; + return _sectionName; +} + +template <class ELFT> +DefinedAtom::ContentPermissions ELFDefinedAtom<ELFT>::permissions() const { + 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___; + } +} + +template <class ELFT> +DefinedAtom::reference_iterator ELFDefinedAtom<ELFT>::begin() const { + uintptr_t index = _referenceStartIndex; + const void *it = reinterpret_cast<const void *>(index); + return reference_iterator(*this, it); +} + +template <class ELFT> +DefinedAtom::reference_iterator ELFDefinedAtom<ELFT>::end() const { + uintptr_t index = _referenceEndIndex; + const void *it = reinterpret_cast<const void *>(index); + return reference_iterator(*this, it); +} + +template <class ELFT> +const Reference *ELFDefinedAtom<ELFT>::derefIterator(const void *It) const { + uintptr_t index = reinterpret_cast<uintptr_t>(It); + assert(index >= _referenceStartIndex); + assert(index < _referenceEndIndex); + return ((_referenceList)[index]); +} + +template <class ELFT> +void ELFDefinedAtom<ELFT>::incrementIterator(const void *&It) const { + uintptr_t index = reinterpret_cast<uintptr_t>(It); + ++index; + It = reinterpret_cast<const void *>(index); +} + +template <class ELFT> +void ELFDefinedAtom<ELFT>::addReference(ELFReference<ELFT> *reference) { + _referenceList.push_back(reference); + _referenceEndIndex = _referenceList.size(); +} + +template <class ELFT> AbsoluteAtom::Scope ELFDynamicAtom<ELFT>::scope() const { + if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) + return scopeLinkageUnit; + if (_symbol->getBinding() != llvm::ELF::STB_LOCAL) + return scopeGlobal; + return scopeTranslationUnit; +} + +template <class ELFT> +SharedLibraryAtom::Type ELFDynamicAtom<ELFT>::type() const { + 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; + } +} + +#define INSTANTIATE(klass) \ + template class klass<ELF32LE>; \ + template class klass<ELF32BE>; \ + template class klass<ELF64LE>; \ + template class klass<ELF64BE> + +INSTANTIATE(ELFAbsoluteAtom); +INSTANTIATE(ELFDefinedAtom); +INSTANTIATE(ELFDynamicAtom); +INSTANTIATE(ELFUndefinedAtom); + +} // end namespace elf +} // end namespace lld |
