Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -1329,14 +1329,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; } } @@ -1405,8 +1405,8 @@ } template static Symbol *addUndefined(StringRef Name) { - return Symtab->addUndefined(Name, STB_GLOBAL, STV_DEFAULT, 0, false, - nullptr); + return Symtab->addUndefined( + Undefined{nullptr, Name, STB_GLOBAL, STV_DEFAULT, 0}); } // The --wrap option is a feature to rename symbols so that you can write Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -864,13 +864,12 @@ } template Symbol *ObjFile::createSymbol(const Elf_Sym *Sym) { - int Binding = Sym->getBinding(); - uint32_t SecIdx = getSectionIndex(*Sym); if (SecIdx >= this->Sections.size()) fatal(toString(this) + ": invalid section index: " + Twine(SecIdx)); InputSectionBase *Sec = this->Sections[SecIdx]; + uint8_t Binding = Sym->getBinding(); uint8_t StOther = Sym->st_other; uint8_t Type = Sym->getType(); uint64_t Value = Sym->st_value; @@ -886,7 +885,6 @@ StringRefZ Name = this->StringTable.data() + Sym->st_name; if (Sym->st_shndx == SHN_UNDEF) return make(this, Name, Binding, StOther, Type); - return make(this, Name, Binding, StOther, Type, Value, Size, Sec); } @@ -894,26 +892,27 @@ switch (Sym->st_shndx) { case SHN_UNDEF: - return Symtab->addUndefined(Name, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this); + return Symtab->addUndefined( + Undefined{this, Name, Binding, StOther, Type}); 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); + return Symtab->addCommon( + Defined{this, Name, Binding, StOther, Type, Value, Size, nullptr}); } switch (Binding) { default: - fatal(toString(this) + ": unexpected binding: " + Twine(Binding)); + fatal(toString(this) + ": unexpected binding: " + Twine((int)Binding)); 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); + return Symtab->addUndefined( + Undefined{this, Name, Binding, StOther, Type}); + return Symtab->addDefined( + Defined{this, Name, Binding, StOther, Type, Value, Size, Sec}); } } @@ -923,7 +922,7 @@ template void ArchiveFile::parse() { for (const Archive::Symbol &Sym : File->symbols()) - Symtab->addLazyArchive(Sym.getName(), *this, Sym); + Symtab->addLazyArchive(LazyArchive{*this, Sym}); } // Returns a buffer pointing to a member file containing a given symbol. @@ -1124,9 +1123,8 @@ } if (Sym.isUndefined()) { - Symbol *S = Symtab->addUndefined(Name, Sym.getBinding(), - Sym.st_other, Sym.getType(), - /*CanOmitFromDynSym=*/false, this); + Symbol *S = Symtab->addUndefined( + Undefined{this, Name, Sym.getBinding(), Sym.st_other, Sym.getType()}); S->ExportDynamic = true; continue; } @@ -1139,10 +1137,12 @@ Name == "_gp_disp") 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); + uint32_t Alignment = getAlignment(Sections, Sym); + if (!(Versyms[I] & VERSYM_HIDDEN)) { + Symtab->addShared(SharedSymbol{*this, Name, Sym.getBinding(), + Sym.st_other, Sym.getType(), Sym.st_value, + Sym.st_size, Alignment, Idx}); + } // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. @@ -1161,9 +1161,9 @@ 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); + Symtab->addShared(SharedSymbol{*this, Saver.save(Name), Sym.getBinding(), + Sym.st_other, Sym.getType(), Sym.st_value, + Sym.st_size, Alignment, Idx}); } } @@ -1252,28 +1252,28 @@ const lto::InputFile::Symbol &ObjSym, BitcodeFile &F) { StringRef Name = Saver.save(ObjSym.getName()); - uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; - + uint8_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE; uint8_t Visibility = mapVisibility(ObjSym.getVisibility()); 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); - - return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym, - F); + return Symtab->addCommon(Defined{&F, Name, Binding, Visibility, STT_OBJECT, + ObjSym.getCommonAlignment(), + ObjSym.getCommonSize(), nullptr}); + + Defined New(&F, Name, Binding, Visibility, Type, 0, 0, nullptr); + if (CanOmitFromDynSym) + New.ExportDynamic = false; + return Symtab->addBitcode(New); } template @@ -1331,12 +1331,12 @@ 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); + Symtab->addDefined(Defined{nullptr, Saver.save(S + "_start"), STB_GLOBAL, + STV_DEFAULT, STT_OBJECT, 0, 0, Section}); + Symtab->addDefined(Defined{nullptr, Saver.save(S + "_end"), STB_GLOBAL, + STV_DEFAULT, STT_OBJECT, Data.size(), 0, Section}); + Symtab->addDefined(Defined{nullptr, Saver.save(S + "_size"), STB_GLOBAL, + STV_DEFAULT, STT_OBJECT, Data.size(), 0, nullptr}); } InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, @@ -1401,9 +1401,11 @@ 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; + Symtab->addLazyObject(LazyObject{*this, Saver.save(Sym.getName())}); + } return; } @@ -1424,10 +1426,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; + Symtab->addLazyObject( + LazyObject{*this, CHECK(Sym.getName(StringTable), this)}); + } return; } } Index: lld/trunk/ELF/LTO.cpp =================================================================== --- lld/trunk/ELF/LTO.cpp +++ lld/trunk/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) { Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/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; Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/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; Index: lld/trunk/ELF/SymbolTable.h =================================================================== --- lld/trunk/ELF/SymbolTable.h +++ lld/trunk/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(const Undefined &New); - template - void addLazyArchive(StringRef Name, ArchiveFile &F, - const llvm::object::Archive::Symbol S); + Defined *addDefined(const Defined &New); - template void addLazyObject(StringRef Name, LazyObjFile &Obj); + void addShared(const SharedSymbol &New); - Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type, bool CanOmitFromDynSym, BitcodeFile &File); + template void addLazyArchive(const LazyArchive &New); + template void addLazyObject(const 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(const Defined &New); + Symbol *addCommon(const Defined &New); - std::pair insert(StringRef Name, uint8_t Visibility, - bool CanOmitFromDynSym, InputFile *File); + std::pair insert(const Symbol &New); template void fetchLazy(Symbol *Sym); @@ -81,7 +72,7 @@ llvm::DenseMap SoNames; private: - std::pair insertName(StringRef Name); + template void addLazy(const LazyT &New); std::vector findByVersion(SymbolVersion Ver); std::vector findAllByVersion(SymbolVersion Ver); Index: lld/trunk/ELF/SymbolTable.cpp =================================================================== --- lld/trunk/ELF/SymbolTable.cpp +++ lld/trunk/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(const 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); - - if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) - S->ExportDynamic = true; - - if (!File || File->kind() == InputFile::ObjKind) - S->IsUsedInRegularObj = true; + 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]; + } + + // Merge symbol properties. + Old->ExportDynamic = Old->ExportDynamic || New.ExportDynamic; + Old->IsUsedInRegularObj = Old->IsUsedInRegularObj || New.IsUsedInRegularObj; + + // 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(const 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(const Symbol *Old, const 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,77 @@ // 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(const Symbol *OldSym, const 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(const Defined &New) { + Symbol *Old; bool WasInserted; - std::tie(S, WasInserted) = insert(N, getVisibility(StOther), - /*CanOmitFromDynSym*/ false, &File); - - int Cmp = compareDefined(S, WasInserted, Binding, N); - if (Cmp < 0) - return S; + std::tie(Old, WasInserted) = insert(New); - 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; + Defined Sym = New; + Sym.Value = 0; + Sym.Section = Bss; + replaceSymbol(Old, &Sym); + }; + + 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 +371,62 @@ 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(const 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(const 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(const 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(const 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(const LazyArchive &New) { + addLazy(New); +} - if (InputFile *F = File.fetch()) - parseFile(F); +template void SymbolTable::addLazyObject(const 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(const Undefined &); +template Symbol *SymbolTable::addUndefined(const Undefined &); +template Symbol *SymbolTable::addUndefined(const Undefined &); +template Symbol *SymbolTable::addUndefined(const 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(const LazyArchive &); +template void SymbolTable::addLazyArchive(const LazyArchive &); +template void SymbolTable::addLazyArchive(const LazyArchive &); +template void SymbolTable::addLazyArchive(const LazyArchive &); + +template void SymbolTable::addLazyObject(const LazyObject &); +template void SymbolTable::addLazyObject(const LazyObject &); +template void SymbolTable::addLazyObject(const LazyObject &); +template void SymbolTable::addLazyObject(const LazyObject &); template void SymbolTable::fetchLazy(Symbol *); template void SymbolTable::fetchLazy(Symbol *); Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/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,15 +292,14 @@ // 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; } - InputFile *fetch(); + InputFile *fetch() const; MemoryBufferRef getMemberBuffer(); private: @@ -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() const; }; // 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, const 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); Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -239,7 +239,9 @@ Verstr); } -InputFile *LazyArchive::fetch() { return cast(File)->fetch(Sym); } +InputFile *LazyArchive::fetch() const { + return cast(File)->fetch(Sym); +} MemoryBufferRef LazyArchive::getMemberBuffer() { Archive::Child C = CHECK( @@ -250,6 +252,10 @@ Sym.getName()); } +InputFile *LazyObject::fetch() const { + return cast(File)->fetch(); +} + uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/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); + + return Symtab->addDefined(Defined{/*File=*/nullptr, Name, Binding, StOther, + STT_NOTYPE, Val, + /*Size=*/0, Sec}); } static Defined *addAbsolute(StringRef Name) { - return Symtab->addDefined(Name, STV_HIDDEN, STT_NOTYPE, 0, 0, STB_GLOBAL, - nullptr, nullptr); + return Symtab->addDefined(Defined{nullptr, Name, STB_GLOBAL, STV_HIDDEN, + STT_NOTYPE, 0, 0, nullptr}); } // The linker is expected to define some symbols depending on @@ -236,9 +237,9 @@ GotOff = 0x8000; ElfSym::GlobalOffsetTable = - Symtab->addDefined(GotSymName, STV_HIDDEN, STT_NOTYPE, GotOff, - /*Size=*/0, STB_GLOBAL, Out::ElfHeader, - /*File=*/nullptr); + Symtab->addDefined(Defined{/*File=*/nullptr, GotSymName, STB_GLOBAL, + STV_HIDDEN, STT_NOTYPE, GotOff, + /*Size=*/0, Out::ElfHeader}); } // __ehdr_start is the location of ELF file headers. Note that we define @@ -1588,9 +1589,9 @@ // 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); + Symtab->addDefined(Defined{/*File=*/nullptr, "_DYNAMIC", STB_WEAK, + STV_HIDDEN, STT_NOTYPE, + /*Value=*/0, /*Size=*/0, In.Dynamic}); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols();