diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1419,7 +1419,7 @@ template static Symbol *addUndefined(StringRef Name) { Undefined Sym(nullptr, Name, STB_GLOBAL, STV_DEFAULT, 0); - return Symtab->addUndefined(&Sym); + return Symtab->addSymbol(&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 @@ -914,14 +914,14 @@ switch (Sym->st_shndx) { case SHN_UNDEF: { Undefined S(this, Name, Binding, StOther, Type); - return Symtab->addUndefined(&S); + return Symtab->addSymbol(&S); } case SHN_COMMON: if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); CommonSymbol New(this, Name, Binding, StOther, Type, Value, Size); - return Symtab->addCommon(&New); + return Symtab->addSymbol(&New); } switch (Binding) { @@ -932,11 +932,11 @@ case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) { Undefined S(this, Name, Binding, StOther, Type); - return Symtab->addUndefined(&S); + return Symtab->addSymbol(&S); } Defined New(this, Name, Binding, StOther, Type, Value, Size, Sec); - return Symtab->addDefined(&New); + return Symtab->addSymbol(&New); } } @@ -947,7 +947,7 @@ void ArchiveFile::parse() { for (const Archive::Symbol &Sym : File->symbols()) { LazyArchive New(*this, Sym); - Symtab->addLazyArchive(&New); + Symtab->addSymbol(&New); } } @@ -1150,7 +1150,7 @@ if (Sym.isUndefined()) { Undefined New(this, Name, Sym.getBinding(), Sym.st_other, Sym.getType()); - Symbol *S = Symtab->addUndefined(&New); + Symbol *S = Symtab->addSymbol(&New); S->ExportDynamic = true; continue; } @@ -1167,7 +1167,7 @@ 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); + Symtab->addSymbol(&S); } // Also add the symbol with the versioned name to handle undefined symbols @@ -1190,7 +1190,7 @@ SharedSymbol S(*this, Saver.save(Name), Sym.getBinding(), Sym.st_other, Sym.getType(), Sym.st_value, Sym.st_size, Alignment, Idx); - Symtab->addShared(&S); + Symtab->addSymbol(&S); } } @@ -1290,19 +1290,19 @@ Undefined New(&F, Name, Binding, Visibility, Type); if (CanOmitFromDynSym) New.ExportDynamic = false; - return Symtab->addUndefined(&New); + return Symtab->addSymbol(&New); } if (ObjSym.isCommon()) { CommonSymbol New(&F, Name, Binding, Visibility, STT_OBJECT, ObjSym.getCommonAlignment(), ObjSym.getCommonSize()); - return Symtab->addCommon(&New); + return Symtab->addSymbol(&New); } Defined New(&F, Name, Binding, Visibility, Type, 0, 0, nullptr); if (CanOmitFromDynSym) New.ExportDynamic = false; - return Symtab->addDefined(&New); + return Symtab->addSymbol(&New); } template @@ -1367,9 +1367,9 @@ 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); + Symtab->addSymbol(&Sym1); + Symtab->addSymbol(&Sym2); + Symtab->addSymbol(&Sym3); } InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, @@ -1438,7 +1438,7 @@ if (Sym.isUndefined()) continue; LazyObject New(*this, Saver.save(Sym.getName())); - Symtab->addLazyObject(&New); + Symtab->addSymbol(&New); } return; } @@ -1464,7 +1464,7 @@ if (Sym.st_shndx == SHN_UNDEF) continue; LazyObject New(*this, CHECK(Sym.getName(StringTable), this)); - Symtab->addLazyObject(&New); + Symtab->addSymbol(&New); } return; } diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -186,8 +186,8 @@ Defined New(nullptr, Cmd->Name, STB_GLOBAL, Visibility, STT_NOTYPE, SymValue, 0, Sec); - Symbol *Sym = Symtab->insert(&New); - Symtab->mergeProperties(Sym, &New); + Symbol *Sym = Symtab->insert(Cmd->Name); + mergeSymbolProperties(Sym, &New); replaceSymbol(Sym, &New); Cmd->Sym = cast(Sym); } @@ -203,8 +203,8 @@ nullptr); // We can't calculate final value right now. - Symbol *Sym = Symtab->insert(&New); - Symtab->mergeProperties(Sym, &New); + Symbol *Sym = Symtab->insert(Cmd->Name); + mergeSymbolProperties(Sym, &New); replaceSymbol(Sym, &New); Cmd->Sym = cast(Sym); diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -45,15 +45,9 @@ ArrayRef getSymbols() const { return SymVector; } - Symbol *addCommon(CommonSymbol *New); - Symbol *addDefined(Defined *New); - Symbol *addLazyArchive(LazyArchive *New); - Symbol *addLazyObject(LazyObject *New); - Symbol *addShared(SharedSymbol *New); - Symbol *addUndefined(Undefined *New); + Symbol *insert(StringRef Name); - Symbol *insert(Symbol *New); - void mergeProperties(Symbol *Old, Symbol *New); + Symbol *addSymbol(Symbol *New); void fetchLazy(Symbol *Sym); @@ -69,8 +63,6 @@ llvm::DenseMap SoNames; private: - template Symbol *addLazy(LazyT *New); - std::vector findByVersion(SymbolVersion Ver); std::vector findAllByVersion(SymbolVersion Ver); @@ -106,6 +98,10 @@ }; extern SymbolTable *Symtab; + +void mergeSymbolProperties(Symbol *Old, Symbol *New); +void resolveSymbol(Symbol *Old, Symbol *New); + } // namespace elf } // namespace lld diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -86,18 +86,14 @@ return std::min(VA, VB); } -// Find an existing symbol or create and insert a new one, then apply the given -// attributes. -Symbol *SymbolTable::insert(Symbol *New) { - // Find an existing symbol or create and insert a new one. - +// Find an existing symbol or create a new one. +Symbol *SymbolTable::insert(StringRef Name) { // @@ 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); @@ -113,51 +109,35 @@ Traced = 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]; - } - - return Old; + if (!IsNew) + return SymVector[SymIndex]; + + Symbol *Sym = reinterpret_cast(make()); + SymVector.push_back(Sym); + + Sym->SymbolKind = Symbol::PlaceholderKind; + Sym->VersionId = Config->DefaultSymbolVersion; + Sym->Visibility = STV_DEFAULT; + Sym->IsUsedInRegularObj = false; + Sym->ExportDynamic = false; + Sym->CanInline = true; + Sym->Traced = Traced; + Sym->ScriptDefined = false; + return Sym; } -// -void SymbolTable::mergeProperties(Symbol *Old, Symbol *New) { - // 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); +Symbol *SymbolTable::addSymbol(Symbol *New) { + Symbol *Old = Symtab->insert(New->getName()); + resolveSymbol(Old, New); + return Old; } -Symbol *SymbolTable::addUndefined(Undefined *New) { - Symbol *Old = insert(New); - mergeProperties(Old, New); - - if (Old->isPlaceholder()) { - replaceSymbol(Old, New); - return Old; - } - +static void addUndefined(Symbol *Old, Undefined *New) { // An undefined symbol with non default visibility must be satisfied // in the same DSO. if (isa(Old) && New->Visibility != STV_DEFAULT) { replaceSymbol(Old, New); - return Old; + return; } if (Old->isShared() || Old->isLazy() || @@ -169,7 +149,7 @@ // Symbols.h for the details. if (New->Binding == STB_WEAK) { Old->Type = New->Type; - return Old; + return; } // Do extra check for --warn-backrefs. @@ -224,7 +204,7 @@ // group assignment rule simulates the traditional linker's semantics. bool Backref = Config->WarnBackrefs && New->File && Old->File->GroupId < New->File->GroupId; - fetchLazy(Old); + Symtab->fetchLazy(Old); // We don't report backward references to weak symbols as they can be // overridden later. @@ -232,7 +212,6 @@ warn("backward reference detected: " + New->getName() + " in " + toString(New->File) + " refers to " + toString(Old->File)); } - return Old; } // Using .symver foo,foo@@VER unfortunately creates two symbols: foo and @@ -299,22 +278,14 @@ return 0; } -Symbol *SymbolTable::addCommon(CommonSymbol *New) { - Symbol *Old = insert(New); - mergeProperties(Old, New); - - if (Old->isPlaceholder()) { - replaceSymbol(Old, New); - return Old; - } - +static void addCommon(Symbol *Old, CommonSymbol *New) { int Cmp = compare(Old, New); if (Cmp < 0) - return Old; + return; if (Cmp > 0) { replaceSymbol(Old, New); - return Old; + return; } auto *OldSym = cast(Old); @@ -324,7 +295,6 @@ OldSym->File = New->File; OldSym->Size = New->Size; } - return OldSym; } static void reportDuplicate(Symbol *Sym, InputFile *NewFile, @@ -362,15 +332,7 @@ error(Msg); } -Symbol *SymbolTable::addDefined(Defined *New) { - Symbol *Old = insert(New); - mergeProperties(Old, New); - - if (Old->isPlaceholder()) { - replaceSymbol(Old, New); - return Old; - } - +static void addDefined(Symbol *Old, Defined *New) { int Cmp = compare(Old, New); if (Cmp > 0) replaceSymbol(Old, New); @@ -378,23 +340,9 @@ reportDuplicate(Old, New->File, dyn_cast_or_null(New->Section), New->Value); - - return Old; } -Symbol *SymbolTable::addShared(SharedSymbol *New) { - Symbol *Old = insert(New); - mergeProperties(Old, New); - - // Make sure we preempt DSO symbols with default visibility. - if (New->Visibility == STV_DEFAULT) - Old->ExportDynamic = true; - - if (Old->isPlaceholder()) { - replaceSymbol(Old, New); - return Old; - } - +static void addShared(Symbol *Old, SharedSymbol *New) { if (Old->Visibility == STV_DEFAULT && (Old->isUndefined() || Old->isLazy())) { // An undefined symbol with non default visibility must be satisfied // in the same DSO. @@ -402,7 +350,6 @@ replaceSymbol(Old, New); Old->Binding = Binding; } - return Old; } Symbol *SymbolTable::find(StringRef Name) { @@ -414,17 +361,9 @@ return SymVector[It->second]; } -template Symbol *SymbolTable::addLazy(LazyT *New) { - Symbol *Old = insert(New); - mergeProperties(Old, New); - - if (Old->isPlaceholder()) { - replaceSymbol(Old, New); - return Old; - } - +template static void addLazy(Symbol *Old, LazyT *New) { if (!Old->isUndefined()) - return Old; + return; // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. @@ -433,17 +372,16 @@ replaceSymbol(Old, New); Old->Type = Type; Old->Binding = STB_WEAK; - return Old; + return; } if (InputFile *F = New->fetch()) parseFile(F); - return Old; } -Symbol *SymbolTable::addLazyArchive(LazyArchive *New) { return addLazy(New); } +static void addLazyArchive(Symbol *Old, LazyArchive *New) { addLazy(Old, New); } -Symbol *SymbolTable::addLazyObject(LazyObject *New) { return addLazy(New); } +static void addLazyObject(Symbol *Old, LazyObject *New) { addLazy(Old, New); } void SymbolTable::fetchLazy(Symbol *Sym) { if (auto *S = dyn_cast(Sym)) { @@ -618,6 +556,40 @@ Sym->parseSymbolVersion(); } +void elf::mergeSymbolProperties(Symbol *Old, Symbol *New) { + // 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); +} + +void elf::resolveSymbol(Symbol *Old, Symbol *New) { + mergeSymbolProperties(Old, New); + + if (Old->isPlaceholder()) { + replaceSymbol(Old, New); + return; + } + + if (auto *Sym = dyn_cast(New)) + addUndefined(Old, Sym); + else if (auto *Sym = dyn_cast(New)) + addCommon(Old, Sym); + else if (auto *Sym = dyn_cast(New)) + addDefined(Old, Sym); + else if (auto *Sym = dyn_cast(New)) + addLazyArchive(Old, Sym); + else if (auto *Sym = dyn_cast(New)) + addLazyObject(Old, Sym); + else if (auto *Sym = dyn_cast(New)) + addShared(Old, Sym); + else + llvm_unreachable("unknown symbol type"); +} + template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); template void SymbolTable::addCombinedLTOObject(); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -172,17 +172,23 @@ uint64_t getSize() const; OutputSection *getOutputSection() const; +private: + bool isExportDynamic(Kind K, uint8_t Visibility) { + if (K == SharedKind) + return Visibility == llvm::ELF::STV_DEFAULT; + return Config->Shared || Config->ExportDynamic; + } + protected: 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), 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) {} + ExportDynamic(isExportDynamic(K, Visibility)), 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. @@ -392,24 +398,55 @@ // using the placement new. union SymbolUnion { alignas(Defined) char A[sizeof(Defined)]; + alignas(CommonSymbol) char B[sizeof(CommonSymbol)]; 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); - -template void replaceSymbol(Symbol *Sym, T *New) { - using llvm::ELF::STT_TLS; - +template struct AssertSymbol { static_assert(std::is_trivially_destructible(), "Symbol types must be trivially destructible"); 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 Symbol"); +}; + +static inline void assertSymbols() { + AssertSymbol(); + AssertSymbol(); + AssertSymbol(); + AssertSymbol(); + AssertSymbol(); + AssertSymbol(); +} + +void printTraceSymbol(Symbol *Sym); + +static size_t getSymbolSize(Symbol *Sym) { + switch (Sym->SymbolKind) { + case Symbol::CommonKind: + return sizeof(CommonSymbol); + case Symbol::DefinedKind: + return sizeof(Defined); + case Symbol::LazyArchiveKind: + return sizeof(LazyArchive); + case Symbol::LazyObjectKind: + return sizeof(LazyObject); + case Symbol::SharedKind: + return sizeof(SharedSymbol); + case Symbol::UndefinedKind: + return sizeof(Undefined); + case Symbol::PlaceholderKind: + return sizeof(Symbol); + default: + llvm_unreachable("unknown symbol type"); + } +} + +inline void replaceSymbol(Symbol *Sym, Symbol *New) { + using llvm::ELF::STT_TLS; // Symbols representing thread-local variables must be referenced by // TLS-aware relocations, and non-TLS symbols must be reference by @@ -426,7 +463,7 @@ } Symbol Old = *Sym; - memcpy(Sym, New, sizeof(T)); + memcpy(Sym, New, getSymbolSize(New)); Sym->VersionId = Old.VersionId; Sym->Visibility = Old.Visibility; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -182,12 +182,12 @@ Defined New(/*File=*/nullptr, Name, Binding, StOther, STT_NOTYPE, Val, /*Size=*/0, Sec); - return cast(Symtab->addDefined(&New)); + return cast(Symtab->addSymbol(&New)); } static Defined *addAbsolute(StringRef Name) { Defined New(nullptr, Name, STB_GLOBAL, STV_HIDDEN, STT_NOTYPE, 0, 0, nullptr); - Symbol *Sym = Symtab->addDefined(&New); + Symbol *Sym = Symtab->addSymbol(&New); if (!Sym->isDefined()) error("duplicate symbol: " + toString(*Sym)); return cast(Sym); @@ -241,7 +241,7 @@ Defined New(/*File=*/nullptr, GotSymName, STB_GLOBAL, STV_HIDDEN, STT_NOTYPE, GotOff, /*Size=*/0, Out::ElfHeader); - Symtab->addDefined(&New); + Symtab->addSymbol(&New); ElfSym::GlobalOffsetTable = cast(S); } @@ -1594,7 +1594,7 @@ if (In.Dynamic->Parent) { Defined New(/*File=*/nullptr, "_DYNAMIC", STB_WEAK, STV_HIDDEN, STT_NOTYPE, /*Value=*/0, /*Size=*/0, In.Dynamic); - Symtab->addDefined(&New); + Symtab->addSymbol(&New); } // Define __rel[a]_iplt_{start,end} symbols if needed.