diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index eb6734dfd458d..dd141ff70f26a 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2470,6 +2470,12 @@ static void readSymbolPartitionSection(InputSectionBase *s) { sym->partition = newPart.getNumber(); } +static Symbol *addUnusedUndefined(StringRef name, + uint8_t binding = STB_GLOBAL) { + return symtab.addSymbol( + Undefined{ctx.internalFile, name, binding, STV_DEFAULT, 0}); +} + static void markBuffersAsDontNeed(bool skipLinkedOutput) { // With --thinlto-index-only, all buffers are nearly unused from now on // (except symbol/section names used by infrequent passes). Mark input file @@ -2556,19 +2562,19 @@ static std::vector addWrappedSymbols(opt::InputArgList &args) { continue; Symbol *wrap = - symtab.addUnusedUndefined(saver().save("__wrap_" + name), sym->binding); + addUnusedUndefined(saver().save("__wrap_" + name), sym->binding); // If __real_ is referenced, pull in the symbol if it is lazy. Do this after // processing __wrap_ as that may have referenced __real_. StringRef realName = saver().save("__real_" + name); if (Symbol *real = symtab.find(realName)) { - symtab.addUnusedUndefined(name, sym->binding); + addUnusedUndefined(name, sym->binding); // Update sym's binding, which will replace real's later in // SymbolTable::wrap. sym->binding = real->binding; } - Symbol *real = symtab.addUnusedUndefined(realName); + Symbol *real = addUnusedUndefined(realName); v.push_back({sym, real, wrap}); // We want to tell LTO not to inline symbols to be overwritten @@ -2845,13 +2851,26 @@ template void LinkerDriver::link(opt::InputArgList &args) { // Handle -u/--undefined before input files. If both a.a and b.so define foo, // -u foo a.a b.so will extract a.a. for (StringRef name : config->undefined) - symtab.addUnusedUndefined(name)->referenced = true; + addUnusedUndefined(name)->referenced = true; parseFiles(files, armCmseImpLib); // Create dynamic sections for dynamic linking and static PIE. config->hasDynSymTab = !ctx.sharedFiles.empty() || config->isPic; + // Some symbols (such as __ehdr_start) are defined lazily only when there + // are undefined symbols for them, so we add these to trigger that logic. + for (StringRef name : script->referencedSymbols) { + Symbol *sym = addUnusedUndefined(name); + sym->isUsedInRegularObj = true; + sym->referenced = true; + } + + // Prevent LTO from removing any definition referenced by -u. + for (StringRef name : config->undefined) + if (Defined *sym = dyn_cast_or_null(symtab.find(name))) + sym->isUsedInRegularObj = true; + // If an entry symbol is in a static archive, pull out that file now. if (Symbol *sym = symtab.find(config->entry)) handleUndefined(sym, "--entry"); @@ -2860,16 +2879,6 @@ template void LinkerDriver::link(opt::InputArgList &args) { for (StringRef pat : args::getStrings(args, OPT_undefined_glob)) handleUndefinedGlob(pat); - // After potential archive member extraction involving ENTRY and - // -u/--undefined-glob, check whether PROVIDE symbols should be defined (the - // RHS may refer to definitions in just extracted object files). - script->addScriptReferencedSymbolsToSymTable(); - - // Prevent LTO from removing any definition referenced by -u. - for (StringRef name : config->undefined) - if (Defined *sym = dyn_cast_or_null(symtab.find(name))) - sym->isUsedInRegularObj = true; - // Mark -init and -fini symbols so that the LTO doesn't eliminate them. if (Symbol *sym = dyn_cast_or_null(symtab.find(config->init))) sym->isUsedInRegularObj = true; diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 055fa21d44ca6..7cc6d05ffeb56 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -199,7 +199,15 @@ static bool shouldDefineSym(SymbolAssignment *cmd) { if (cmd->name == ".") return false; - return !cmd->provide || LinkerScript::shouldAddProvideSym(cmd->name); + if (!cmd->provide) + return true; + + // If a symbol was in PROVIDE(), we need to define it only + // when it is a referenced undefined symbol. + Symbol *b = symtab.find(cmd->name); + if (b && !b->isDefined() && !b->isCommon()) + return true; + return false; } // Called by processSymbolAssignments() to assign definitions to @@ -1683,41 +1691,3 @@ void LinkerScript::checkFinalScriptConditions() const { checkMemoryRegion(lmaRegion, sec, sec->getLMA()); } } - -void LinkerScript::addScriptReferencedSymbolsToSymTable() { - // Some symbols (such as __ehdr_start) are defined lazily only when there - // are undefined symbols for them, so we add these to trigger that logic. - auto reference = [](StringRef name) { - Symbol *sym = symtab.addUnusedUndefined(name); - sym->isUsedInRegularObj = true; - sym->referenced = true; - }; - for (StringRef name : referencedSymbols) - reference(name); - - // Keeps track of references from which PROVIDE symbols have been added to the - // symbol table. - DenseSet added; - SmallVector *, 0> symRefsVec; - for (const auto &[name, symRefs] : provideMap) - if (LinkerScript::shouldAddProvideSym(name) && added.insert(name).second) - symRefsVec.push_back(&symRefs); - while (symRefsVec.size()) { - for (StringRef name : *symRefsVec.pop_back_val()) { - reference(name); - // Prevent the symbol from being discarded by --gc-sections. - script->referencedSymbols.push_back(name); - auto it = script->provideMap.find(name); - if (it != script->provideMap.end() && - LinkerScript::shouldAddProvideSym(name) && - added.insert(name).second) { - symRefsVec.push_back(&it->second); - } - } - } -} - -bool LinkerScript::shouldAddProvideSym(StringRef symName) { - Symbol *sym = symtab.find(symName); - return sym && !sym->isDefined() && !sym->isCommon(); -} diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index b86521a429f04..f4017141b54e2 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -17,7 +17,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include @@ -366,18 +365,6 @@ class LinkerScript final { // Check backward location counter assignment and memory region/LMA overflows. void checkFinalScriptConditions() const; - // Add symbols that are referenced in the linker script to the symbol table. - // Symbols referenced in a PROVIDE command are only added to the symbol table - // if the PROVIDE command actually provides the symbol. - // It also adds the symbols referenced by the used PROVIDE symbols to the - // linker script referenced symbols list. - void addScriptReferencedSymbolsToSymTable(); - - // Returns true if the PROVIDE symbol should be added to the link. - // A PROVIDE symbol is added to the link only if it satisfies an - // undefined reference. - static bool shouldAddProvideSym(StringRef symName); - // SECTIONS command list. SmallVector sectionCommands; @@ -413,14 +400,6 @@ class LinkerScript final { // Sections that will be warned/errored by --orphan-handling. SmallVector orphanSections; - // Stores the mapping: PROVIDE symbol -> symbols referred in the PROVIDE - // expression. For example, if the PROVIDE command is: - // - // PROVIDE(v = a + b + c); - // - // then provideMap should contain the mapping: 'v' -> ['a', 'b', 'c'] - llvm::MapVector> provideMap; - // List of potential spill locations (PotentialSpillSection) for an input // section. struct PotentialSpillList { diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 49aa7e6374905..406cbd0f4df59 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -36,7 +36,6 @@ #include "llvm/Support/TimeProfiler.h" #include #include -#include #include using namespace llvm; @@ -140,10 +139,6 @@ class ScriptParser final : ScriptLexer { // A set to detect an INCLUDE() cycle. StringSet<> seen; - - // If we are currently parsing a PROVIDE|PROVIDE_HIDDEN command, - // then this member is set to the PROVIDE symbol name. - std::optional activeProvideSym; }; } // namespace @@ -1088,9 +1083,6 @@ SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) { ; return nullptr; } - llvm::SaveAndRestore saveActiveProvideSym(activeProvideSym); - if (provide) - activeProvideSym = name; SymbolAssignment *cmd = readSymbolAssignment(name); cmd->provide = provide; cmd->hidden = hidden; @@ -1604,10 +1596,7 @@ Expr ScriptParser::readPrimary() { tok = unquote(tok); else if (!isValidSymbolName(tok)) setError("malformed number: " + tok); - if (activeProvideSym) - script->provideMap[*activeProvideSym].push_back(tok); - else - script->referencedSymbols.push_back(tok); + script->referencedSymbols.push_back(tok); return [=] { return script->getSymbolValue(tok, location); }; } diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 258a78ab40bb5..b3d97e4de7790 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -333,7 +333,3 @@ void SymbolTable::scanVersionScript() { // --dynamic-list. handleDynamicList(); } - -Symbol *SymbolTable::addUnusedUndefined(StringRef name, uint8_t binding) { - return addSymbol(Undefined{ctx.internalFile, name, binding, STV_DEFAULT, 0}); -} diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index 269f7f284bc73..37e31d2372963 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -57,9 +57,6 @@ class SymbolTable { void handleDynamicList(); - Symbol *addUnusedUndefined(StringRef name, - uint8_t binding = llvm::ELF::STB_GLOBAL); - // Set of .so files to not link the same shared object file more than once. llvm::DenseMap soNames; diff --git a/lld/test/ELF/gc-sections-with-provide.s b/lld/test/ELF/gc-sections-with-provide.s deleted file mode 100644 index 3e5b1b1efe6ca..0000000000000 --- a/lld/test/ELF/gc-sections-with-provide.s +++ /dev/null @@ -1,60 +0,0 @@ -# REQUIRES: x86 - -# This test verifies that garbage-collection is correctly garbage collecting -# unused sections when the symbol of the unused section is only referred by -# an unused PROVIDE symbol. - -# RUN: rm -rf %t && split-file %s %t && cd %t -# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o -# RUN: ld.lld -o a_nogc a.o -T script.t -# RUN: llvm-nm a_nogc | FileCheck -check-prefix=NOGC %s -# RUN: ld.lld -o a_gc a.o --gc-sections --print-gc-sections -T script.t | FileCheck --check-prefix=GC_LINK %s -# RUN: llvm-nm a_gc | FileCheck -check-prefix=GC %s - -NOGC-NOT: another_unused -NOGC: another_used -NOGC: bar -NOGC: baz -NOGC: baz_ref -NOGC: foo -NOGC-NOT: unused -NOGC: used - -GC_LINK: removing unused section a.o:(.text.bar) - -GC-NOT: another_unused -GC: another_used -GC-NOT: bar -GC: baz -GC: baz_ref -GC: foo -GC-NOT: unused -GC: used - -#--- a.s -.global _start -_start: - call foo - call used - -.section .text.foo,"ax",@progbits -foo: - nop - -.section .text.bar,"ax",@progbits -.global bar -bar: - nop - -.section .text.baz,"ax",@progbits -.global baz -baz: - nop - - -#--- script.t -PROVIDE(unused = bar + used); -PROVIDE(used = another_used); -PROVIDE(baz_ref = baz); -PROVIDE(another_used = baz_ref); -PROVIDE(another_unused = unused + bar + 0x1); diff --git a/lld/test/ELF/linkerscript/symbolreferenced.s b/lld/test/ELF/linkerscript/symbolreferenced.s index 6848082690837..ba7a7721ea969 100644 --- a/lld/test/ELF/linkerscript/symbolreferenced.s +++ b/lld/test/ELF/linkerscript/symbolreferenced.s @@ -21,50 +21,15 @@ # RUN: ld.lld -o chain -T chain.t a.o # RUN: llvm-nm chain | FileCheck %s -# CHECK-NOT: another_unused -# CHECK: 0000000000007000 a f1 -# CHECK-NEXT: 0000000000007000 A f2 -# CHECK-NEXT: 0000000000007000 A f3 -# CHECK-NEXT: 0000000000007000 A f4 -# CHECK-NEXT: 0000000000006000 A f5 -# CHECK-NEXT: 0000000000003000 A f6 -# CHECK-NEXT: 0000000000001000 A f7 -# CHECK-NOT: g1 -# CHECK-NOT: g2 -# CHECK-NEXT: 0000000000007500 A newsym -# CHECK: 0000000000002000 A u -# CHECK-NOT: unused -# CHECK-NEXT: 0000000000002000 A v -# CHECK-NEXT: 0000000000002000 A w - - -# RUN: ld.lld -o chain_with_cycle -T chain_with_cycle.t a.o -# RUN: llvm-nm chain_with_cycle | FileCheck %s --check-prefix=CHAIN_WITH_CYCLE - -# CHAIN_WITH_CYCLE: 000 A f1 -# CHAIN_WITH_CYCLE: 000 A f2 -# CHAIN_WITH_CYCLE: 000 A f3 -# CHAIN_WITH_CYCLE: 000 A f4 -# CHAIN_WITH_CYCLE: 000 A newsym +# CHECK: 0000000000001000 a f1 +# CHECK-NEXT: 0000000000001000 A f2 +# CHECK-NEXT: 0000000000001000 a g1 +# CHECK-NEXT: 0000000000001000 A g2 +# CHECK-NEXT: 0000000000001000 A newsym # RUN: not ld.lld -T chain2.t a.o 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error: # ERR-COUNT-3: error: chain2.t:1: symbol not found: undef -## _start in a lazy object file references PROVIDE symbols. We extract _start -## earlier to avoid spurious "symbol not found" errors. -# RUN: llvm-mc -filetype=obj -triple=x86_64 undef.s -o undef.o -# RUN: llvm-mc -filetype=obj -triple=x86_64 start.s -o start.o -# RUN: ld.lld -T chain2.t undef.o --start-lib start.o --end-lib -o lazy -# RUN: llvm-nm lazy | FileCheck %s --check-prefix=LAZY -# RUN: ld.lld -e 0 -T chain2.t --undefined-glob '_start*' undef.o --start-lib start.o --end-lib -o lazy -# RUN: llvm-nm lazy | FileCheck %s --check-prefix=LAZY - -# LAZY: T _start -# LAZY-NEXT: t f1 -# LAZY-NEXT: T f2 -# LAZY-NEXT: T newsym -# LAZY-NEXT: T unde - #--- a.s .global _start _start: @@ -75,42 +40,15 @@ patatino: movl newsym, %eax #--- chain.t -PROVIDE(f7 = 0x1000); -PROVIDE(f5 = f6 + 0x3000); -PROVIDE(f6 = f7 + 0x2000); -PROVIDE(f4 = f5 + 0x1000); -PROVIDE(f3 = f4); -PROVIDE(f2 = f3); +PROVIDE(f2 = 0x1000); PROVIDE_HIDDEN(f1 = f2); -PROVIDE(newsym = f1 + 0x500); - -u = v; -PROVIDE(w = 0x2000); -PROVIDE(v = w); +PROVIDE(newsym = f1); PROVIDE(g2 = 0x1000); PROVIDE_HIDDEN(g1 = g2); PROVIDE(unused = g1); -PROVIDE_HIDDEN(another_unused = g1); - -#--- chain_with_cycle.t -PROVIDE(f1 = f2 + f3); -PROVIDE(f2 = f3 + f4); -PROVIDE(f3 = f4); -PROVIDE(f4 = f1); -PROVIDE(newsym = f1); #--- chain2.t PROVIDE(f2 = undef); PROVIDE_HIDDEN(f1 = f2); PROVIDE(newsym = f1); - -#--- undef.s -.globl undef -undef: ret - -#--- start.s -.globl _start -_start: ret -.data -.quad newsym