diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1470,16 +1470,12 @@ visit(file); } -// Force Sym to be entered in the output. Used for -u or equivalent. +// Force Sym to be entered in the output. static void handleUndefined(Symbol *sym) { // Since a symbol may not be used inside the program, LTO may // eliminate it. Mark the symbol as "used" to prevent it. sym->isUsedInRegularObj = true; - // GNU linkers allow -u foo -ldef -lref. We should not treat it as a backward - // reference. - backwardReferences.erase(sym); - if (sym->isLazy()) sym->fetch(); } @@ -1675,6 +1671,12 @@ Undefined{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}); } +static Symbol *addUnusedUndefined(StringRef name) { + Undefined sym{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}; + sym.isUsedInRegularObj = false; + return symtab->addSymbol(sym); +} + // This function is where all the optimizations of link-time // optimization takes place. When LTO is in use, some input files are // not in native object file format but in the LLVM bitcode format. @@ -1851,6 +1853,11 @@ for (auto *arg : args.filtered(OPT_trace_symbol)) symtab->insert(arg->getValue())->traced = true; + // Handle -u/--undefined before input files. If both a.a and b.so define foo, + // -u foo a.a b.so will fetch a.a. + for (StringRef name : config->undefined) + addUnusedUndefined(name); + // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. This process might // add files to the link, via autolinking, these files are always @@ -1875,10 +1882,10 @@ for (StringRef name : script->referencedSymbols) addUndefined(name); - // Handle the `--undefined ` options. - for (StringRef arg : config->undefined) - if (Symbol *sym = symtab->find(arg)) - handleUndefined(sym); + // 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)) diff --git a/lld/test/ELF/undefined-opt.s b/lld/test/ELF/undefined-opt.s --- a/lld/test/ELF/undefined-opt.s +++ b/lld/test/ELF/undefined-opt.s @@ -54,13 +54,19 @@ # UNK-UNDEFINED-SO: ] # Added undefined symbols should appear in the dynamic table if necessary. -# RUN: ld.lld -shared -o %t5 %t.o -u export -# RUN: llvm-readobj --dyn-symbols %t5 | \ +# RUN: ld.lld -shared -soname=t -o %t.so %t.o -u export +# RUN: llvm-readobj --dyn-symbols %t.so | \ # RUN: FileCheck --check-prefix=EXPORT-SO %s # EXPORT-SO: DynamicSymbols [ # EXPORT-SO: Name: export # EXPORT-SO: ] +## Test that we handle -u before input files: if we handle -u after +## %t.so, foo would be undefined in the output. +# RUN: rm -f %t.a && llvm-ar rc %t.a %t.o +# RUN: ld.lld -u export %t.a %t.so -o %t5 +# RUN: llvm-readobj --dyn-symbols %t5 | FileCheck --check-prefix=EXPORT-SO %s + .globl _start _start: