Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -437,7 +437,7 @@ // Set either EntryAddr (if S is a number) or EntrySym (otherwise). StringRef S = Config->Entry; if (S.getAsInteger(0, Config->EntryAddr)) - Config->EntrySym = Symtab.addUndefined(S)->getSymbol(); + Config->EntrySym = Symtab.addUndefined(S)->Backref; } for (std::unique_ptr &F : Files) Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -76,13 +76,13 @@ static bool shouldInternalize(const SmallPtrSet &Used, SymbolBody &B, GlobalValue *GV) { - if (B.isUsedInRegularObj()) + if (B.Backref->IsUsedInRegularObj) return false; if (Used.count(GV)) return false; - return !B.includeInDynsym(); + return !B.Backref->includeInDynsym(); } void BitcodeCompiler::add(BitcodeFile &F) { Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -113,13 +113,10 @@ // Preserve externally-visible symbols if the symbols defined by this // file can interrupt other ELF file's symbols at runtime. - if (Config->Shared || Config->ExportDynamic) { - for (const Symbol *S : Symtab->getSymbols()) { - SymbolBody *B = S->Body; - if (B->includeInDynsym()) - MarkSymbol(B); - } - } + if (Config->Shared || Config->ExportDynamic) + for (const Symbol *S : Symtab->getSymbols()) + if (S->includeInDynsym()) + MarkSymbol(S->Body); // Preserve special sections and those which are specified in linker // script KEEP command. Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1355,7 +1355,7 @@ } static uint8_t getSymbolBinding(SymbolBody *Body) { - uint8_t Visibility = Body->getVisibility(); + uint8_t Visibility = Body->Backref->Visibility; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; if (Config->NoGnuUnique && Body->Binding == STB_GNU_UNIQUE) @@ -1440,12 +1440,6 @@ } } -static uint8_t getSymbolVisibility(SymbolBody *Body) { - if (Body->isShared()) - return STV_DEFAULT; - return Body->getVisibility(); -} - template void SymbolTableSection::writeGlobalSymbols(uint8_t *Buf) { // Write the internal symbol table contents to the output symbol table @@ -1461,7 +1455,7 @@ ESym->setBindingAndType(getSymbolBinding(Body), Type); ESym->st_size = Size; ESym->st_name = StrOff; - ESym->setVisibility(getSymbolVisibility(Body)); + ESym->setVisibility(Body->Backref->Visibility); ESym->st_value = Body->getVA(); if (const OutputSectionBase *OutSec = getOutputSection(Body)) Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -132,11 +132,6 @@ Obj->parse(DummyGroups); for (SymbolBody *Body : Obj->getNonLocalSymbols()) { Symbol *Sym = insert(Body); - Sym->Body->setUsedInRegularObj(); - if (Sym->Body->isShared()) - Sym->Body->MustBeInDynSym = true; - if (Sym->Body->MustBeInDynSym) - Body->MustBeInDynSym = true; if (!Sym->Body->isUndefined() && Body->isUndefined()) continue; Sym->Body = Body; @@ -198,9 +193,9 @@ if (Symtab.count(Name) == 0) return; StringSaver Saver(Alloc); - Symbol *Sym = addUndefined(Name)->getSymbol(); - Symbol *Real = addUndefined(Saver.save("__real_" + Name))->getSymbol(); - Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->getSymbol(); + Symbol *Sym = addUndefined(Name)->Backref; + Symbol *Real = addUndefined(Saver.save("__real_" + Name))->Backref; + Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->Backref; Real->Body = Sym->Body; Sym->Body = Wrap->Body; } @@ -247,8 +242,6 @@ } // Found a definition for something also in an archive. // Ignore the archive definition. - if (L->isUsedInRegularObj()) - New->setUsedInRegularObj(); Sym->Body = New; return; } @@ -273,6 +266,24 @@ Sym->Body = New; } +static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { + if (VA == STV_DEFAULT) + return VB; + if (VB == STV_DEFAULT) + return VA; + return std::min(VA, VB); +} + +static bool shouldExport(SymbolBody *B) { + if (Config->Shared || Config->ExportDynamic) { + // Export most symbols except for those that do not need to be exported. + return !B->CanOmitFromDynSym; + } else { + // Make sure we preempt DSO symbols with default visibility. + return B->isShared() && B->getVisibility() == STV_DEFAULT; + } +} + // Find an existing symbol or create and insert a new one. template Symbol *SymbolTable::insert(SymbolBody *New) { StringRef Name = New->getName(); @@ -280,12 +291,24 @@ auto P = Symtab.insert(std::make_pair(Name, NumSyms)); Symbol *Sym; if (P.second) { - Sym = new (Alloc) Symbol{New}; + Sym = new (Alloc) Symbol{New, STV_DEFAULT, false, false}; SymVector.push_back(Sym); } else { Sym = SymVector[P.first->second]; } - New->setBackref(Sym); + New->Backref = Sym; + + // Merge in the new symbol's visibility. DSO symbols do not affect visibility + // in the output. + if (!New->isShared()) + Sym->Visibility = getMinVisibility(Sym->Visibility, New->getVisibility()); + Sym->ExportDynamic = Sym->ExportDynamic || shouldExport(New); + SymbolBody::Kind K = New->kind(); + if (K == SymbolBody::DefinedRegularKind || + K == SymbolBody::DefinedCommonKind || + K == SymbolBody::DefinedSyntheticKind || + K == SymbolBody::UndefinedElfKind) + Sym->IsUsedInRegularObj = true; return Sym; } @@ -309,8 +332,6 @@ template void SymbolTable::addMemberFile(SymbolBody *Undef, Lazy *L) { - if (Undef->isUsedInRegularObj()) - L->setUsedInRegularObj(); // Weak undefined symbols should not fetch members from archives. // If we were to keep old symbol we would not know that an archive member was // available if a strong undefined symbol shows up afterwards in the link. @@ -319,7 +340,6 @@ // We set UsedInRegularObj in a similar way to what is done with shared // symbols and copy information to reduce how many special cases are needed. if (Undef->isWeak()) { - L->setUsedInRegularObj(); L->Binding = Undef->Binding; L->Type = Undef->Type; @@ -345,7 +365,7 @@ for (StringRef U : File->getUndefinedSymbols()) if (SymbolBody *Sym = find(U)) if (Sym->isDefined()) - Sym->MustBeInDynSym = true; + Sym->Backref->ExportDynamic = true; } // This function process the dynamic list option by marking all the symbols @@ -353,7 +373,7 @@ template void SymbolTable::scanDynamicList() { for (StringRef S : Config->DynamicList) if (SymbolBody *B = find(S)) - B->MustBeInDynSym = true; + B->Backref->ExportDynamic = true; } template class elf::SymbolTable; Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -40,8 +40,27 @@ // A real symbol object, SymbolBody, is usually accessed indirectly // through a Symbol. There's always one Symbol for each symbol name. // The resolver updates SymbolBody pointers as it resolves symbols. +// Symbol also holds computed properties of symbol names. struct Symbol { SymbolBody *Body; + + // 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; + + bool includeInDynsym() const; }; // The base class for real symbol classes. @@ -76,7 +95,6 @@ } bool isShared() const { return SymbolKind == SharedKind; } bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; } - bool isUsedInRegularObj() const { return IsUsedInRegularObj; } bool isPreemptible() const; // Returns the symbol name. @@ -102,8 +120,6 @@ bool isInPlt() const { return PltIndex != -1U; } bool hasThunk() const { return ThunkIndex != -1U; } - void setUsedInRegularObj() { IsUsedInRegularObj = true; } - template typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const; @@ -121,17 +137,13 @@ // pointer P to a SymbolBody and are not sure whether the resolver // has chosen the object among other objects having the same name, // you can access P->Backref->Body to get the resolver's result. - void setBackref(Symbol *P) { Backref = P; } SymbolBody &repl() { return Backref ? *Backref->Body : *this; } - Symbol *getSymbol() const { return Backref; } // Decides which symbol should "win" in the symbol table, this or // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if // they are duplicate (conflicting) symbols. int compare(SymbolBody *Other); - bool includeInDynsym() const; - protected: SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type); @@ -140,12 +152,6 @@ const unsigned SymbolKind : 8; - // True if the symbol was used for linking and thus need to be - // added to the output file's symbol table. It is usually true, - // but if it is a shared symbol that were not referenced by anyone, - // it can be false. - unsigned IsUsedInRegularObj : 1; - public: // True if this symbol can be omitted from the symbol table if nothing else // requires it to be there. Right now this is only used for linkonce_odr in @@ -153,9 +159,6 @@ // MachO's .weak_def_can_be_hidden. unsigned CanOmitFromDynSym : 1; - // If true, the symbol is added to .dynsym symbol table. - unsigned MustBeInDynSym : 1; - // True if the linker has to generate a copy relocation for this shared // symbol or if the symbol should point to its plt entry. unsigned NeedsCopyOrPltAddr : 1; @@ -173,7 +176,8 @@ bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; } bool isObject() const { return Type == llvm::ELF::STT_OBJECT; } bool isFile() const { return Type == llvm::ELF::STT_FILE; } - void setVisibility(uint8_t V) { StOther = (StOther & ~0x3) | V; } + + Symbol *Backref = nullptr; protected: struct Str { @@ -184,7 +188,6 @@ Str Name; uint32_t NameOffset; }; - Symbol *Backref = nullptr; }; // The base class for any defined symbols. Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -80,7 +80,7 @@ return 0; case SymbolBody::LazyArchiveKind: case SymbolBody::LazyObjectKind: - assert(Body.isUsedInRegularObj() && "lazy symbol reached writer"); + assert(Body.Backref->IsUsedInRegularObj && "lazy symbol reached writer"); return 0; case SymbolBody::DefinedBitcodeKind: llvm_unreachable("should have been replaced"); @@ -104,13 +104,9 @@ } void SymbolBody::init() { - Kind K = kind(); - IsUsedInRegularObj = K == DefinedRegularKind || K == DefinedCommonKind || - K == DefinedSyntheticKind || K == UndefinedElfKind; CanKeepUndefined = false; - MustBeInDynSym = false; - CanOmitFromDynSym = false; NeedsCopyOrPltAddr = false; + CanOmitFromDynSym = false; } // Returns true if a symbol can be replaced at load-time by a symbol @@ -122,7 +118,7 @@ if (isShared()) return true; - if (getVisibility() != STV_DEFAULT) + if (Backref->Visibility != STV_DEFAULT) return false; if (isUndefined()) { @@ -193,14 +189,6 @@ return 0; } -static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { - if (VA == STV_DEFAULT) - return VB; - if (VB == STV_DEFAULT) - return VA; - return std::min(VA, VB); -} - static int compareCommons(DefinedCommon *A, DefinedCommon *B) { if (Config->WarnCommon) warning("multiple common of " + A->getName()); @@ -220,31 +208,6 @@ if (L > R) return -Other->compare(this); - uint8_t V = getMinVisibility(getVisibility(), Other->getVisibility()); - if (isShared() != Other->isShared()) { - SymbolBody *Shared = isShared() ? this : Other; - Shared->MustBeInDynSym = true; - if (Shared->getVisibility() == STV_DEFAULT && - (V == STV_DEFAULT || V == STV_PROTECTED)) { - // We want to export all symbols that exist in the executable and are - // preemptable in DSOs, so that the symbols in the executable can - // preempt symbols in the DSO at runtime. - SymbolBody *NonShared = isShared() ? Other : this; - NonShared->MustBeInDynSym = true; - } - } - - if (!isShared() && !Other->isShared()) { - setVisibility(V); - Other->setVisibility(V); - } - - if (IsUsedInRegularObj || Other->IsUsedInRegularObj) - IsUsedInRegularObj = Other->IsUsedInRegularObj = true; - - if (!CanOmitFromDynSym || !Other->CanOmitFromDynSym) - CanOmitFromDynSym = Other->CanOmitFromDynSym = false; - if (L != R) return -1; if (!isDefined() || isShared() || isWeak()) @@ -358,15 +321,10 @@ #endif } -bool SymbolBody::includeInDynsym() const { - if (MustBeInDynSym) - return true; - uint8_t V = getVisibility(); - if (V != STV_DEFAULT && V != STV_PROTECTED) - return false; - if (!Config->ExportDynamic && !Config->Shared) +bool Symbol::includeInDynsym() const { + if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return false; - return !CanOmitFromDynSym; + return ExportDynamic || Body->isShared(); } template uint32_t SymbolBody::template getVA(uint32_t) const; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -977,8 +977,7 @@ continue; S.OffsetInBss = Off; S.NeedsCopyOrPltAddr = true; - S.setUsedInRegularObj(); - S.MustBeInDynSym = true; + S.Backref->IsUsedInRegularObj = true; } Out::RelaDyn->addReloc( {Target->CopyRel, Out::Bss, SS->OffsetInBss, false, SS, 0}); @@ -1042,7 +1041,7 @@ } template static bool includeInSymtab(const SymbolBody &B) { - if (!B.isUsedInRegularObj()) + if (!B.Backref->IsUsedInRegularObj) return false; if (auto *D = dyn_cast>(&B)) { @@ -1326,7 +1325,7 @@ if (Out::SymTab) Out::SymTab->addSymbol(Body); - if (isOutputDynamic() && Body->includeInDynsym()) + if (isOutputDynamic() && S->includeInDynsym()) Out::DynSymTab->addSymbol(Body); }