Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -1474,12 +1474,8 @@ bool canOmitFromDynSym = objSym.canBeOmittedFromSymbolTable(); int c = objSym.getComdatIndex(); - if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) { - Undefined New(&f, name, binding, visibility, type); - if (canOmitFromDynSym) - New.exportDynamic = false; - return symtab->addSymbol(New); - } + if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) + return symtab->addSymbol(Undefined{&f, name, binding, visibility, type}); if (objSym.isCommon()) return symtab->addSymbol( @@ -1487,8 +1483,7 @@ objSym.getCommonAlignment(), objSym.getCommonSize()}); Defined New(&f, name, binding, visibility, type, 0, 0, nullptr); - if (canOmitFromDynSym) - New.exportDynamic = false; + New.canOmitFromDynSym = canOmitFromDynSym; return symtab->addSymbol(New); } Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -77,6 +77,7 @@ sym->visibility = STV_DEFAULT; sym->isUsedInRegularObj = false; sym->exportDynamic = false; + sym->canOmitFromDynSym = false; sym->canInline = true; sym->scriptDefined = false; sym->partition = 1; @@ -162,12 +163,8 @@ else syms = findByVersion(ver); - for (Symbol *b : syms) { - if (!config->shared) - b->exportDynamic = true; - else if (b->includeInDynsym()) - b->isPreemptible = true; - } + for (Symbol *b : syms) + b->exportDynamic = true; } } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -116,12 +116,15 @@ // 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. + // Used by Defined with protected or default visibility to track if it should + // appear in .dynsym. This flag is set by interposable DSO symbols (symbols + // with default visibility), and by dynamic lists. unsigned exportDynamic : 1; + // Stores the value of bitcode canBeOmittedFromSymbolTable(). Used as an + // optimization to omit some .dynsym entries. + unsigned canOmitFromDynSym : 1; + // False if LTO shouldn't inline whatever this symbol points to. If a symbol // is overwritten after LTO, LTO shouldn't inline the symbol because it // doesn't know the final contents of the symbol. @@ -211,12 +214,6 @@ void fetch() const; private: - static bool isExportDynamic(Kind k, uint8_t visibility) { - if (k == SharedKind) - return visibility == llvm::ELF::STV_DEFAULT; - return config->shared || config->exportDynamic; - } - void resolveUndefined(const Undefined &other); void resolveCommon(const CommonSymbol &other); void resolveDefined(const Defined &other); @@ -233,10 +230,11 @@ : 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(isExportDynamic(k, visibility)), canInline(false), - referenced(false), traced(false), needsPltAddr(false), isInIplt(false), - gotInIgot(false), isPreemptible(false), used(!config->gcSections), - needsTocRestore(false), scriptDefined(false) {} + exportDynamic(k == SharedKind && visibility == llvm::ELF::STV_DEFAULT), + canOmitFromDynSym(false), canInline(false), referenced(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. Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -295,7 +295,13 @@ if (isUndefWeak() && config->pie && sharedFiles.empty()) return false; - return isUndefined() || isShared() || exportDynamic; + if (isUndefined() || isShared() || exportDynamic) + return true; + + // -shared and --export-dynamic default to export defined symbols. As an + // optimization, it can be omitted if lto canBeOmittedFromSymbolTable() is + // true. + return (config->shared || config->exportDynamic) && !canOmitFromDynSym; } // Print out a log message for --trace-symbol. Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1653,13 +1653,13 @@ if (!b.isDefined()) return true; - // If we have a dynamic list it specifies which local symbols are preemptible. - if (config->hasDynamicList) - return false; - if (!config->shared) return false; + // In a DSO, the dynamic list specifies preemptible symbols. + if (config->hasDynamicList) + return b.exportDynamic; + // -Bsymbolic means that definitions are not preempted. if (config->bsymbolic || (config->bsymbolicFunctions && b.isFunc())) return false; @@ -1728,10 +1728,8 @@ for (Partition &part : partitions) finalizeSynthetic(part.ehFrame); - symtab->forEachSymbol([](Symbol *s) { - if (!s->isPreemptible) - s->isPreemptible = computeIsPreemptible(*s); - }); + symtab->forEachSymbol( + [](Symbol *s) { s->isPreemptible = computeIsPreemptible(*s); }); // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed.