From: Rui Ueyama Date: Tue, 31 Oct 2017 16:07:41 +0000 (+0000) Subject: Merge SymbolBody and Symbol into one class, SymbolBody. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f1f00841d9846acbdd4a4f7f8a1c60bb3079541d;p=platform%2Fupstream%2Fllvm.git Merge SymbolBody and Symbol into one class, SymbolBody. SymbolBody and Symbol were separated classes due to a historical reason. Symbol used to be a pointer to a SymbolBody, and the relationship between Symbol and SymbolBody was n:1. r2681780 changed that. Since that patch, SymbolBody and Symbol are allocated next to each other to improve memory locality, and they have 1:1 relationship now. So, the separation of Symbol and SymbolBody no longer makes sense. This patch merges them into one class. In order to avoid updating too many places, I chose SymbolBody as a unified name. I'll rename it Symbol in a follow-up patch. Differential Revision: https://reviews.llvm.org/D39406 llvm-svn: 317006 --- diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 314e70a..d4b8510 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -24,7 +24,6 @@ namespace lld { namespace elf { class InputFile; -struct Symbol; enum ELFKind { ELFNoneKind, diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index d60d39e..ce7d4a3 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -997,13 +997,12 @@ static void excludeLibs(opt::InputArgList &Args, ArrayRef Files) { DenseSet Libs = getExcludeLibs(Args); bool All = Libs.count("ALL"); - for (InputFile *File : Files) { + for (InputFile *File : Files) if (Optional Archive = getArchiveName(File)) if (All || Libs.count(path::filename(*Archive))) - for (SymbolBody *SymBody : File->getSymbols()) - if (!SymBody->isLocal()) - SymBody->symbol()->VersionId = VER_NDX_LOCAL; - } + for (SymbolBody *Sym : File->getSymbols()) + if (!Sym->isLocal()) + Sym->VersionId = VER_NDX_LOCAL; } // Do actual linking. Note that when this function is called, diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index f68911a..e1cc2fe 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -551,16 +551,14 @@ SymbolBody *ObjFile::createSymbolBody(const Elf_Sym *Sym) { switch (Sym->st_shndx) { case SHN_UNDEF: - return Symtab - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); + return Symtab->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, + Type, + /*CanOmitFromDynSym=*/false, this); case SHN_COMMON: if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); - return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this) - ->body(); + return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this); } switch (Binding) { @@ -570,13 +568,11 @@ SymbolBody *ObjFile::createSymbolBody(const Elf_Sym *Sym) { case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) - return Symtab - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); - return Symtab - ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this) - ->body(); + return Symtab->addUndefined(Name, /*IsLocal=*/false, Binding, + StOther, Type, + /*CanOmitFromDynSym=*/false, this); + return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, + Sec, this); } } @@ -587,8 +583,7 @@ ArchiveFile::ArchiveFile(std::unique_ptr &&File) template void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symbols.push_back( - Symtab->addLazyArchive(Sym.getName(), this, Sym)->body()); + Symbols.push_back(Symtab->addLazyArchive(Sym.getName(), this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. @@ -848,9 +843,9 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { } template -static Symbol *createBitcodeSymbol(const std::vector &KeptComdats, - const lto::InputFile::Symbol &ObjSym, - BitcodeFile *F) { +static SymbolBody *createBitcodeSymbol(const std::vector &KeptComdats, + const lto::InputFile::Symbol &ObjSym, + BitcodeFile *F) { StringRef NameRef = Saver.save(ObjSym.getName()); uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; @@ -883,8 +878,7 @@ void BitcodeFile::parse(DenseSet &ComdatGroups) { KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) - Symbols.push_back( - createBitcodeSymbol(KeptComdats, ObjSym, this)->body()); + Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, this)); } static ELFKind getELFKind(MemoryBufferRef MB) { diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 55877df..d0da8c8 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -108,8 +108,8 @@ static std::unique_ptr createLTO() { } BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) { - for (Symbol *Sym : Symtab->getSymbols()) { - StringRef Name = Sym->body()->getName(); + for (SymbolBody *Sym : Symtab->getSymbols()) { + StringRef Name = Sym->getName(); for (StringRef Prefix : {"__start_", "__stop_"}) if (Name.startswith(Prefix)) UsedStartStop.insert(Name.substr(Prefix.size())); @@ -118,9 +118,9 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) { BitcodeCompiler::~BitcodeCompiler() = default; -static void undefine(Symbol *S) { - replaceBody(S, nullptr, S->body()->getName(), /*IsLocal=*/false, - STV_DEFAULT, S->body()->Type); +static void undefine(SymbolBody *S) { + replaceBody(S, nullptr, S->getName(), /*IsLocal=*/false, + STV_DEFAULT, S->Type); } void BitcodeCompiler::add(BitcodeFile &F) { @@ -136,8 +136,7 @@ void BitcodeCompiler::add(BitcodeFile &F) { // Provide a resolution to the LTO API for each symbol. for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { - SymbolBody *B = Syms[SymNum]; - Symbol *Sym = B->symbol(); + SymbolBody *Sym = Syms[SymNum]; lto::SymbolResolution &R = Resols[SymNum]; ++SymNum; @@ -146,7 +145,7 @@ void BitcodeCompiler::add(BitcodeFile &F) { // flags an undefined in IR with a definition in ASM as prevailing. // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. - R.Prevailing = !ObjSym.isUndefined() && B->getFile() == &F; + R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F; // We ask LTO to preserve following global symbols: // 1) All symbols when doing relocatable link, so that them can be used @@ -165,7 +164,7 @@ void BitcodeCompiler::add(BitcodeFile &F) { // still not final: // 1) Aliased (with --defsym) or wrapped (with --wrap) symbols. // 2) Symbols redefined in linker script. - R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(B->getName()); + R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(Sym->getName()); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index e8c377c..29a5837 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -127,7 +127,7 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) { return; // Define a symbol. - Symbol *Sym; + SymbolBody *Sym; uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false, @@ -151,7 +151,7 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) { replaceBody(Sym, nullptr, Cmd->Name, /*IsLocal=*/false, Visibility, STT_NOTYPE, SymValue, 0, Sec); - Cmd->Sym = cast(Sym->body()); + Cmd->Sym = cast(Sym); } // This function is called from assignAddresses, while we are diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index b585f7e..adc4c55 100644 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -228,9 +228,9 @@ template static void doGcSections() { // Preserve externally-visible symbols if the symbols defined by this // file can interrupt other ELF file's symbols at runtime. - for (Symbol *S : Symtab->getSymbols()) + for (SymbolBody *S : Symtab->getSymbols()) if (S->includeInDynsym()) - MarkSymbol(S->body()); + MarkSymbol(S); // Preserve special sections and those which are specified in linker // script KEEP command. diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 31ff4fe..67a42ed 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -544,7 +544,7 @@ template static void addCopyRelSymbol(SharedSymbol *SS) { for (SharedSymbol *Sym : getSymbolsAt(SS)) { Sym->CopyRelSec = Sec; Sym->IsPreemptible = false; - Sym->symbol()->IsUsedInRegularObj = true; + Sym->IsUsedInRegularObj = true; } In::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0}); @@ -717,11 +717,11 @@ static bool maybeReportUndefined(SymbolBody &Sym, InputSectionBase &Sec, if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) return false; - if (Sym.isLocal() || !Sym.isUndefined() || Sym.symbol()->isWeak()) + if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak()) return false; - bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL && - Sym.getVisibility() == STV_DEFAULT; + bool CanBeExternal = + Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT; if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) return false; diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 8ad2a73..83fd2de 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -136,9 +136,9 @@ template void SymbolTable::addCombinedLTOObject() { template DefinedRegular *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility, uint8_t Binding) { - Symbol *Sym = addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, - nullptr, nullptr); - return cast(Sym->body()); + SymbolBody *Sym = addRegular(Name, Visibility, STT_NOTYPE, 0, 0, + Binding, nullptr, nullptr); + return cast(Sym); } // Set a flag for --trace-symbol so that we can print out a log message @@ -150,12 +150,11 @@ void SymbolTable::trace(StringRef Name) { // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template void SymbolTable::addSymbolWrap(StringRef Name) { - SymbolBody *B = find(Name); - if (!B) + SymbolBody *Sym = find(Name); + if (!Sym) return; - Symbol *Sym = B->symbol(); - Symbol *Real = addUndefined(Saver.save("__real_" + Name)); - Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); + SymbolBody *Real = addUndefined(Saver.save("__real_" + Name)); + SymbolBody *Wrap = addUndefined(Saver.save("__wrap_" + Name)); defsym(Real, Sym); defsym(Sym, Wrap); @@ -172,7 +171,7 @@ void SymbolTable::addSymbolAlias(StringRef Alias, StringRef Name) { return; } - defsym(addUndefined(Alias), B->symbol()); + defsym(addUndefined(Alias), B); } // Apply symbol renames created by -wrap and -defsym. The renames are created @@ -190,13 +189,13 @@ void SymbolTable::applySymbolRenames() { // __wrap_foo point to, we just want have __real_foo in the symbol table. // First make a copy of __real_foo - std::vector Origs; + std::vector Origs; for (const auto &P : WrapSymbols) - Origs.push_back(*P.second); + Origs.emplace_back(*(SymbolUnion *)P.second); // Replace __real_foo with foo and foo with __wrap_foo for (SymbolRenaming &S : Defsyms) { - S.Dst->body()->copyFrom(S.Src->body()); + S.Dst->copyFrom(S.Src); S.Dst->File = S.Src->File; S.Dst->Binding = S.Binding; } @@ -205,16 +204,16 @@ void SymbolTable::applySymbolRenames() { // __real_foo into it. for (unsigned I = 0, N = WrapSymbols.size(); I < N; ++I) { // We now have two copies of __wrap_foo. Drop one. - Symbol *Wrap = WrapSymbols[I].first; + SymbolBody *Wrap = WrapSymbols[I].first; Wrap->IsUsedInRegularObj = false; - Symbol *Real = &Origs[I]; + auto *Real = (SymbolBody *)&Origs[I]; // If __real_foo was undefined, we don't want it in the symbol table. - if (!Real->body()->isInCurrentOutput()) + if (!Real->isInCurrentOutput()) continue; - auto *NewSym = make(); - memcpy(NewSym, Real, sizeof(Symbol)); + auto *NewSym = (SymbolBody *)make(); + memcpy(NewSym, Real, sizeof(SymbolUnion)); SymVector.push_back(NewSym); } } @@ -228,7 +227,7 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { } // Find an existing symbol or create and insert a new one. -std::pair SymbolTable::insert(StringRef Name) { +std::pair SymbolTable::insert(StringRef Name) { // @@ means the symbol is the default version. In that // case @@ will be used to resolve references to . // @@ -249,9 +248,9 @@ std::pair SymbolTable::insert(StringRef Name) { V = SymIndex((int)SymVector.size(), true); } - Symbol *Sym; + SymbolBody *Sym; if (IsNew) { - Sym = make(); + Sym = (SymbolBody *)make(); Sym->InVersionScript = false; Sym->Binding = STB_WEAK; Sym->Visibility = STV_DEFAULT; @@ -269,11 +268,11 @@ std::pair SymbolTable::insert(StringRef Name) { // Find an existing symbol or create and insert a new one, then apply the given // attributes. -std::pair SymbolTable::insert(StringRef Name, uint8_t Type, - uint8_t Visibility, - bool CanOmitFromDynSym, - InputFile *File) { - Symbol *S; +std::pair SymbolTable::insert(StringRef Name, uint8_t Type, + uint8_t Visibility, + bool CanOmitFromDynSym, + InputFile *File) { + SymbolBody *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); @@ -286,17 +285,16 @@ std::pair SymbolTable::insert(StringRef Name, uint8_t Type, if (!File || File->kind() == InputFile::ObjKind) S->IsUsedInRegularObj = true; - if (!WasInserted && S->body()->Type != SymbolBody::UnknownType && - ((Type == STT_TLS) != S->body()->isTls())) { - error("TLS attribute mismatch: " + toString(*S->body()) + - "\n>>> defined in " + toString(S->File) + "\n>>> defined in " + - toString(File)); + if (!WasInserted && S->Type != SymbolBody::UnknownType && + ((Type == STT_TLS) != S->isTls())) { + error("TLS attribute mismatch: " + toString(*S) + "\n>>> defined in " + + toString(S->File) + "\n>>> defined in " + toString(File)); } return {S, WasInserted}; } -template Symbol *SymbolTable::addUndefined(StringRef Name) { +template SymbolBody *SymbolTable::addUndefined(StringRef Name) { return addUndefined(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0, /*CanOmitFromDynSym*/ false, /*File*/ nullptr); @@ -305,30 +303,29 @@ template Symbol *SymbolTable::addUndefined(StringRef Name) { static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; } template -Symbol *SymbolTable::addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, - uint8_t StOther, uint8_t Type, - bool CanOmitFromDynSym, InputFile *File) { - Symbol *S; +SymbolBody *SymbolTable::addUndefined(StringRef Name, bool IsLocal, + uint8_t Binding, uint8_t StOther, + uint8_t Type, bool CanOmitFromDynSym, + InputFile *File) { + SymbolBody *S; bool WasInserted; uint8_t Visibility = getVisibility(StOther); std::tie(S, WasInserted) = insert(Name, Type, Visibility, CanOmitFromDynSym, File); // An undefined symbol with non default visibility must be satisfied // in the same DSO. - if (WasInserted || - (isa(S->body()) && Visibility != STV_DEFAULT)) { + if (WasInserted || (isa(S) && Visibility != STV_DEFAULT)) { S->Binding = Binding; replaceBody(S, File, Name, IsLocal, StOther, Type); return S; } if (Binding != STB_WEAK) { - SymbolBody *B = S->body(); - if (!B->isInCurrentOutput()) + if (!S->isInCurrentOutput()) S->Binding = Binding; - if (auto *SS = dyn_cast(B)) + if (auto *SS = dyn_cast(S)) SS->getFile()->IsUsed = true; } - if (auto *L = dyn_cast(S->body())) { + if (auto *L = dyn_cast(S)) { // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. if (S->isWeak()) @@ -345,9 +342,9 @@ Symbol *SymbolTable::addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, // FIXME: If users can transition to using // .symver foo,foo@@@VER // we can delete this hack. -static int compareVersion(Symbol *S, StringRef Name) { +static int compareVersion(SymbolBody *S, StringRef Name) { bool A = Name.contains("@@"); - bool B = S->body()->getName().contains("@@"); + bool B = S->getName().contains("@@"); if (A && !B) return 1; if (!A && B) @@ -358,17 +355,14 @@ static int compareVersion(Symbol *S, StringRef Name) { // We have a new defined symbol with the specified binding. Return 1 if the new // symbol should win, -1 if the new symbol should lose, or 0 if both symbols are // strong defined symbols. -static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, +static int compareDefined(SymbolBody *S, bool WasInserted, uint8_t Binding, StringRef Name) { if (WasInserted) return 1; - SymbolBody *Body = S->body(); - if (!Body->isInCurrentOutput()) + if (!S->isInCurrentOutput()) return 1; - if (int R = compareVersion(S, Name)) return R; - if (Binding == STB_WEAK) return -1; if (S->isWeak()) @@ -379,21 +373,21 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, // We have a new non-common defined symbol with the specified binding. Return 1 // if the new symbol should win, -1 if the new symbol should lose, or 0 if there // is a conflict. If the new symbol wins, also update the binding. -static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, - bool IsAbsolute, uint64_t Value, - StringRef Name) { +static int compareDefinedNonCommon(SymbolBody *S, bool WasInserted, + uint8_t Binding, bool IsAbsolute, + uint64_t Value, StringRef Name) { if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) { if (Cmp > 0) S->Binding = Binding; return Cmp; } - SymbolBody *B = S->body(); - if (isa(B)) { + if (isa(S)) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) - warn("common " + S->body()->getName() + " is overridden"); + warn("common " + S->getName() + " is overridden"); return 1; - } else if (auto *R = dyn_cast(B)) { + } + if (auto *R = dyn_cast(S)) { if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && R->Value == Value) return -1; @@ -401,10 +395,11 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, return 0; } -Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, - uint8_t Binding, uint8_t StOther, uint8_t Type, - InputFile *File) { - Symbol *S; +SymbolBody *SymbolTable::addCommon(StringRef N, uint64_t Size, + uint32_t Alignment, uint8_t Binding, + uint8_t StOther, uint8_t Type, + InputFile *File) { + SymbolBody *S; bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); @@ -413,16 +408,16 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, S->Binding = Binding; replaceBody(S, File, N, Size, Alignment, StOther, Type); } else if (Cmp == 0) { - auto *C = dyn_cast(S->body()); + auto *C = dyn_cast(S); if (!C) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) - warn("common " + S->body()->getName() + " is overridden"); + warn("common " + S->getName() + " is overridden"); return S; } if (Config->WarnCommon) - warn("multiple common of " + S->body()->getName()); + warn("multiple common of " + S->getName()); Alignment = C->Alignment = std::max(C->Alignment, Alignment); if (Size > C->Size) @@ -477,10 +472,11 @@ static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec, } template -Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, - uint64_t Value, uint64_t Size, uint8_t Binding, - SectionBase *Section, InputFile *File) { - Symbol *S; +SymbolBody *SymbolTable::addRegular(StringRef Name, uint8_t StOther, + uint8_t Type, uint64_t Value, uint64_t Size, + uint8_t Binding, SectionBase *Section, + InputFile *File) { + SymbolBody *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); @@ -490,8 +486,8 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, replaceBody(S, File, Name, /*IsLocal=*/false, StOther, Type, Value, Size, Section); else if (Cmp == 0) - reportDuplicate(S->body(), - dyn_cast_or_null(Section), Value); + reportDuplicate(S, dyn_cast_or_null(Section), + Value); return S; } @@ -502,7 +498,7 @@ void SymbolTable::addShared(StringRef Name, SharedFile *File, // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT // as the visibility, which will leave the visibility in the symbol table // unchanged. - Symbol *S; + SymbolBody *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, File); @@ -510,11 +506,10 @@ void SymbolTable::addShared(StringRef Name, SharedFile *File, if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; - SymbolBody *Body = S->body(); // An undefined symbol with non default visibility must be satisfied // in the same DSO. - if (WasInserted || ((Body->isUndefined() || Body->isLazy()) && - Body->getVisibility() == STV_DEFAULT)) { + if (WasInserted || ((S->isUndefined() || S->isLazy()) && + S->getVisibility() == STV_DEFAULT)) { replaceBody(S, File, Name, Sym.st_other, Sym.getType(), Sym.st_value, Sym.st_size, Alignment, Verdef); if (!S->isWeak()) @@ -522,10 +517,10 @@ void SymbolTable::addShared(StringRef Name, SharedFile *File, } } -Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, - uint8_t StOther, uint8_t Type, - bool CanOmitFromDynSym, BitcodeFile *F) { - Symbol *S; +SymbolBody *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, + uint8_t StOther, uint8_t Type, + bool CanOmitFromDynSym, BitcodeFile *F) { + SymbolBody *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); @@ -535,7 +530,7 @@ Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, replaceBody(S, F, Name, /*IsLocal=*/false, StOther, Type, 0, 0, nullptr); else if (Cmp == 0) - reportDuplicate(S->body(), F); + reportDuplicate(S, F); return S; } @@ -546,10 +541,10 @@ SymbolBody *SymbolTable::find(StringRef Name) { SymIndex V = It->second; if (V.Idx == -1) return nullptr; - return SymVector[V.Idx]->body(); + return SymVector[V.Idx]; } -void SymbolTable::defsym(Symbol *Dst, Symbol *Src) { +void SymbolTable::defsym(SymbolBody *Dst, SymbolBody *Src) { // We want to tell LTO not to inline Dst symbol because LTO doesn't // know the final symbol contents after renaming. Dst->CanInline = false; @@ -561,22 +556,22 @@ void SymbolTable::defsym(Symbol *Dst, Symbol *Src) { } template -Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, - const object::Archive::Symbol Sym) { - Symbol *S; +SymbolBody *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, + const object::Archive::Symbol Sym) { + SymbolBody *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody(S, F, Sym, SymbolBody::UnknownType); return S; } - if (!S->body()->isUndefined()) + if (!S->isUndefined()) return S; // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. if (S->isWeak()) { - replaceBody(S, F, Sym, S->body()->Type); + replaceBody(S, F, Sym, S->Type); return S; } std::pair MBInfo = F->getMember(&Sym); @@ -587,19 +582,19 @@ Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, template void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { - Symbol *S; + SymbolBody *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody(S, &Obj, Name, SymbolBody::UnknownType); return; } - if (!S->body()->isUndefined()) + if (!S->isUndefined()) return; // See comment for addLazyArchive above. if (S->isWeak()) - replaceBody(S, &Obj, Name, S->body()->Type); + replaceBody(S, &Obj, Name, S->Type); else if (InputFile *F = Obj.fetch()) addFile(F); } @@ -609,7 +604,7 @@ template void SymbolTable::fetchIfLazy(StringRef Name) { if (SymbolBody *B = find(Name)) { // Mark the symbol not to be eliminated by LTO // even if it is a bitcode symbol. - B->symbol()->IsUsedInRegularObj = true; + B->IsUsedInRegularObj = true; if (auto *L = dyn_cast_or_null(B)) if (InputFile *File = L->fetch()) addFile(File); @@ -629,13 +624,13 @@ template void SymbolTable::scanShlibUndefined() { SymbolBody *Sym = find(U); if (!Sym || !Sym->isDefined()) continue; - Sym->symbol()->ExportDynamic = true; + Sym->ExportDynamic = true; // If -dynamic-list is given, the default version is set to // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym. // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were // specified by -dynamic-list. - Sym->symbol()->VersionId = VER_NDX_GLOBAL; + Sym->VersionId = VER_NDX_GLOBAL; } } } @@ -656,14 +651,13 @@ template void SymbolTable::scanShlibUndefined() { StringMap> &SymbolTable::getDemangledSyms() { if (!DemangledSyms) { DemangledSyms.emplace(); - for (Symbol *Sym : SymVector) { - SymbolBody *B = Sym->body(); - if (!B->isInCurrentOutput()) + for (SymbolBody *Sym : SymVector) { + if (!Sym->isInCurrentOutput()) continue; - if (Optional S = demangle(B->getName())) - (*DemangledSyms)[*S].push_back(B); + if (Optional S = demangle(Sym->getName())) + (*DemangledSyms)[*S].push_back(Sym); else - (*DemangledSyms)[B->getName()].push_back(B); + (*DemangledSyms)[Sym->getName()].push_back(Sym); } } return *DemangledSyms; @@ -689,11 +683,9 @@ std::vector SymbolTable::findAllByVersion(SymbolVersion Ver) { return Res; } - for (Symbol *Sym : SymVector) { - SymbolBody *B = Sym->body(); - if (B->isInCurrentOutput() && M.match(B->getName())) - Res.push_back(B); - } + for (SymbolBody *Sym : SymVector) + if (Sym->isInCurrentOutput() && M.match(Sym->getName())) + Res.push_back(Sym); return Res; } @@ -722,8 +714,8 @@ void SymbolTable::handleDynamicList() { for (SymbolBody *B : Syms) { if (!Config->Shared) - B->symbol()->ExportDynamic = true; - else if (B->symbol()->includeInDynsym()) + B->ExportDynamic = true; + else if (B->includeInDynsym()) B->IsPreemptible = true; } } @@ -746,14 +738,13 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, } // Assign the version. - for (SymbolBody *B : Syms) { + for (SymbolBody *Sym : Syms) { // Skip symbols containing version info because symbol versions // specified by symbol names take precedence over version scripts. // See parseSymbolVersion(). - if (B->getName().contains('@')) + if (Sym->getName().contains('@')) continue; - Symbol *Sym = B->symbol(); if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); Sym->VersionId = VersionId; @@ -769,8 +760,8 @@ void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. for (SymbolBody *B : findAllByVersion(Ver)) - if (B->symbol()->VersionId == Config->DefaultSymbolVersion) - B->symbol()->VersionId = VersionId; + if (B->VersionId == Config->DefaultSymbolVersion) + B->VersionId = VersionId; } // This function processes version scripts by updating VersionId @@ -801,8 +792,8 @@ void SymbolTable::scanVersionScript() { // Symbol themselves might know their versions because symbols // can contain versions in the form of @. // Let them parse and update their names to exclude version suffix. - for (Symbol *Sym : SymVector) - Sym->body()->parseSymbolVersion(); + for (SymbolBody *Sym : SymVector) + Sym->parseSymbolVersion(); } template void SymbolTable::addSymbolWrap(StringRef); @@ -810,23 +801,27 @@ template void SymbolTable::addSymbolWrap(StringRef); template void SymbolTable::addSymbolWrap(StringRef); template void SymbolTable::addSymbolWrap(StringRef); -template Symbol *SymbolTable::addUndefined(StringRef); -template Symbol *SymbolTable::addUndefined(StringRef); -template Symbol *SymbolTable::addUndefined(StringRef); -template Symbol *SymbolTable::addUndefined(StringRef); - -template Symbol *SymbolTable::addUndefined(StringRef, bool, uint8_t, - uint8_t, uint8_t, bool, - InputFile *); -template Symbol *SymbolTable::addUndefined(StringRef, bool, uint8_t, - uint8_t, uint8_t, bool, - InputFile *); -template Symbol *SymbolTable::addUndefined(StringRef, bool, uint8_t, - uint8_t, uint8_t, bool, - InputFile *); -template Symbol *SymbolTable::addUndefined(StringRef, bool, uint8_t, - uint8_t, uint8_t, bool, - InputFile *); +template SymbolBody *SymbolTable::addUndefined(StringRef); +template SymbolBody *SymbolTable::addUndefined(StringRef); +template SymbolBody *SymbolTable::addUndefined(StringRef); +template SymbolBody *SymbolTable::addUndefined(StringRef); + +template SymbolBody *SymbolTable::addUndefined(StringRef, bool, + uint8_t, uint8_t, + uint8_t, bool, + InputFile *); +template SymbolBody *SymbolTable::addUndefined(StringRef, bool, + uint8_t, uint8_t, + uint8_t, bool, + InputFile *); +template SymbolBody *SymbolTable::addUndefined(StringRef, bool, + uint8_t, uint8_t, + uint8_t, bool, + InputFile *); +template SymbolBody *SymbolTable::addUndefined(StringRef, bool, + uint8_t, uint8_t, + uint8_t, bool, + InputFile *); template void SymbolTable::addSymbolAlias(StringRef, StringRef); template void SymbolTable::addSymbolAlias(StringRef, StringRef); @@ -838,18 +833,18 @@ template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); -template Symbol *SymbolTable::addRegular(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); +template SymbolBody * +SymbolTable::addRegular(StringRef, uint8_t, uint8_t, uint64_t, + uint64_t, uint8_t, SectionBase *, InputFile *); +template SymbolBody * +SymbolTable::addRegular(StringRef, uint8_t, uint8_t, uint64_t, + uint64_t, uint8_t, SectionBase *, InputFile *); +template SymbolBody * +SymbolTable::addRegular(StringRef, uint8_t, uint8_t, uint64_t, + uint64_t, uint8_t, SectionBase *, InputFile *); +template SymbolBody * +SymbolTable::addRegular(StringRef, uint8_t, uint8_t, uint64_t, + uint64_t, uint8_t, SectionBase *, InputFile *); template DefinedRegular *SymbolTable::addAbsolute(StringRef, uint8_t, uint8_t); @@ -860,16 +855,16 @@ template DefinedRegular *SymbolTable::addAbsolute(StringRef, uint8_t, template DefinedRegular *SymbolTable::addAbsolute(StringRef, uint8_t, uint8_t); -template Symbol * +template SymbolBody * SymbolTable::addLazyArchive(StringRef, ArchiveFile *, const object::Archive::Symbol); -template Symbol * +template SymbolBody * SymbolTable::addLazyArchive(StringRef, ArchiveFile *, const object::Archive::Symbol); -template Symbol * +template SymbolBody * SymbolTable::addLazyArchive(StringRef, ArchiveFile *, const object::Archive::Symbol); -template Symbol * +template SymbolBody * SymbolTable::addLazyArchive(StringRef, ArchiveFile *, const object::Archive::Symbol); diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index e2acc47..ee48f70 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -19,8 +19,6 @@ namespace lld { namespace elf { -struct Symbol; - // SymbolTable is a bucket of all known symbols, including defined, // undefined, or lazy symbols (the last one is symbols in archive // files whose archive members are not yet loaded). @@ -41,22 +39,22 @@ public: template void addSymbolWrap(StringRef Name); void applySymbolRenames(); - ArrayRef getSymbols() const { return SymVector; } + ArrayRef getSymbols() const { return SymVector; } template DefinedRegular *addAbsolute(StringRef Name, uint8_t Visibility = llvm::ELF::STV_HIDDEN, uint8_t Binding = llvm::ELF::STB_GLOBAL); - template Symbol *addUndefined(StringRef Name); + template SymbolBody *addUndefined(StringRef Name); template - Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, - uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, - InputFile *File); + SymbolBody *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, + uint8_t StOther, uint8_t Type, + bool CanOmitFromDynSym, InputFile *File); template - Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type, - uint64_t Value, uint64_t Size, uint8_t Binding, - SectionBase *Section, InputFile *File); + SymbolBody *addRegular(StringRef Name, uint8_t StOther, uint8_t Type, + uint64_t Value, uint64_t Size, uint8_t Binding, + SectionBase *Section, InputFile *File); template void addShared(StringRef Name, SharedFile *F, @@ -64,22 +62,23 @@ public: const typename ELFT::Verdef *Verdef); template - Symbol *addLazyArchive(StringRef Name, ArchiveFile *F, - const llvm::object::Archive::Symbol S); + SymbolBody *addLazyArchive(StringRef Name, ArchiveFile *F, + const llvm::object::Archive::Symbol S); template void addLazyObject(StringRef Name, LazyObjFile &Obj); - Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File); + SymbolBody *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, + uint8_t Type, bool CanOmitFromDynSym, + BitcodeFile *File); - Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment, - uint8_t Binding, uint8_t StOther, uint8_t Type, - InputFile *File); + SymbolBody *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment, + uint8_t Binding, uint8_t StOther, uint8_t Type, + InputFile *File); - std::pair insert(StringRef Name); - std::pair insert(StringRef Name, uint8_t Type, - uint8_t Visibility, bool CanOmitFromDynSym, - InputFile *File); + std::pair insert(StringRef Name); + std::pair insert(StringRef Name, uint8_t Type, + uint8_t Visibility, + bool CanOmitFromDynSym, InputFile *File); template void fetchIfLazy(StringRef Name); template void scanShlibUndefined(); @@ -94,7 +93,7 @@ public: private: std::vector findByVersion(SymbolVersion Ver); std::vector findAllByVersion(SymbolVersion Ver); - void defsym(Symbol *Dst, Symbol *Src); + void defsym(SymbolBody *Dst, SymbolBody *Src); llvm::StringMap> &getDemangledSyms(); void handleAnonymousVersion(); @@ -116,7 +115,7 @@ private: // FIXME: Experiment with passing in a custom hashing or sorting the symbols // once symbol resolution is finished. llvm::DenseMap Symtab; - std::vector SymVector; + std::vector SymVector; // Comdat groups define "link once" sections. If two comdat groups have the // same name, only one of them is linked, and the other is ignored. This set @@ -133,8 +132,8 @@ private: llvm::Optional>> DemangledSyms; struct SymbolRenaming { - Symbol *Dst; - Symbol *Src; + SymbolBody *Dst; + SymbolBody *Src; uint8_t Binding; }; @@ -142,7 +141,7 @@ private: std::vector Defsyms; // For -wrap. - std::vector> WrapSymbols; + std::vector> WrapSymbols; // For LTO. std::unique_ptr LTO; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 307e2f2..703f304 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -113,7 +113,7 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { return 0; case SymbolBody::LazyArchiveKind: case SymbolBody::LazyObjectKind: - assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer"); + assert(Body.IsUsedInRegularObj && "lazy symbol reached writer"); return 0; } llvm_unreachable("invalid symbol kind"); @@ -122,7 +122,7 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { // Returns true if this is a weak undefined symbol. bool SymbolBody::isUndefWeak() const { // See comment on Lazy in Symbols.h for the details. - return !isLocal() && symbol()->isWeak() && (isUndefined() || isLazy()); + return !isLocal() && isWeak() && (isUndefined() || isLazy()); } InputFile *SymbolBody::getFile() const { @@ -133,15 +133,24 @@ InputFile *SymbolBody::getFile() const { // SymbolBody, or having a special absolute section if needed. return Sec ? cast(Sec)->File : nullptr; } - return symbol()->File; + return File; } // 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::copyFrom(SymbolBody *Other) { - memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer, - sizeof(Symbol::Body)); + SymbolBody Sym = *this; + memcpy(this, Other, sizeof(SymbolUnion)); + + Binding = Sym.Binding; + VersionId = Sym.VersionId; + Visibility = Sym.Visibility; + IsUsedInRegularObj = Sym.IsUsedInRegularObj; + ExportDynamic = Sym.ExportDynamic; + CanInline = Sym.CanInline; + Traced = Sym.Traced; + InVersionScript = Sym.InVersionScript; } uint64_t SymbolBody::getVA(int64_t Addend) const { @@ -235,9 +244,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; } @@ -287,44 +296,43 @@ LazyObjFile *LazyObject::getFile() { InputFile *LazyObject::fetch() { return getFile()->fetch(); } -uint8_t Symbol::computeBinding() const { +uint8_t SymbolBody::computeBinding() const { if (Config->Relocatable) return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; - if (VersionId == VER_NDX_LOCAL && body()->isInCurrentOutput()) + if (VersionId == VER_NDX_LOCAL && isInCurrentOutput()) return STB_LOCAL; if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; return Binding; } -bool Symbol::includeInDynsym() const { +bool SymbolBody::includeInDynsym() const { if (!Config->HasDynSymTab) return false; if (computeBinding() == STB_LOCAL) return false; - if (!body()->isInCurrentOutput()) + if (!isInCurrentOutput()) return true; return ExportDynamic; } // Print out a log message for --trace-symbol. -void elf::printTraceSymbol(Symbol *Sym) { - SymbolBody *B = Sym->body(); +void elf::printTraceSymbol(SymbolBody *Sym) { std::string S; - if (B->isUndefined()) + if (Sym->isUndefined()) S = ": reference to "; - else if (B->isCommon()) + else if (Sym->isCommon()) S = ": common definition of "; - else if (B->isLazy()) + else if (Sym->isLazy()) S = ": lazy definition of "; - else if (B->isShared()) + else if (Sym->isShared()) S = ": shared definition of "; else S = ": definition of "; - message(toString(Sym->File) + S + B->getName()); + message(toString(Sym->File) + S + Sym->getName()); } // Returns a symbol for an error message. diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index ffedabd..a765b07 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -34,8 +34,6 @@ template class ObjFile; class OutputSection; template class SharedFile; -struct Symbol; - // The base class for real symbol classes. class SymbolBody { public: @@ -51,13 +49,51 @@ public: }; SymbolBody(Kind K) : SymbolKind(K) {} + Kind kind() const { return static_cast(SymbolKind); } - Symbol *symbol(); - const Symbol *symbol() const { - return const_cast(this)->symbol(); - } + // Symbol binding. This is not overwritten by replaceSymbol to track + // changes during resolution. In particular: + // - An undefined weak is still weak when it resolves to a shared library. + // - An undefined weak will not fetch archive members, but we have to + // remember it is weak. + uint8_t Binding; - Kind kind() const { return static_cast(SymbolKind); } + // Version definition index. + uint16_t VersionId; + + // Symbol visibility. This is the computed minimum visibility of all + // observed non-DSO symbols. + unsigned Visibility : 2; + + // True if the symbol was used for linking and thus need to be added to the + // output file's symbol table. This is true for all symbols except for + // unreferenced DSO symbols and bitcode symbols that are unreferenced except + // by other bitcode objects. + unsigned IsUsedInRegularObj : 1; + + // If this flag is true and the symbol has protected or default visibility, it + // will appear in .dynsym. This flag is set by interposable DSO symbols in + // executables, by most symbols in DSOs and executables built with + // --export-dynamic, and by dynamic lists. + unsigned ExportDynamic : 1; + + // False if LTO shouldn't inline whatever this symbol points to. If a symbol + // is overwritten after LTO, LTO shouldn't inline the symbol because it + // doesn't know the final contents of the symbol. + unsigned CanInline : 1; + + // True if this symbol is specified by --trace-symbol option. + unsigned Traced : 1; + + // This symbol version was found in a version script. + unsigned InVersionScript : 1; + + // The file from which this symbol was created. + InputFile *File = nullptr; + + bool includeInDynsym() const; + uint8_t computeBinding() const; + bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } bool isUndefined() const { return SymbolKind == UndefinedKind; } bool isDefined() const { return SymbolKind <= DefinedLast; } @@ -344,89 +380,47 @@ struct ElfSym { static DefinedRegular *MipsLocalGp; }; -// A real symbol object, SymbolBody, is usually stored within a Symbol. There's -// always one Symbol for each symbol name. The resolver updates the SymbolBody -// stored in the Body field of this object as it resolves symbols. Symbol also -// holds computed properties of symbol names. -struct Symbol { - // Symbol binding. This is on the Symbol to track changes during resolution. - // In particular: - // An undefined weak is still weak when it resolves to a shared library. - // An undefined weak will not fetch archive members, but we have to remember - // it is weak. - uint8_t Binding; - - // Version definition index. - uint16_t VersionId; - - // Symbol visibility. This is the computed minimum visibility of all - // observed non-DSO symbols. - unsigned Visibility : 2; - - // True if the symbol was used for linking and thus need to be added to the - // output file's symbol table. This is true for all symbols except for - // unreferenced DSO symbols and bitcode symbols that are unreferenced except - // by other bitcode objects. - unsigned IsUsedInRegularObj : 1; - - // If this flag is true and the symbol has protected or default visibility, it - // will appear in .dynsym. This flag is set by interposable DSO symbols in - // executables, by most symbols in DSOs and executables built with - // --export-dynamic, and by dynamic lists. - unsigned ExportDynamic : 1; - - // False if LTO shouldn't inline whatever this symbol points to. If a symbol - // is overwritten after LTO, LTO shouldn't inline the symbol because it - // doesn't know the final contents of the symbol. - unsigned CanInline : 1; - - // True if this symbol is specified by --trace-symbol option. - unsigned Traced : 1; - - // This symbol version was found in a version script. - unsigned InVersionScript : 1; - - // The file from which this symbol was created. - InputFile *File = nullptr; - - bool includeInDynsym() const; - uint8_t computeBinding() const; - bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } - - // This field is used to store the Symbol's SymbolBody. This instantiation of - // AlignedCharArrayUnion gives us a struct with a char array field that is - // large and aligned enough to store any derived class of SymbolBody. - llvm::AlignedCharArrayUnion - Body; - - SymbolBody *body() { return reinterpret_cast(Body.buffer); } - const SymbolBody *body() const { return const_cast(this)->body(); } +// A buffer class that is large enough to hold any SymbolBody-derived +// object. We allocate memory using this class and instantiate a symbol +// using the placement new. +union SymbolUnion { + alignas(DefinedRegular) char A[sizeof(DefinedRegular)]; + alignas(DefinedCommon) char B[sizeof(DefinedCommon)]; + alignas(Undefined) char C[sizeof(Undefined)]; + alignas(SharedSymbol) char D[sizeof(SharedSymbol)]; + alignas(LazyArchive) char E[sizeof(LazyArchive)]; + alignas(LazyObject) char F[sizeof(LazyObject)]; }; -void printTraceSymbol(Symbol *Sym); +void printTraceSymbol(SymbolBody *Sym); template -void replaceBody(Symbol *S, InputFile *File, ArgT &&... Arg) { - static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); - static_assert(alignof(T) <= alignof(decltype(S->Body)), - "Body not aligned enough"); +void replaceBody(SymbolBody *S, InputFile *File, ArgT &&... Arg) { + static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); + static_assert(alignof(T) <= alignof(SymbolUnion), + "SymbolUnion not aligned enough"); assert(static_cast(static_cast(nullptr)) == nullptr && "Not a SymbolBody"); + + SymbolBody Sym = *S; + + new (S) T(std::forward(Arg)...); S->File = File; - new (S->Body.buffer) T(std::forward(Arg)...); + + S->Binding = Sym.Binding; + S->VersionId = Sym.VersionId; + S->Visibility = Sym.Visibility; + S->IsUsedInRegularObj = Sym.IsUsedInRegularObj; + S->ExportDynamic = Sym.ExportDynamic; + S->CanInline = Sym.CanInline; + S->Traced = Sym.Traced; + S->InVersionScript = Sym.InVersionScript; // Print out a log message if --trace-symbol was specified. // This is for debugging. if (S->Traced) printTraceSymbol(S); } - -inline Symbol *SymbolBody::symbol() { - assert(!isLocal()); - return reinterpret_cast(reinterpret_cast(this) - - offsetof(Symbol, Body)); -} } // namespace elf std::string toString(const elf::SymbolBody &B); diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 8c1c8b56..f7d90dd 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -66,8 +66,8 @@ uint64_t SyntheticSection::getVA() const { // Create a .bss section for each common symbol and replace the common symbol // with a DefinedRegular symbol. template void elf::createCommonSections() { - for (Symbol *S : Symtab->getSymbols()) { - auto *Sym = dyn_cast(S->body()); + for (SymbolBody *S : Symtab->getSymbols()) { + auto *Sym = dyn_cast(S); if (!Sym) continue; @@ -1533,8 +1533,7 @@ void SymbolTableBaseSection::postThunkContents() { // move all local symbols before global symbols. auto It = std::stable_partition( Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { - return S.Symbol->isLocal() || - S.Symbol->symbol()->computeBinding() == STB_LOCAL; + return S.Symbol->isLocal() || S.Symbol->computeBinding() == STB_LOCAL; }); size_t NumLocals = It - Symbols.begin(); getParent()->Info = NumLocals + 1; @@ -1591,8 +1590,8 @@ template void SymbolTableSection::writeTo(uint8_t *Buf) { if (Body->isLocal()) { ESym->setBindingAndType(STB_LOCAL, Body->Type); } else { - ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type); - ESym->setVisibility(Body->symbol()->Visibility); + ESym->setBindingAndType(Body->computeBinding(), Body->Type); + ESym->setVisibility(Body->Visibility); } ESym->st_name = Ent.StrTabOffset; @@ -2284,7 +2283,7 @@ template size_t VersionTableSection::getSize() const { template void VersionTableSection::writeTo(uint8_t *Buf) { auto *OutVersym = reinterpret_cast(Buf) + 1; for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) { - OutVersym->vs_index = S.Symbol->symbol()->VersionId; + OutVersym->vs_index = S.Symbol->VersionId; ++OutVersym; } } @@ -2307,7 +2306,7 @@ template void VersionNeedSection::addSymbol(SharedSymbol *SS) { auto *Ver = reinterpret_cast(SS->Verdef); if (!Ver) { - SS->symbol()->VersionId = VER_NDX_GLOBAL; + SS->VersionId = VER_NDX_GLOBAL; return; } @@ -2327,7 +2326,7 @@ void VersionNeedSection::addSymbol(SharedSymbol *SS) { Ver->getAux()->vda_name); NV.Index = NextIndex++; } - SS->symbol()->VersionId = NV.Index; + SS->VersionId = NV.Index; } template void VersionNeedSection::writeTo(uint8_t *Buf) { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index d904060..49dc9ac 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -425,7 +425,7 @@ static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, } static bool includeInSymtab(const SymbolBody &B) { - if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) + if (!B.isLocal() && !B.IsUsedInRegularObj) return false; if (auto *D = dyn_cast(&B)) { @@ -743,10 +743,10 @@ addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, SymbolBody *S = Symtab->find(Name); if (!S || S->isInCurrentOutput()) return nullptr; - Symbol *Sym = Symtab->addRegular(Name, StOther, STT_NOTYPE, Val, - /*Size=*/0, Binding, Sec, - /*File=*/nullptr); - return cast(Sym->body()); + SymbolBody *Sym = Symtab->addRegular(Name, StOther, STT_NOTYPE, Val, + /*Size=*/0, Binding, Sec, + /*File=*/nullptr); + return cast(Sym); } // The beginning and the ending of .rel[a].plt section are marked @@ -1188,11 +1188,11 @@ static void removeUnusedSyntheticSections() { static bool computeIsPreemptible(const SymbolBody &B) { assert(!B.isLocal()); // Only symbols that appear in dynsym can be preempted. - if (!B.symbol()->includeInDynsym()) + if (!B.includeInDynsym()) return false; // Only default visibility symbols can be preempted. - if (B.symbol()->Visibility != STV_DEFAULT) + if (B.Visibility != STV_DEFAULT) return false; // At this point copy relocations have not been created yet, so any @@ -1248,8 +1248,8 @@ template void Writer::finalizeSections() { applySynthetic({InX::EhFrame}, [](SyntheticSection *SS) { SS->finalizeContents(); }); - for (Symbol *S : Symtab->getSymbols()) - S->body()->IsPreemptible |= computeIsPreemptible(*S->body()); + for (SymbolBody *S : Symtab->getSymbols()) + S->IsPreemptible |= computeIsPreemptible(*S); // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. @@ -1263,18 +1263,16 @@ template void Writer::finalizeSections() { // Now that we have defined all possible global symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. - for (Symbol *S : Symtab->getSymbols()) { - SymbolBody *Body = S->body(); - - if (!includeInSymtab(*Body)) + for (SymbolBody *Sym : Symtab->getSymbols()) { + if (!includeInSymtab(*Sym)) continue; if (InX::SymTab) - InX::SymTab->addSymbol(Body); + InX::SymTab->addSymbol(Sym); - if (InX::DynSymTab && S->includeInDynsym()) { - InX::DynSymTab->addSymbol(Body); - if (auto *SS = dyn_cast(Body)) - if (cast>(S->File)->isNeeded()) + if (InX::DynSymTab && Sym->includeInDynsym()) { + InX::DynSymTab->addSymbol(Sym); + if (auto *SS = dyn_cast(Sym)) + if (cast>(Sym->File)->isNeeded()) In::VerNeed->addSymbol(SS); } } diff --git a/lld/docs/NewLLD.rst b/lld/docs/NewLLD.rst index cb27cc5..fb796a4 100644 --- a/lld/docs/NewLLD.rst +++ b/lld/docs/NewLLD.rst @@ -140,13 +140,13 @@ We will describe the key data structures in LLD in this section. The linker can be understood as the interactions between them. Once you understand their functions, the code of the linker should look obvious to you. -* SymbolBody +* Symbol - SymbolBody is a class to represent symbols. + This class represents a symbol. They are created for symbols in object files or archive files. The linker creates linker-defined symbols as well. - There are basically three types of SymbolBodies: Defined, Undefined, or Lazy. + There are basically three types of Symbols: Defined, Undefined, or Lazy. - Defined symbols are for all symbols that are considered as "resolved", including real defined symbols, COMDAT symbols, common symbols, @@ -156,26 +156,17 @@ Once you understand their functions, the code of the linker should look obvious - Lazy symbols represent symbols we found in archive file headers which can turn into Defined if we read archieve members. -* Symbol + There's only one Symbol instance for each unique symbol name. This uniqueness + is guaranteed by the symbol table. As the resolver reads symbols from input + files, it replaces an existing Symbol with the "best" Symbol for its symbol + name using the placement new. - A Symbol is a container for a SymbolBody. There's only one Symbol for each - unique symbol name (this uniqueness is guaranteed by the symbol table). - Each global symbol has only one SymbolBody at any one time, which is - the SymbolBody stored within a memory region of the Symbol large enough - to store any SymbolBody. - - As the resolver reads symbols from input files, it replaces the Symbol's - SymbolBody with the "best" SymbolBody for its symbol name by constructing - the new SymbolBody in place on top of the existing SymbolBody. For example, - if the resolver is given a defined symbol, and the SymbolBody with its name - is undefined, it will construct a Defined SymbolBody over the Undefined - SymbolBody. - - This means that each SymbolBody pointer always points to the best SymbolBody, - and it is possible to get from a SymbolBody to a Symbol, or vice versa, - by adding or subtracting a fixed offset. This memory layout helps reduce - the cache miss rate through high locality and a small number of required - pointer indirections. + The above mechanism allows you to use pointers to Symbols as a very cheap way + to access name resolution results. Assume for example that you have a pointer + to an undefined symbol before name resolution. If the symbol is resolved to a + defined symbol by the resolver, the pointer will "automatically" point to the + defined symbol, because the undefined symbol the pointer pointed to will have + been replaced by the defined symbol in-place. * SymbolTable @@ -221,8 +212,7 @@ There are mainly three actors in this linker. InputFile is a superclass of file readers. We have a different subclass for each input file type, such as regular object file, archive file, etc. - They are responsible for creating and owning SymbolBodies and - InputSections/Chunks. + They are responsible for creating and owning Symbols and InputSections/Chunks. * Writer