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" @@ -1318,8 +1319,35 @@ Visit(File); } +// A helper function for -u to do wildcard pattern match. +static void handleUndefinedWildcard(const GlobPattern &Pat) { + std::vector Syms; + + Symtab->forEachSymbol([&](Symbol *Sym) { + // Calling Sym->fetch() from here not safe as 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) { + Sym->IsUsedInRegularObj = true; + if (Sym->isLazy()) + Sym->fetch(); + } +} + // Force Sym to be entered in the output. Used for -u or equivalent. static void handleUndefined(StringRef Name) { + if (Name.contains('*') || Name.contains('?') || Name.contains('[')) { + Expected Pat = GlobPattern::create(Name); + if (Pat) { + handleUndefinedWildcard(*Pat); + return; + } + } + Symbol *Sym = Symtab->find(Name); if (!Sym) return; 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: