diff options
Diffstat (limited to 'ELF/Symbols.cpp')
-rw-r--r-- | ELF/Symbols.cpp | 253 |
1 files changed, 71 insertions, 182 deletions
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index c69007e781a68..ab42fcd51a81b 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -8,15 +8,15 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" -#include "Error.h" #include "InputFiles.h" #include "InputSection.h" #include "OutputSections.h" -#include "Strings.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Path.h" #include <cstring> @@ -28,25 +28,23 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf; -DefinedRegular *ElfSym::Bss; -DefinedRegular *ElfSym::Etext1; -DefinedRegular *ElfSym::Etext2; -DefinedRegular *ElfSym::Edata1; -DefinedRegular *ElfSym::Edata2; -DefinedRegular *ElfSym::End1; -DefinedRegular *ElfSym::End2; -DefinedRegular *ElfSym::GlobalOffsetTable; -DefinedRegular *ElfSym::MipsGp; -DefinedRegular *ElfSym::MipsGpDisp; -DefinedRegular *ElfSym::MipsLocalGp; - -static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { - switch (Body.kind()) { - case SymbolBody::DefinedRegularKind: { - auto &D = cast<DefinedRegular>(Body); +Defined *ElfSym::Bss; +Defined *ElfSym::Etext1; +Defined *ElfSym::Etext2; +Defined *ElfSym::Edata1; +Defined *ElfSym::Edata2; +Defined *ElfSym::End1; +Defined *ElfSym::End2; +Defined *ElfSym::GlobalOffsetTable; +Defined *ElfSym::MipsGp; +Defined *ElfSym::MipsGpDisp; +Defined *ElfSym::MipsLocalGp; + +static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { + switch (Sym.kind()) { + case Symbol::DefinedKind: { + auto &D = cast<Defined>(Sym); SectionBase *IS = D.Section; - if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS)) - IS = ISB->Repl; // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule @@ -59,6 +57,7 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { if (!IS) return D.Value; + IS = IS->Repl; uint64_t Offset = D.Value; // An object in an SHF_MERGE section might be referenced via a @@ -99,139 +98,85 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { } return VA; } - case SymbolBody::DefinedCommonKind: - if (!Config->DefineCommon) - return 0; - return InX::Common->getParent()->Addr + InX::Common->OutSecOff + - cast<DefinedCommon>(Body).Offset; - case SymbolBody::SharedKind: { - auto &SS = cast<SharedSymbol>(Body); - if (SS.NeedsCopy) - return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff + - SS.CopyRelSecOff; + case Symbol::SharedKind: { + auto &SS = cast<SharedSymbol>(Sym); + if (SS.CopyRelSec) + return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff; if (SS.NeedsPltAddr) - return Body.getPltVA(); + return Sym.getPltVA(); return 0; } - case SymbolBody::UndefinedKind: + case Symbol::UndefinedKind: return 0; - case SymbolBody::LazyArchiveKind: - case SymbolBody::LazyObjectKind: - assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer"); + case Symbol::LazyArchiveKind: + case Symbol::LazyObjectKind: + assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer"); return 0; } llvm_unreachable("invalid symbol kind"); } -SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type) - : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal), - IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} - -// Returns true if a symbol can be replaced at load-time by a symbol -// with the same name defined in other ELF executable or DSO. -bool SymbolBody::isPreemptible() const { - if (isLocal()) - return false; - - // Shared symbols resolve to the definition in the DSO. The exceptions are - // symbols with copy relocations (which resolve to .bss) or preempt plt - // entries (which resolve to that plt entry). - if (isShared()) - return !NeedsCopy && !NeedsPltAddr; - - // That's all that can be preempted in a non-DSO. - if (!Config->Shared) - return false; - - // Only symbols that appear in dynsym can be preempted. - if (!symbol()->includeInDynsym()) - return false; - - // Only default visibility symbols can be preempted. - if (symbol()->Visibility != STV_DEFAULT) - return false; - - // -Bsymbolic means that definitions are not preempted. - if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc())) - return !isDefined(); - return true; -} - -// Overwrites all attributes with Other's so that this symbol becomes -// an alias to Other. This is useful for handling some options such as -// --wrap. -void SymbolBody::copy(SymbolBody *Other) { - memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer, - sizeof(Symbol::Body)); +// Returns true if this is a weak undefined symbol. +bool Symbol::isUndefWeak() const { + // See comment on Lazy in Symbols.h for the details. + return isWeak() && (isUndefined() || isLazy()); } -uint64_t SymbolBody::getVA(int64_t Addend) const { +uint64_t Symbol::getVA(int64_t Addend) const { uint64_t OutVA = getSymVA(*this, Addend); return OutVA + Addend; } -uint64_t SymbolBody::getGotVA() const { - return InX::Got->getVA() + getGotOffset(); -} +uint64_t Symbol::getGotVA() const { return InX::Got->getVA() + getGotOffset(); } -uint64_t SymbolBody::getGotOffset() const { +uint64_t Symbol::getGotOffset() const { return GotIndex * Target->GotEntrySize; } -uint64_t SymbolBody::getGotPltVA() const { +uint64_t Symbol::getGotPltVA() const { if (this->IsInIgot) return InX::IgotPlt->getVA() + getGotPltOffset(); return InX::GotPlt->getVA() + getGotPltOffset(); } -uint64_t SymbolBody::getGotPltOffset() const { +uint64_t Symbol::getGotPltOffset() const { return GotPltIndex * Target->GotPltEntrySize; } -uint64_t SymbolBody::getPltVA() const { +uint64_t Symbol::getPltVA() const { if (this->IsInIplt) return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize; return InX::Plt->getVA() + Target->PltHeaderSize + PltIndex * Target->PltEntrySize; } -template <class ELFT> typename ELFT::uint SymbolBody::getSize() const { - if (const auto *C = dyn_cast<DefinedCommon>(this)) - return C->Size; - if (const auto *DR = dyn_cast<DefinedRegular>(this)) +uint64_t Symbol::getSize() const { + if (const auto *DR = dyn_cast<Defined>(this)) return DR->Size; if (const auto *S = dyn_cast<SharedSymbol>(this)) - return S->getSize<ELFT>(); + return S->Size; return 0; } -OutputSection *SymbolBody::getOutputSection() const { - if (auto *S = dyn_cast<DefinedRegular>(this)) { - if (S->Section) - return S->Section->getOutputSection(); +OutputSection *Symbol::getOutputSection() const { + if (auto *S = dyn_cast<Defined>(this)) { + if (auto *Sec = S->Section) + return Sec->Repl->getOutputSection(); return nullptr; } if (auto *S = dyn_cast<SharedSymbol>(this)) { - if (S->NeedsCopy) + if (S->CopyRelSec) return S->CopyRelSec->getParent(); return nullptr; } - if (isa<DefinedCommon>(this)) { - if (Config->DefineCommon) - return InX::Common->getParent(); - return nullptr; - } - return nullptr; } // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. -void SymbolBody::parseSymbolVersion() { +void Symbol::parseSymbolVersion() { StringRef S = getName(); size_t Pos = S.find('@'); if (Pos == 0 || Pos == StringRef::npos) @@ -244,7 +189,7 @@ void SymbolBody::parseSymbolVersion() { Name = {S.data(), Pos}; // If this is not in this DSO, it is not a definition. - if (!isInCurrentDSO()) + if (!isDefined()) return; // '@@' in a symbol name means the default version. @@ -258,9 +203,9 @@ void SymbolBody::parseSymbolVersion() { continue; if (IsDefault) - symbol()->VersionId = Ver.Id; + VersionId = Ver.Id; else - symbol()->VersionId = Ver.Id | VERSYM_HIDDEN; + VersionId = Ver.Id | VERSYM_HIDDEN; return; } @@ -273,81 +218,34 @@ void SymbolBody::parseSymbolVersion() { Verstr); } -Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type) - : SymbolBody(K, Name, IsLocal, StOther, Type) {} - -template <class ELFT> bool DefinedRegular::isMipsPIC() const { - typedef typename ELFT::Ehdr Elf_Ehdr; - if (!Section || !isFunc()) - return false; - - auto *Sec = cast<InputSectionBase>(Section); - const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader(); - return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || - (Hdr->e_flags & EF_MIPS_PIC); -} - -Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type, InputFile *File) - : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) { - this->File = File; -} - -DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment, - uint8_t StOther, uint8_t Type, InputFile *File) - : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, - Type), - Alignment(Alignment), Size(Size) { - this->File = File; -} - -// If a shared symbol is referred via a copy relocation, its alignment -// becomes part of the ABI. This function returns a symbol alignment. -// Because symbols don't have alignment attributes, we need to infer that. -template <class ELFT> uint32_t SharedSymbol::getAlignment() const { - auto *File = cast<SharedFile<ELFT>>(this->File); - uint32_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign; - uint64_t SymValue = getSym<ELFT>().st_value; - uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue); - return std::min(SecAlign, SymAlign); -} - InputFile *Lazy::fetch() { if (auto *S = dyn_cast<LazyArchive>(this)) return S->fetch(); return cast<LazyObject>(this)->fetch(); } -LazyArchive::LazyArchive(ArchiveFile &File, - const llvm::object::Archive::Symbol S, uint8_t Type) - : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) { - this->File = &File; -} - -LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type) - : Lazy(LazyObjectKind, Name, Type) { - this->File = &File; -} +ArchiveFile *LazyArchive::getFile() { return cast<ArchiveFile>(File); } InputFile *LazyArchive::fetch() { - std::pair<MemoryBufferRef, uint64_t> MBInfo = file()->getMember(&Sym); + std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile()->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBInfo.first.getBuffer().empty()) return nullptr; - return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second); + return createObjectFile(MBInfo.first, getFile()->getName(), MBInfo.second); } -InputFile *LazyObject::fetch() { return file()->fetch(); } +LazyObjFile *LazyObject::getFile() { return cast<LazyObjFile>(File); } + +InputFile *LazyObject::fetch() { return getFile()->fetch(); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; - if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO()) + if (VersionId == VER_NDX_LOCAL && isDefined()) return STB_LOCAL; if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; @@ -355,45 +253,36 @@ uint8_t Symbol::computeBinding() const { } bool Symbol::includeInDynsym() const { + if (!Config->HasDynSymTab) + return false; if (computeBinding() == STB_LOCAL) return false; - return ExportDynamic || body()->isShared() || - (body()->isUndefined() && Config->Shared); + if (!isDefined()) + return true; + return ExportDynamic; } // Print out a log message for --trace-symbol. void elf::printTraceSymbol(Symbol *Sym) { - SymbolBody *B = Sym->body(); std::string S; - if (B->isUndefined()) + if (Sym->isUndefined()) S = ": reference to "; - else if (B->isCommon()) + else if (Sym->isLazy()) + S = ": lazy definition of "; + else if (Sym->isShared()) + S = ": shared definition of "; + else if (dyn_cast_or_null<BssSection>(cast<Defined>(Sym)->Section)) S = ": common definition of "; else S = ": definition of "; - message(toString(B->File) + S + B->getName()); + message(toString(Sym->File) + S + Sym->getName()); } // Returns a symbol for an error message. -std::string lld::toString(const SymbolBody &B) { +std::string lld::toString(const Symbol &B) { if (Config->Demangle) - if (Optional<std::string> S = demangle(B.getName())) + if (Optional<std::string> S = demangleItanium(B.getName())) return *S; return B.getName(); } - -template uint32_t SymbolBody::template getSize<ELF32LE>() const; -template uint32_t SymbolBody::template getSize<ELF32BE>() const; -template uint64_t SymbolBody::template getSize<ELF64LE>() const; -template uint64_t SymbolBody::template getSize<ELF64BE>() const; - -template bool DefinedRegular::template isMipsPIC<ELF32LE>() const; -template bool DefinedRegular::template isMipsPIC<ELF32BE>() const; -template bool DefinedRegular::template isMipsPIC<ELF64LE>() const; -template bool DefinedRegular::template isMipsPIC<ELF64BE>() const; - -template uint32_t SharedSymbol::template getAlignment<ELF32LE>() const; -template uint32_t SharedSymbol::template getAlignment<ELF32BE>() const; -template uint32_t SharedSymbol::template getAlignment<ELF64LE>() const; -template uint32_t SharedSymbol::template getAlignment<ELF64BE>() const; |