diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index f66fe3cab5a2..5a6a4a61030e 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -37,6 +37,7 @@ #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/GlobPattern.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Parallel.h" @@ -704,6 +705,24 @@ Symbol *LinkerDriver::addUndefined(StringRef name) { return b; } +void LinkerDriver::addUndefinedGlob(StringRef arg) { + Expected pat = GlobPattern::create(arg); + if (!pat) { + error("/includeglob: " + toString(pat.takeError())); + return; + } + + SmallVector syms; + ctx.symtab.forEachSymbol([&syms, &pat](Symbol *sym) { + if (pat->match(sym->getName())) { + syms.push_back(sym); + } + }); + + for (Symbol *sym : syms) + addUndefined(sym->getName()); +} + StringRef LinkerDriver::mangleMaybe(Symbol *s) { // If the plain symbol name has already been resolved, do nothing. Undefined *unmangled = dyn_cast(s); @@ -2524,6 +2543,10 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { } while (run()); } + // Handle /includeglob + for (StringRef pat : args::getStrings(args, OPT_incl_glob)) + addUndefinedGlob(pat); + // Create wrapped symbols for -wrap option. std::vector wrapped = addWrappedSymbols(ctx, args); // Load more object files that might be needed for wrapped symbols. diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 0c195a7cc314..58a2ed231062 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -172,6 +172,8 @@ private: Symbol *addUndefined(StringRef sym); + void addUndefinedGlob(StringRef arg); + StringRef mangleMaybe(Symbol *s); // Windows specific -- "main" is not the only main function in Windows. diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index 4bc4d7c4b5a4..7ceb824c068d 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -310,6 +310,9 @@ defm build_id: B< "Generate build ID (always on when generating PDB)", "Do not Generate build ID">; +def incl_glob : Joined<["/", "-", "/?", "-?"], "includeglob:">, + HelpText<"Force symbol to be added to symbol table as undefined one using a glob pattern">; + // Flags for debugging def lldmap : F<"lldmap">; def lldmap_file : P_priv<"lldmap">; diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index 6d09de10e719..6e043773f003 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -41,6 +41,7 @@ Breaking changes COFF Improvements ----------------- +* ``/includeglob`` has been implemented to match the behavior of ``--undefined-glob`` available for ELF. MinGW Improvements ------------------ diff --git a/lld/test/COFF/Inputs/include1d.yaml b/lld/test/COFF/Inputs/include1d.yaml new file mode 100644 index 000000000000..d315cc885dd7 --- /dev/null +++ b/lld/test/COFF/Inputs/include1d.yaml @@ -0,0 +1,29 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B800000000506800000000680000000050E80000000050E800000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 28 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: baz + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/COFF/include.test b/lld/test/COFF/include.test index 8879ee5bd7a6..2a8a8fe4034c 100644 --- a/lld/test/COFF/include.test +++ b/lld/test/COFF/include.test @@ -9,10 +9,18 @@ # RUN: echo dummy >> %t.log # RUN: FileCheck -check-prefix=CHECK2 %s < %t.log +# RUN: lld-link /out:%t.exe /entry:main %t.obj /verbose /includeglob:"glob_*" >& %t.log +# RUN: echo dummy >> %t.log +# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log + # CHECK1: Discarded unused +# CHECK1: Discarded glob_match1 +# CHECK1: Discarded glob_match2 # CHECK1-NOT: Discarded used # CHECK2-NOT: Discarded unused # CHECK2-NOT: Discarded used +# CHECK3-NOT: Discarded glob_match1 +# CHECK3-NOT: Discarded glob_match2 --- !COFF header: @@ -31,6 +39,14 @@ sections: Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: B82A000000C3 + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B82A000000C3 + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B82A000000C3 - Name: .drectve Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] Alignment: 1 @@ -75,6 +91,32 @@ symbols: CheckSum: 0 Number: 0 Selection: IMAGE_COMDAT_SELECT_ANY + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: '.text$mn' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_ANY - Name: main Value: 0 SectionNumber: 1 @@ -93,4 +135,16 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_FUNCTION StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: glob_match1 + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: glob_match2 + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL ... diff --git a/lld/test/COFF/include2.test b/lld/test/COFF/include2.test index 557de47d9e19..4796512fff93 100644 --- a/lld/test/COFF/include2.test +++ b/lld/test/COFF/include2.test @@ -1,14 +1,20 @@ # RUN: yaml2obj %p/Inputs/include1a.yaml -o %t1.obj # RUN: yaml2obj %p/Inputs/include1b.yaml -o %t2.obj # RUN: yaml2obj %p/Inputs/include1c.yaml -o %t3.obj -# RUN: rm -f %t2.lib %t3.lib +# RUN: yaml2obj %p/Inputs/include1d.yaml -o %t4.obj +# RUN: rm -f %t2.lib %t3.lib %t4.lib # RUN: llvm-ar cru %t2.lib %t2.obj # RUN: llvm-ar cru %t3.lib %t3.obj -# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.lib %t3.lib /verbose >& %t.log +# RUN: llvm-ar cru %t4.lib %t4.obj +# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.lib %t3.lib %t4.lib /verbose >& %t.log # RUN: FileCheck %s < %t.log +# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.lib %t3.lib %t4.lib /includeglob:baz /verbose >& %t.glob.log +# RUN: FileCheck -check-prefix=GLOB %s < %t.glob.log CHECK: include2.test.tmp1.obj CHECK: include2.test.tmp2.lib CHECK: include2.test.tmp2.lib(include2.test.tmp2.obj) for foo CHECK: include2.test.tmp3.lib CHECK: include2.test.tmp3.lib(include2.test.tmp3.obj) for bar +CHECK-NOT: include2.test.tmp4.lib(include2.test.tmp4.obj) for baz +GLOB: include2.test.tmp4.lib(include2.test.tmp4.obj) for baz