diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1299,14 +1299,14 @@ // that point to a non-existent DSO. static void demoteSharedSymbols() { for (Symbol *Sym : Symtab->getSymbols()) { - if (auto *S = dyn_cast(Sym)) { - if (!S->getFile().IsNeeded) { - bool Used = S->Used; - replaceSymbol(S, nullptr, S->getName(), STB_WEAK, S->StOther, - S->Type); - S->Used = Used; - } - } + auto *S = dyn_cast(Sym); + if (!S || S->getFile().IsNeeded) + continue; + + bool Used = S->Used; + Undefined New(nullptr, S->getName(), STB_WEAK, S->StOther, S->Type); + replaceSymbol(S, &New); + S->Used = Used; } } @@ -1375,8 +1375,8 @@ } template static Symbol *addUndefined(StringRef Name) { - return Symtab->addUndefined(Name, STB_GLOBAL, STV_DEFAULT, 0, false, - nullptr); + Undefined Sym(nullptr, Name, STB_GLOBAL, STV_DEFAULT, 0); + return Symtab->addUndefined(&Sym); } // The --wrap option is a feature to rename symbols so that you can write diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -893,14 +893,16 @@ StringRef Name = CHECK(Sym->getName(this->StringTable), this); switch (Sym->st_shndx) { - case SHN_UNDEF: - return Symtab->addUndefined(Name, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this); + case SHN_UNDEF: { + Undefined S(this, Name, Binding, StOther, Type); + return Symtab->addUndefined(&S); + } 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); + Defined New(this, Name, Binding, StOther, Type, Value, Size, nullptr); + return Symtab->addCommon(&New); } switch (Binding) { @@ -909,11 +911,13 @@ case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: - if (Sec == &InputSection::Discarded) - return Symtab->addUndefined(Name, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this); - return Symtab->addDefined(Name, StOther, Type, Value, Size, Binding, Sec, - this); + if (Sec == &InputSection::Discarded) { + Undefined S(this, Name, Binding, StOther, Type); + return Symtab->addUndefined(&S); + } + + Defined New(this, Name, Binding, StOther, Type, Value, Size, Sec); + return Symtab->addDefined(&New); } } @@ -922,8 +926,10 @@ File(std::move(File)) {} template void ArchiveFile::parse() { - for (const Archive::Symbol &Sym : File->symbols()) - Symtab->addLazyArchive(Sym.getName(), *this, Sym); + for (const Archive::Symbol &Sym : File->symbols()) { + LazyArchive New(*this, Sym); + Symtab->addLazyArchive(&New); + } } // Returns a buffer pointing to a member file containing a given symbol. @@ -1124,9 +1130,8 @@ } if (Sym.isUndefined()) { - Symbol *S = Symtab->addUndefined(Name, Sym.getBinding(), - Sym.st_other, Sym.getType(), - /*CanOmitFromDynSym=*/false, this); + Undefined New(this, Name, Sym.getBinding(), Sym.st_other, Sym.getType()); + Symbol *S = Symtab->addUndefined(&New); S->ExportDynamic = true; continue; } @@ -1140,9 +1145,11 @@ continue; uint64_t Alignment = getAlignment(Sections, Sym); - if (!(Versyms[I] & VERSYM_HIDDEN)) - Symtab->addShared(Name, Sym.getBinding(), Sym.st_other, Sym.getType(), - Sym.st_value, Sym.st_size, Alignment, Idx, this); + if (!(Versyms[I] & VERSYM_HIDDEN)) { + SharedSymbol S(*this, Name, Sym.getBinding(), Sym.st_other, Sym.getType(), + Sym.st_value, Sym.st_size, Alignment, Idx); + Symtab->addShared(&S); + } // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. @@ -1161,9 +1168,10 @@ reinterpret_cast(Verdefs[Idx])->getAux()->vda_name; VersionedNameBuffer.clear(); Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer); - Symtab->addShared(Saver.save(Name), Sym.getBinding(), Sym.st_other, - Sym.getType(), Sym.st_value, Sym.st_size, Alignment, Idx, - this); + + SharedSymbol S(*this, Saver.save(Name), Sym.getBinding(), Sym.st_other, + Sym.getType(), Sym.st_value, Sym.st_size, Alignment, Idx); + Symtab->addShared(&S); } } @@ -1259,21 +1267,23 @@ bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable(); int C = ObjSym.getComdatIndex(); - if (C != -1 && !KeptComdats[C]) - return Symtab->addUndefined(Name, Binding, Visibility, Type, - CanOmitFromDynSym, &F); - - if (ObjSym.isUndefined()) - return Symtab->addUndefined(Name, Binding, Visibility, Type, - CanOmitFromDynSym, &F); + if (ObjSym.isUndefined() || (C != -1 && !KeptComdats[C])) { + Undefined New(&F, Name, Binding, Visibility, Type); + if (CanOmitFromDynSym) + New.ExportDynamic = false; + return Symtab->addUndefined(&New); + } - if (ObjSym.isCommon()) - return Symtab->addCommon(Name, ObjSym.getCommonSize(), - ObjSym.getCommonAlignment(), Binding, Visibility, - STT_OBJECT, F); + if (ObjSym.isCommon()) { + Defined New(&F, Name, Binding, Visibility, STT_OBJECT, + ObjSym.getCommonAlignment(), ObjSym.getCommonSize(), nullptr); + return Symtab->addCommon(&New); + } - return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym, - F); + Defined New(&F, Name, Binding, Visibility, Type, 0, 0, nullptr); + if (CanOmitFromDynSym) + New.ExportDynamic = false; + return Symtab->addBitcode(&New); } template @@ -1331,12 +1341,16 @@ if (!isAlnum(S[I])) S[I] = '_'; - Symtab->addDefined(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, - STB_GLOBAL, Section, nullptr); - Symtab->addDefined(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, Section, nullptr); - Symtab->addDefined(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, nullptr, nullptr); + Defined Sym1(nullptr, Saver.save(S + "_start"), STB_GLOBAL, STV_DEFAULT, + STT_OBJECT, 0, 0, Section); + Defined Sym2(nullptr, Saver.save(S + "_end"), STB_GLOBAL, STV_DEFAULT, + STT_OBJECT, Data.size(), 0, Section); + Defined Sym3(nullptr, Saver.save(S + "_size"), STB_GLOBAL, STV_DEFAULT, + STT_OBJECT, Data.size(), 0, nullptr); + + Symtab->addDefined(&Sym1); + Symtab->addDefined(&Sym2); + Symtab->addDefined(&Sym3); } InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, @@ -1401,9 +1415,12 @@ if (isBitcode(this->MB)) { std::unique_ptr Obj = CHECK(lto::InputFile::create(this->MB), this); - for (const lto::InputFile::Symbol &Sym : Obj->symbols()) - if (!Sym.isUndefined()) - Symtab->addLazyObject(Saver.save(Sym.getName()), *this); + for (const lto::InputFile::Symbol &Sym : Obj->symbols()) { + if (Sym.isUndefined()) + continue; + LazyObject New(*this, Saver.save(Sym.getName())); + Symtab->addLazyObject(&New); + } return; } @@ -1424,10 +1441,12 @@ StringRef StringTable = CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); - for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal)) - if (Sym.st_shndx != SHN_UNDEF) - Symtab->addLazyObject(CHECK(Sym.getName(StringTable), this), - *this); + for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal)) { + if (Sym.st_shndx == SHN_UNDEF) + continue; + LazyObject New(*this, CHECK(Sym.getName(StringTable), this)); + Symtab->addLazyObject(&New); + } return; } } diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -153,8 +153,8 @@ BitcodeCompiler::~BitcodeCompiler() = default; static void undefine(Symbol *S) { - replaceSymbol(S, nullptr, S->getName(), STB_GLOBAL, STV_DEFAULT, - S->Type); + Undefined New(nullptr, S->getName(), STB_GLOBAL, STV_DEFAULT, S->Type); + replaceSymbol(S, &New); } void BitcodeCompiler::add(BitcodeFile &F) { diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -166,13 +166,9 @@ return; // Define a symbol. - Symbol *Sym; - uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; - std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility, - /*CanOmitFromDynSym*/ false, - /*File*/ nullptr); ExprValue Value = Cmd->Expression(); SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; // When this function is called, section addresses have not been // fixed yet. So, we may or may not know the value of the RHS @@ -187,8 +183,12 @@ // write expressions like this: `alignment = 16; . = ALIGN(., alignment)`. uint64_t SymValue = Value.Sec ? 0 : Value.getValue(); - replaceSymbol(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, - STT_NOTYPE, SymValue, 0, Sec); + Defined New(nullptr, Cmd->Name, STB_GLOBAL, Visibility, STT_NOTYPE, SymValue, + 0, Sec); + + Symbol *Sym; + std::tie(Sym, std::ignore) = Symtab->insert(&New); + replaceSymbol(Sym, &New); Cmd->Sym = cast(Sym); } @@ -198,14 +198,15 @@ if (!shouldDefineSym(Cmd)) return; + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + Defined New(nullptr, Cmd->Name, STB_GLOBAL, Visibility, STT_NOTYPE, 0, 0, + nullptr); + // We can't calculate final value right now. Symbol *Sym; - uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; - std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility, - /*CanOmitFromDynSym*/ false, - /*File*/ nullptr); - replaceSymbol(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, - STT_NOTYPE, 0, 0, nullptr); + std::tie(Sym, std::ignore) = Symtab->insert(&New); + replaceSymbol(Sym, &New); + Cmd->Sym = cast(Sym); Cmd->Provide = false; Sym->ScriptDefined = true; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -529,8 +529,11 @@ static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value, uint64_t Size) { Symbol Old = Sym; - replaceSymbol(&Sym, Sym.File, Sym.getName(), Sym.Binding, - Sym.StOther, Sym.Type, Value, Size, Sec); + + Defined New(Sym.File, Sym.getName(), Sym.Binding, Sym.StOther, Sym.Type, + Value, Size, Sec); + replaceSymbol(&Sym, &New); + Sym.PltIndex = Old.PltIndex; Sym.GotIndex = Old.GotIndex; Sym.VerdefIndex = Old.VerdefIndex; diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -17,8 +17,13 @@ namespace lld { namespace elf { + class Defined; +class LazyArchive; +class LazyObject; class SectionBase; +class SharedSymbol; +class Undefined; // SymbolTable is a bucket of all known symbols, including defined, // undefined, or lazy symbols (the last one is symbols in archive @@ -39,33 +44,19 @@ ArrayRef getSymbols() const { return SymVector; } - template - Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type, bool CanOmitFromDynSym, InputFile *File); - - Defined *addDefined(StringRef Name, uint8_t StOther, uint8_t Type, - uint64_t Value, uint64_t Size, uint8_t Binding, - SectionBase *Section, InputFile *File); - - void addShared(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, - uint64_t Value, uint64_t Size, uint32_t Alignment, - uint32_t VerdefIndex, InputFile *File); + template Symbol *addUndefined(Undefined *New); - template - void addLazyArchive(StringRef Name, ArchiveFile &F, - const llvm::object::Archive::Symbol S); + Defined *addDefined(Defined *New); - template void addLazyObject(StringRef Name, LazyObjFile &Obj); + void addShared(SharedSymbol *New); - Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type, bool CanOmitFromDynSym, BitcodeFile &File); + template void addLazyArchive(LazyArchive *New); + template void addLazyObject(LazyObject *New); - Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment, - uint8_t Binding, uint8_t StOther, uint8_t Type, - InputFile &File); + Symbol *addBitcode(Defined *New); + Symbol *addCommon(Defined *New); - std::pair insert(StringRef Name, uint8_t Visibility, - bool CanOmitFromDynSym, InputFile *File); + std::pair insert(Symbol *New); template void fetchLazy(Symbol *Sym); @@ -81,7 +72,7 @@ llvm::DenseMap SoNames; private: - std::pair insertName(StringRef Name); + template void addLazy(LazyT *New); std::vector findByVersion(SymbolVersion Ver); std::vector findAllByVersion(SymbolVersion Ver); diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -86,14 +86,18 @@ return std::min(VA, VB); } -// Find an existing symbol or create and insert a new one. -std::pair SymbolTable::insertName(StringRef Name) { +// Find an existing symbol or create and insert a new one, then apply the given +// attributes. +std::pair SymbolTable::insert(Symbol *New) { + // Find an existing symbol or create and insert a new one. + // @@ means the symbol is the default version. In that // case @@ will be used to resolve references to . // // Since this is a hot path, the following string search code is // optimized for speed. StringRef::find(char) is much faster than // StringRef::find(StringRef). + StringRef Name = New->getName(); size_t Pos = Name.find('@'); if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@') Name = Name.take_front(Pos); @@ -109,70 +113,57 @@ Traced = true; } - if (!IsNew) - return {SymVector[SymIndex], false}; - - auto *Sym = reinterpret_cast(make()); - Sym->SymbolKind = Symbol::PlaceholderKind; - Sym->Visibility = STV_DEFAULT; - Sym->IsUsedInRegularObj = false; - Sym->ExportDynamic = false; - Sym->CanInline = true; - Sym->Traced = Traced; - Sym->VersionId = Config->DefaultSymbolVersion; - SymVector.push_back(Sym); - return {Sym, true}; -} - -// Find an existing symbol or create and insert a new one, then apply the given -// attributes. -std::pair SymbolTable::insert(StringRef Name, - uint8_t Visibility, - bool CanOmitFromDynSym, - InputFile *File) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insertName(Name); - - // Merge in the new symbol's visibility. - S->Visibility = getMinVisibility(S->Visibility, Visibility); + Symbol *Old; + if (IsNew) { + Old = reinterpret_cast(make()); + SymVector.push_back(Old); + + Old->SymbolKind = Symbol::PlaceholderKind; + Old->VersionId = Config->DefaultSymbolVersion; + Old->Visibility = STV_DEFAULT; + Old->IsUsedInRegularObj = false; + Old->ExportDynamic = false; + Old->CanInline = true; + Old->Traced = Traced; + Old->ScriptDefined = false; + } else { + Old = SymVector[SymIndex]; + } - if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) - S->ExportDynamic = true; + // Merge symbol properties. + Old->ExportDynamic = Old->ExportDynamic || New->ExportDynamic; + Old->IsUsedInRegularObj = Old->IsUsedInRegularObj || New->IsUsedInRegularObj; - if (!File || File->kind() == InputFile::ObjKind) - S->IsUsedInRegularObj = true; + // DSO symbols do not affect visibility in the output. + if (!isa(New)) + Old->Visibility = getMinVisibility(Old->Visibility, New->Visibility); - return {S, WasInserted}; + return {Old, IsNew}; } -static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; } - -template -Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, - uint8_t StOther, uint8_t Type, - bool CanOmitFromDynSym, InputFile *File) { - Symbol *S; +template Symbol *SymbolTable::addUndefined(Undefined *New) { + Symbol *Old; bool WasInserted; - uint8_t Visibility = getVisibility(StOther); - std::tie(S, WasInserted) = insert(Name, Visibility, CanOmitFromDynSym, File); + std::tie(Old, WasInserted) = insert(New); // An undefined symbol with non default visibility must be satisfied // in the same DSO. - if (WasInserted || (isa(S) && Visibility != STV_DEFAULT)) { - replaceSymbol(S, File, Name, Binding, StOther, Type); - return S; + if (WasInserted || + (isa(Old) && New->Visibility != STV_DEFAULT)) { + replaceSymbol(Old, New); + return Old; } - if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK)) - S->Binding = Binding; + if (Old->isShared() || Old->isLazy() || + (Old->isUndefined() && New->Binding != STB_WEAK)) + Old->Binding = New->Binding; - if (S->isLazy()) { + if (Old->isLazy()) { // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. - if (Binding == STB_WEAK) { - S->Type = Type; - return S; + if (New->Binding == STB_WEAK) { + Old->Type = New->Type; + return Old; } // Do extra check for --warn-backrefs. @@ -225,17 +216,17 @@ // A forms group 0. B form group 1. C and D (including their member object // files) form group 2. E forms group 3. I think that you can see how this // group assignment rule simulates the traditional linker's semantics. - bool Backref = - Config->WarnBackrefs && File && S->File->GroupId < File->GroupId; - fetchLazy(S); + bool Backref = Config->WarnBackrefs && New->File && + Old->File->GroupId < New->File->GroupId; + fetchLazy(Old); // We don't report backward references to weak symbols as they can be // overridden later. - if (Backref && !S->isWeak()) - warn("backward reference detected: " + Name + " in " + toString(File) + - " refers to " + toString(S->File)); + if (Backref && !Old->isWeak()) + warn("backward reference detected: " + New->getName() + " in " + + toString(New->File) + " refers to " + toString(Old->File)); } - return S; + return Old; } // Using .symver foo,foo@@VER unfortunately creates two symbols: foo and @@ -244,12 +235,12 @@ // FIXME: If users can transition to using // .symver foo,foo@@@VER // we can delete this hack. -static int compareVersion(Symbol *S, StringRef Name) { - bool A = Name.contains("@@"); - bool B = S->getName().contains("@@"); - if (A && !B) - return 1; +static int compareVersion(StringRef OldName, StringRef NewName) { + bool A = OldName.contains("@@"); + bool B = NewName.contains("@@"); if (!A && B) + return 1; + if (A && !B) return -1; return 0; } @@ -257,17 +248,14 @@ // 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, - StringRef Name) { - if (WasInserted) - return 1; - if (!S->isDefined()) +static int compareDefined(Symbol *Old, Symbol *New) { + if (!Old->isDefined()) return 1; - if (int R = compareVersion(S, Name)) - return R; - if (Binding == STB_WEAK) + if (int Cmp = compareVersion(Old->getName(), New->getName())) + return Cmp; + if (New->Binding == STB_WEAK) return -1; - if (S->isWeak()) + if (Old->isWeak()) return 1; return 0; } @@ -275,65 +263,76 @@ // 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) { - if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) +static int compareDefinedNonCommon(Symbol *OldSym, Defined *New) { + if (int Cmp = compareDefined(OldSym, New)) return Cmp; - if (auto *R = dyn_cast(S)) { - if (R->Section && isa(R->Section)) { + + if (auto *Old = dyn_cast(OldSym)) { + if (Old->Section && isa(Old->Section)) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) - warn("common " + S->getName() + " is overridden"); + warn("common " + Old->getName() + " is overridden"); return 1; } - if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && - R->Value == Value) + + if (New->File && isa(New->File)) + return 0; + + if (Old->Section == nullptr && New->Section == nullptr && + Old->Value == New->Value && New->Binding == STB_GLOBAL) return -1; } 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; +Symbol *SymbolTable::addCommon(Defined *New) { + Symbol *Old; bool WasInserted; - std::tie(S, WasInserted) = insert(N, getVisibility(StOther), - /*CanOmitFromDynSym*/ false, &File); + std::tie(Old, WasInserted) = insert(New); - int Cmp = compareDefined(S, WasInserted, Binding, N); - if (Cmp < 0) - return S; - - if (Cmp > 0) { - auto *Bss = make("COMMON", Size, Alignment); - Bss->File = &File; + auto Replace = [&] { + auto *Bss = make("COMMON", New->Size, New->Value); + Bss->File = New->File; Bss->Live = !Config->GcSections; InputSections.push_back(Bss); - replaceSymbol(S, &File, N, Binding, StOther, Type, 0, Size, Bss); - return S; + New->Value = 0; + New->Section = Bss; + replaceSymbol(Old, New); + }; + + if (WasInserted) { + Replace(); + return Old; + } + + int Cmp = compareDefined(Old, New); + if (Cmp < 0) + return Old; + + if (Cmp > 0) { + Replace(); + return Old; } - auto *D = cast(S); + auto *D = cast(Old); auto *Bss = dyn_cast_or_null(D->Section); if (!Bss) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) - warn("common " + S->getName() + " is overridden"); - return S; + warn("common " + Old->getName() + " is overridden"); + return Old; } if (Config->WarnCommon) warn("multiple common of " + D->getName()); - Bss->Alignment = std::max(Bss->Alignment, Alignment); - if (Size > Bss->Size) { - D->File = Bss->File = &File; - D->Size = Bss->Size = Size; + Bss->Alignment = std::max(Bss->Alignment, New->Value); + if (New->Size > Bss->Size) { + D->File = Bss->File = New->File; + D->Size = Bss->Size = New->Size; } - return S; + return Old; } static void reportDuplicate(Symbol *Sym, InputFile *NewFile, @@ -371,66 +370,63 @@ error(Msg); } -Defined *SymbolTable::addDefined(StringRef Name, uint8_t StOther, uint8_t Type, - uint64_t Value, uint64_t Size, uint8_t Binding, - SectionBase *Section, InputFile *File) { - Symbol *S; +Defined *SymbolTable::addDefined(Defined *New) { + Symbol *Old; bool WasInserted; - std::tie(S, WasInserted) = insert(Name, getVisibility(StOther), - /*CanOmitFromDynSym*/ false, File); - int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr, - Value, Name); + std::tie(Old, WasInserted) = insert(New); + + if (WasInserted) { + replaceSymbol(Old, New); + return cast(Old); + } + + int Cmp = compareDefinedNonCommon(Old, New); if (Cmp > 0) - replaceSymbol(S, File, Name, Binding, StOther, Type, Value, Size, - Section); + replaceSymbol(Old, New); else if (Cmp == 0) - reportDuplicate(S, File, dyn_cast_or_null(Section), - Value); - return cast(S); + reportDuplicate(Old, New->File, + dyn_cast_or_null(New->Section), + New->Value); + return cast(Old); } -void SymbolTable::addShared(StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type, uint64_t Value, uint64_t Size, - uint32_t Alignment, uint32_t VerdefIndex, - InputFile *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; +void SymbolTable::addShared(SharedSymbol *New) { + Symbol *Old; bool WasInserted; - std::tie(S, WasInserted) = insert(Name, STV_DEFAULT, - /*CanOmitFromDynSym*/ true, File); - // Make sure we preempt DSO symbols with default visibility. - if (getVisibility(StOther) == STV_DEFAULT) - S->ExportDynamic = true; + std::tie(Old, WasInserted) = insert(New); - // An undefined symbol with non default visibility must be satisfied - // in the same DSO. - auto Replace = [&](uint8_t Binding) { - replaceSymbol(S, *File, Name, Binding, StOther, Type, Value, - Size, Alignment, VerdefIndex); - }; + // Make sure we preempt DSO symbols with default visibility. + if (New->Visibility == STV_DEFAULT) + Old->ExportDynamic = true; - if (WasInserted) - Replace(Binding); - else if (S->Visibility == STV_DEFAULT && (S->isUndefined() || S->isLazy())) - Replace(S->Binding); + if (WasInserted) { + replaceSymbol(Old, New); + } else if (Old->Visibility == STV_DEFAULT && + (Old->isUndefined() || Old->isLazy())) { + // An undefined symbol with non default visibility must be satisfied + // in the same DSO. + uint8_t Binding = Old->Binding; + replaceSymbol(Old, New); + Old->Binding = Binding; + } } -Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, - uint8_t StOther, uint8_t Type, - bool CanOmitFromDynSym, BitcodeFile &F) { - Symbol *S; +Symbol *SymbolTable::addBitcode(Defined *New) { + Symbol *Old; bool WasInserted; - std::tie(S, WasInserted) = - insert(Name, getVisibility(StOther), CanOmitFromDynSym, &F); - int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, - /*IsAbs*/ false, /*Value*/ 0, Name); + std::tie(Old, WasInserted) = insert(New); + + if (WasInserted) { + replaceSymbol(Old, New); + return Old; + } + + int Cmp = compareDefinedNonCommon(Old, New); if (Cmp > 0) - replaceSymbol(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr); + replaceSymbol(Old, New); else if (Cmp == 0) - reportDuplicate(S, &F, nullptr, 0); - return S; + reportDuplicate(Old, New->File, nullptr, 0); + return Old; } Symbol *SymbolTable::find(StringRef Name) { @@ -442,53 +438,39 @@ return SymVector[It->second]; } -template -void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &File, - const object::Archive::Symbol Sym) { - Symbol *S; +template void SymbolTable::addLazy(LazyT *New) { + Symbol *Old; bool WasInserted; - std::tie(S, WasInserted) = insertName(Name); + std::tie(Old, WasInserted) = insert(New); + if (WasInserted) { - replaceSymbol(S, File, STT_NOTYPE, Sym); + replaceSymbol(Old, New); return; } - if (!S->isUndefined()) + + if (!Old->isUndefined()) return; // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. - if (S->isWeak()) { - replaceSymbol(S, File, S->Type, Sym); - S->Binding = STB_WEAK; + if (Old->isWeak()) { + uint8_t Type = Old->Type; + replaceSymbol(Old, New); + Old->Type = Type; + Old->Binding = STB_WEAK; return; } - if (InputFile *F = File.fetch(Sym)) + if (InputFile *F = New->fetch()) parseFile(F); } -template -void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &File) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insertName(Name); - if (WasInserted) { - replaceSymbol(S, File, STT_NOTYPE, Name); - return; - } - if (!S->isUndefined()) - return; - - // An undefined weak will not fetch archive members. See comment on Lazy in - // Symbols.h for the details. - if (S->isWeak()) { - replaceSymbol(S, File, S->Type, Name); - S->Binding = STB_WEAK; - return; - } +template void SymbolTable::addLazyArchive(LazyArchive *New) { + addLazy(New); +} - if (InputFile *F = File.fetch()) - parseFile(F); +template void SymbolTable::addLazyObject(LazyObject *New) { + addLazy(New); } template void SymbolTable::fetchLazy(Symbol *Sym) { @@ -664,37 +646,25 @@ Sym->parseSymbolVersion(); } -template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, - uint8_t, bool, InputFile *); -template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, - uint8_t, bool, InputFile *); -template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, - uint8_t, bool, InputFile *); -template Symbol *SymbolTable::addUndefined(StringRef, uint8_t, uint8_t, - uint8_t, bool, InputFile *); +template Symbol *SymbolTable::addUndefined(Undefined *); +template Symbol *SymbolTable::addUndefined(Undefined *); +template Symbol *SymbolTable::addUndefined(Undefined *); +template Symbol *SymbolTable::addUndefined(Undefined *); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); -template void -SymbolTable::addLazyArchive(StringRef, ArchiveFile &, - const object::Archive::Symbol); -template void -SymbolTable::addLazyArchive(StringRef, ArchiveFile &, - const object::Archive::Symbol); -template void -SymbolTable::addLazyArchive(StringRef, ArchiveFile &, - const object::Archive::Symbol); -template void -SymbolTable::addLazyArchive(StringRef, ArchiveFile &, - const object::Archive::Symbol); - -template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); -template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); -template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); -template void SymbolTable::addLazyObject(StringRef, LazyObjFile &); +template void SymbolTable::addLazyArchive(LazyArchive *); +template void SymbolTable::addLazyArchive(LazyArchive *); +template void SymbolTable::addLazyArchive(LazyArchive *); +template void SymbolTable::addLazyArchive(LazyArchive *); + +template void SymbolTable::addLazyObject(LazyObject *); +template void SymbolTable::addLazyObject(LazyObject *); +template void SymbolTable::addLazyObject(LazyObject *); +template void SymbolTable::addLazyObject(LazyObject *); template void SymbolTable::fetchLazy(Symbol *); template void SymbolTable::fetchLazy(Symbol *); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -172,10 +172,13 @@ Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther, uint8_t Type) : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding), - Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false), - IsInIplt(false), GotInIgot(false), IsPreemptible(false), - Used(!Config->GcSections), NeedsTocRestore(false), - ScriptDefined(false) {} + Type(Type), StOther(StOther), SymbolKind(K), Visibility(StOther & 3), + IsUsedInRegularObj(!File || File->kind() == InputFile::ObjKind), + ExportDynamic(K != SharedKind && + (Config->Shared || Config->ExportDynamic)), + CanInline(false), Traced(false), NeedsPltAddr(false), IsInIplt(false), + GotInIgot(false), IsPreemptible(false), Used(!Config->GcSections), + NeedsTocRestore(false), ScriptDefined(false) {} public: // True the symbol should point to its PLT entry. @@ -289,10 +292,9 @@ // symbol. class LazyArchive : public Symbol { public: - LazyArchive(InputFile &File, uint8_t Type, - const llvm::object::Archive::Symbol S) + LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S) : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL, - llvm::ELF::STV_DEFAULT, Type), + llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE), Sym(S) {} static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } @@ -308,11 +310,13 @@ // --start-lib and --end-lib options. class LazyObject : public Symbol { public: - LazyObject(InputFile &File, uint8_t Type, StringRef Name) + LazyObject(InputFile &File, StringRef Name) : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL, - llvm::ELF::STV_DEFAULT, Type) {} + llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE) {} static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; } + + InputFile *fetch(); }; // Some linker-generated symbols need to be created as @@ -361,8 +365,7 @@ void printTraceSymbol(Symbol *Sym); -template -void replaceSymbol(Symbol *S, ArgT &&... Arg) { +template void replaceSymbol(Symbol *Sym, T *New) { using llvm::ELF::STT_TLS; static_assert(std::is_trivially_destructible(), @@ -373,34 +376,35 @@ assert(static_cast(static_cast(nullptr)) == nullptr && "Not a Symbol"); - Symbol Sym = *S; - - new (S) T(std::forward(Arg)...); - - 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->ScriptDefined = Sym.ScriptDefined; - // Symbols representing thread-local variables must be referenced by // TLS-aware relocations, and non-TLS symbols must be reference by // non-TLS relocations, so there's a clear distinction between TLS // and non-TLS symbols. It is an error if the same symbol is defined // as a TLS symbol in one file and as a non-TLS symbol in other file. - bool TlsMismatch = (Sym.Type == STT_TLS && S->Type != STT_TLS) || - (Sym.Type != STT_TLS && S->Type == STT_TLS); + if (Sym->SymbolKind != Symbol::PlaceholderKind && !Sym->isLazy() && + !New->isLazy()) { + bool TlsMismatch = (Sym->Type == STT_TLS && New->Type != STT_TLS) || + (Sym->Type != STT_TLS && New->Type == STT_TLS); + if (TlsMismatch) + error("TLS attribute mismatch: " + toString(*Sym) + "\n>>> defined in " + + toString(New->File) + "\n>>> defined in " + toString(Sym->File)); + } + + Symbol Old = *Sym; + memcpy(Sym, New, sizeof(T)); - if (Sym.SymbolKind != Symbol::PlaceholderKind && TlsMismatch && !Sym.isLazy()) - error("TLS attribute mismatch: " + toString(Sym) + "\n>>> defined in " + - toString(Sym.File) + "\n>>> defined in " + toString(S->File)); + Sym->VersionId = Old.VersionId; + Sym->Visibility = Old.Visibility; + Sym->IsUsedInRegularObj = Old.IsUsedInRegularObj; + Sym->ExportDynamic = Old.ExportDynamic; + Sym->CanInline = Old.CanInline; + Sym->Traced = Old.Traced; + Sym->ScriptDefined = Old.ScriptDefined; // Print out a log message if --trace-symbol was specified. // This is for debugging. - if (S->Traced) - printTraceSymbol(S); + if (Sym->Traced) + printTraceSymbol(Sym); } void maybeWarnUnorderableSymbol(const Symbol *Sym); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -250,6 +250,8 @@ Sym.getName()); } +InputFile *LazyObject::fetch() { return cast(File)->fetch(); } + uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -179,14 +179,15 @@ Symbol *S = Symtab->find(Name); if (!S || S->isDefined()) return nullptr; - return Symtab->addDefined(Name, StOther, STT_NOTYPE, Val, - /*Size=*/0, Binding, Sec, - /*File=*/nullptr); + + Defined New(/*File=*/nullptr, Name, Binding, StOther, STT_NOTYPE, Val, + /*Size=*/0, Sec); + return Symtab->addDefined(&New); } static Defined *addAbsolute(StringRef Name) { - return Symtab->addDefined(Name, STV_HIDDEN, STT_NOTYPE, 0, 0, STB_GLOBAL, - nullptr, nullptr); + Defined New(nullptr, Name, STB_GLOBAL, STV_HIDDEN, STT_NOTYPE, 0, 0, nullptr); + return Symtab->addDefined(&New); } // The linker is expected to define some symbols depending on @@ -235,10 +236,10 @@ if (Config->EMachine == EM_PPC || Config->EMachine == EM_PPC64) GotOff = 0x8000; - ElfSym::GlobalOffsetTable = - Symtab->addDefined(GotSymName, STV_HIDDEN, STT_NOTYPE, GotOff, - /*Size=*/0, STB_GLOBAL, Out::ElfHeader, - /*File=*/nullptr); + Defined New(/*File=*/nullptr, GotSymName, STB_GLOBAL, STV_HIDDEN, + STT_NOTYPE, GotOff, + /*Size=*/0, Out::ElfHeader); + ElfSym::GlobalOffsetTable = Symtab->addDefined(&New); } // __ehdr_start is the location of ELF file headers. Note that we define @@ -1587,10 +1588,11 @@ // It should be okay as no one seems to care about the type. // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html - if (In.Dynamic->Parent) - Symtab->addDefined("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/, - /*Size=*/0, STB_WEAK, In.Dynamic, - /*File=*/nullptr); + if (In.Dynamic->Parent) { + Defined New(/*File=*/nullptr, "_DYNAMIC", STB_WEAK, STV_HIDDEN, STT_NOTYPE, + /*Value=*/0, /*Size=*/0, In.Dynamic); + Symtab->addDefined(&New); + } // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols();