Files
clang-p2996/lld/lib/ReaderWriter/ELF/Atoms.cpp
Leny Kholodov bde4144338 [ARM] Generation of .ARM.exidx/.ARM.extab sections
This patch provides generation of .ARM.exidx & .ARM.extab sections which are
used for unwinding. The patch adds new content type typeARMExidx for atoms from
.ARM.exidx section and integration of atoms with such type to the ELF
ReaderWriter. exidx.test has been added with checking of contents of .ARM.exidx
section and .ARM.extab section.

Differential Revision: http://reviews.llvm.org/D9324

llvm-svn: 236873
2015-05-08 16:04:11 +00:00

298 lines
8.6 KiB
C++

//===- 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))
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_ARM_EXIDX)
return typeARMExidx;
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_;
case llvm::ELF::SHT_ARM_EXIDX:
return _permissions = permR__;
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