From 7bee6e30fe634624a99b43615261f4b5311e7dd1 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 5 Jun 2020 08:41:03 -0700 Subject: [PATCH] [ELF] Handle -u before input files If both a.a and b.so define foo ``` ld.bfd -u foo a.a b.so # foo is defined ld.bfd a.a b.so -u foo # foo is defined ld.bfd -u foo b.so a.a # foo is undefined (provided at runtime by b.so) ld.bfd b.so a.a -u foo # foo is undefined (provided at runtime by b.so) ``` In all cases we make foo undefined in the output. I tend to think the GNU ld behavior makes more sense. * In their model, they have to treat -u as a fake object file with an undefined symbol before all input files, otherwise the first archive would not be fetched. * Following their behavior allows us to drop a --warn-backrefs special case. Reviewed By: psmith Differential Revision: https://reviews.llvm.org/D81052 --- lld/ELF/Driver.cpp | 25 ++++++++++++++++--------- lld/test/ELF/undefined-opt.s | 10 ++++++++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index d2edada..bcef615 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1470,16 +1470,12 @@ static void excludeLibs(opt::InputArgList &args) { 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 @@ static Symbol *addUndefined(StringRef name) { 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 @@ template void LinkerDriver::link(opt::InputArgList &args) { 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 @@ template void LinkerDriver::link(opt::InputArgList &args) { 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 index 2689954..a9e0bf0 100644 --- 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: -- 2.7.4