//===- 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 AbsoluteAtom::Scope ELFAbsoluteAtom::scope() const { if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) return scopeLinkageUnit; if (_symbol->getBinding() == llvm::ELF::STB_LOCAL) return scopeTranslationUnit; return scopeGlobal; } template UndefinedAtom::CanBeNull ELFUndefinedAtom::canBeNull() const { if (_symbol->getBinding() == llvm::ELF::STB_WEAK) return CanBeNull::canBeNullAtBuildtime; return CanBeNull::canBeNullNever; } template uint64_t ELFDefinedAtom::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 AbsoluteAtom::Scope ELFDefinedAtom::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 DefinedAtom::Merge ELFDefinedAtom::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 DefinedAtom::ContentType ELFDefinedAtom::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 DefinedAtom::ContentType ELFDefinedAtom::contentType() const { if (_contentType != typeUnknown) return _contentType; _contentType = doContentType(); return _contentType; } template DefinedAtom::Alignment ELFDefinedAtom::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 DefinedAtom::SectionChoice ELFDefinedAtom::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 StringRef ELFDefinedAtom::customSectionName() const { if ((contentType() == typeZeroFill) || (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON)) return ".bss"; return _sectionName; } template DefinedAtom::ContentPermissions ELFDefinedAtom::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 DefinedAtom::reference_iterator ELFDefinedAtom::begin() const { uintptr_t index = _referenceStartIndex; const void *it = reinterpret_cast(index); return reference_iterator(*this, it); } template DefinedAtom::reference_iterator ELFDefinedAtom::end() const { uintptr_t index = _referenceEndIndex; const void *it = reinterpret_cast(index); return reference_iterator(*this, it); } template const Reference *ELFDefinedAtom::derefIterator(const void *It) const { uintptr_t index = reinterpret_cast(It); assert(index >= _referenceStartIndex); assert(index < _referenceEndIndex); return ((_referenceList)[index]); } template void ELFDefinedAtom::incrementIterator(const void *&It) const { uintptr_t index = reinterpret_cast(It); ++index; It = reinterpret_cast(index); } template void ELFDefinedAtom::addReference(ELFReference *reference) { _referenceList.push_back(reference); _referenceEndIndex = _referenceList.size(); } template AbsoluteAtom::Scope ELFDynamicAtom::scope() const { if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN) return scopeLinkageUnit; if (_symbol->getBinding() != llvm::ELF::STB_LOCAL) return scopeGlobal; return scopeTranslationUnit; } template SharedLibraryAtom::Type ELFDynamicAtom::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; \ template class klass; \ template class klass; \ template class klass INSTANTIATE(ELFAbsoluteAtom); INSTANTIATE(ELFDefinedAtom); INSTANTIATE(ELFDynamicAtom); INSTANTIATE(ELFUndefinedAtom); } // end namespace elf } // end namespace lld