diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -50,6 +50,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/GlobPattern.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" @@ -1320,16 +1321,38 @@ // Force Sym to be entered in the output. Used for -u or equivalent. static void handleUndefined(StringRef Name) { - Symbol *Sym = Symtab->find(Name); - if (!Sym) - return; + auto Handle = [](Symbol *Sym) { + // Since symbol S may not be used inside the program, LTO may + // eliminate it. Mark the symbol as "used" to prevent it. + Sym->IsUsedInRegularObj = true; - // Since symbol S may not be used inside the program, LTO may - // eliminate it. Mark the symbol as "used" to prevent it. - Sym->IsUsedInRegularObj = true; + if (Sym->isLazy()) + Sym->fetch(); + }; - if (Sym->isLazy()) - Sym->fetch(); + // As an extention to GNU linkers, lld supports wildcard patterns in + // `-u` arguments. If a wildcard pattern is given, we need to match + // it against all symbols. + if (Name.find_first_of("*?[")) { + Expected Pat = GlobPattern::create(Name); + if (Pat) { + std::vector Syms; + Symtab->forEachSymbol([&](Symbol *Sym) { + // Calling Sym->fetch() from here is not safe because it may + // add new symbols to the symbol table, invalidating the + // current iterator. So we just keep a note. + if (Pat->match(Sym->getName())) + Syms.push_back(Sym); + }); + + for (Symbol *Sym : Syms) + Handle(Sym); + return; + } + } + + if (Symbol *Sym = Symtab->find(Name)) + Handle(Sym); } static void handleLibcall(StringRef Name) { diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -506,7 +506,8 @@ .It Fl -undefined Ns = Ns Ar symbol , Fl u Ar symbol Force .Ar symbol -to be an undefined symbol during linking. +to be an undefined symbol during linking. You can use wildcard patterns in +.Ar symbol . .It Fl -unresolved-symbols Ns = Ns Ar value Determine how to handle unresolved symbols. .It Fl -use-android-relr-tags diff --git a/lld/test/ELF/undefined-wildcard.s b/lld/test/ELF/undefined-wildcard.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/undefined-wildcard.s @@ -0,0 +1,53 @@ +# REQUIRES: x86 + +# RUN: echo '.globl foo1; foo1:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t1.o +# RUN: echo '.globl foo2; foo2:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t2.o +# RUN: echo '.globl foo32; foo32:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t3.o +# RUN: echo '.globl bar; bar:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t4.o +# RUN: rm -f %t.a +# RUN: llvm-ar rcs %t.a %t1.o %t2.o %t3.o %t4.o + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: ld.lld -o %t.exe %t.o %t.a +# RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=NO-OPT %s + +# NO-OPT-NOT: foo +# NO-OPT-NOT: bar + +# RUN: ld.lld -o %t.exe %t.o %t.a -u foo1 +# RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO1 %s + +# FOO1: foo1 +# FOO1-NOT: foo2 + +# RUN: ld.lld -o %t.exe %t.o %t.a -u 'foo*' +# RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO-STAR %s + +# FOO-STAR: foo1 +# FOO-STAR: foo2 +# FOO-STAR: foo32 +# FOO-STAR-NOT: bar + +# RUN: ld.lld -o %t.exe %t.o %t.a -u 'foo?' +# RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO-Q %s + +# FOO-Q: foo1 +# FOO-Q: foo2 +# FOO-Q-NOT: foo32 +# FOO-Q-NOT: bar + +# RUN: ld.lld -o %t.exe %t.o %t.a -u 'foo[13]*' +# RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO13 %s + +# FOO13: foo1 +# FOO13-NOT: foo2 +# FOO13: foo32 +# FOO13-NOT: bar + +.globl _start +_start: