diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -87,10 +87,12 @@ freeArena(); ObjFile::instances.clear(); + PDBInputFile::instances.clear(); ImportFile::instances.clear(); BitcodeFile::instances.clear(); memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances)); TpiSource::clear(); + OutputSection::clear(); return !errorCount(); } diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h --- a/lld/COFF/Writer.h +++ b/lld/COFF/Writer.h @@ -50,6 +50,9 @@ void writeHeaderTo(uint8_t *buf); void addContributingPartialSection(PartialSection *sec); + // Clear the output sections static container. + static void clear(); + // Returns the size of this section in an executable memory image. // This may be smaller than the raw size (the raw size is multiple // of disk sector size, so there may be padding at end), or may be diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -88,6 +88,8 @@ return osidx == 0 ? nullptr : outputSections[osidx - 1]; } +void OutputSection::clear() { outputSections.clear(); } + namespace { class DebugDirectoryChunk : public NonSectionChunk { diff --git a/lld/test/COFF/dll.test b/lld/test/COFF/dll.test --- a/lld/test/COFF/dll.test +++ b/lld/test/COFF/dll.test @@ -13,10 +13,10 @@ EXPORT-NEXT: 3 0x1010 exportfn3 EXPORT-NEXT: 4 0x1010 mangled -# RUN: yaml2obj < %p/Inputs/export2.yaml > %t5.obj -# RUN: rm -f %t5.lib -# RUN: llvm-ar cru %t5.lib %t5.obj -# RUN: lld-link /out:%t5.dll /dll %t.obj %t5.lib /export:mangled2 +# RUN: yaml2obj < %p/Inputs/export2.yaml > %t4.obj +# RUN: rm -f %t4.lib +# RUN: llvm-ar cru %t4.lib %t4.obj +# RUN: lld-link /out:%t5.dll /dll %t.obj %t4.lib /export:mangled2 # RUN: llvm-objdump -p %t5.dll | FileCheck --check-prefix=EXPORT2 %s EXPORT2: Export Table: diff --git a/lld/test/COFF/duplicate-absolute-same.s b/lld/test/COFF/duplicate-absolute-same.s --- a/lld/test/COFF/duplicate-absolute-same.s +++ b/lld/test/COFF/duplicate-absolute-same.s @@ -2,7 +2,8 @@ // RUN: llvm-mc -triple x86_64-windows-msvc -filetype obj -o %t.obj %s // RUN: echo -e ".globl myabsolute\nmyabsolute = 0" > %t.dupl.s // RUN: llvm-mc -triple x86_64-windows-msvc -filetype obj -o %t.dupl.obj %t.dupl.s -// RUN: lld-link /out:%t.exe %t.obj %t.dupl.obj -subsystem:console -entry:entry 2>&1 | count 0 +// RUN: lld-link /out:%t.exe %t.obj %t.dupl.obj -subsystem:console -entry:entry 2>&1 | FileCheck %s +// CHECK-NOT: error: duplicate // This shouldn't produce any duplicate symbol error. diff --git a/lld/test/COFF/gc-dwarf.s b/lld/test/COFF/gc-dwarf.s --- a/lld/test/COFF/gc-dwarf.s +++ b/lld/test/COFF/gc-dwarf.s @@ -4,9 +4,11 @@ # RUN: lld-link -lldmap:%t.map -out:%t.exe -opt:ref -entry:main %t.obj -verbose 2>&1 | FileCheck %s # RUN: FileCheck %s --check-prefix=MAP --input-file=%t.map +# CHECK-LABEL: LLD_IN_TEST # CHECK: Discarded unused1 # CHECK-NEXT: Discarded unused2 # CHECK-NOT: Discarded +# CHECK-LABEL: LLD_IN_TEST # MAP: In Symbol # MAP: gc-dwarf.s.tmp.obj:(.text) diff --git a/lld/test/COFF/guardcf-lto.ll b/lld/test/COFF/guardcf-lto.ll --- a/lld/test/COFF/guardcf-lto.ll +++ b/lld/test/COFF/guardcf-lto.ll @@ -8,8 +8,8 @@ ; RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %S/Inputs/loadconfig-cfg-x64.s -o %t.ldcfg.obj ; RUN: llvm-as %s -o %t.bc -; RUN: lld-link -entry:main -guard:cf -dll %t.bc %t.lib %t.ldcfg.obj -out:%t.dll -; RUN: llvm-readobj --coff-load-config %t.dll | FileCheck %s +; RUN: lld-link -entry:main -guard:cf -dll %t.bc %t.lib %t.ldcfg.obj -out:%t2.dll +; RUN: llvm-readobj --coff-load-config %t2.dll | FileCheck %s ; There must be *two* entries in the table: DLL entry point, and my_handler. diff --git a/lld/test/COFF/icf-safe.s b/lld/test/COFF/icf-safe.s --- a/lld/test/COFF/icf-safe.s +++ b/lld/test/COFF/icf-safe.s @@ -9,6 +9,7 @@ # CHECK-NEXT: Removed g4 # CHECK-NOT: Removed # CHECK-NOT: Selected +# CHECK: LLD_IN_TEST # EXPORT-NOT: Selected diff --git a/lld/test/COFF/lit.local.cfg b/lld/test/COFF/lit.local.cfg new file mode 100644 --- /dev/null +++ b/lld/test/COFF/lit.local.cfg @@ -0,0 +1 @@ +config.environment['LLD_IN_TEST'] = '3' diff --git a/lld/test/COFF/pdb-unknown-subsection.s b/lld/test/COFF/pdb-unknown-subsection.s --- a/lld/test/COFF/pdb-unknown-subsection.s +++ b/lld/test/COFF/pdb-unknown-subsection.s @@ -9,6 +9,7 @@ # WARNING-NOT: ignoring unknown # WARNING: ignoring unknown debug$S subsection kind 0xFF # WARNING-NOT: ignoring unknown +# WARNING: LLD_IN_TEST # CHECK: Symbols # CHECK: 4 | S_COMPILE3 [size = 52] diff --git a/lld/test/ELF/cgprofile-shared-warn.s b/lld/test/ELF/cgprofile-shared-warn.s --- a/lld/test/ELF/cgprofile-shared-warn.s +++ b/lld/test/ELF/cgprofile-shared-warn.s @@ -1,14 +1,16 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: ld.lld --shared %t.o -o /dev/null 2>&1 | count 0 -# RUN: ld.lld -e A --unresolved-symbols=ignore-all %t.o -o /dev/null 2>&1 | count 0 +# RUN: ld.lld --shared %t.o -o /dev/null 2>&1 | FileCheck %s +# RUN: ld.lld -e A --unresolved-symbols=ignore-all %t.o -o /dev/null 2>&1 | FileCheck %s # RUN: echo '.globl B; B: ret' | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t1.o # RUN: ld.lld --shared %t1.o -o %t1.so -# RUN: ld.lld -e A %t.o %t1.so -o /dev/null 2>&1 | count 0 +# RUN: ld.lld -e A %t.o %t1.so -o /dev/null 2>&1 | FileCheck %s + +# RUN: ld.lld --gc-sections %t.o %t1.so -o /dev/null 2>&1 | FileCheck %s +# CHECK-NOT: ld.lld: error: -# RUN: ld.lld --gc-sections %t.o %t1.so -o /dev/null 2>&1 | count 0 .globl _start _start: ret diff --git a/lld/test/ELF/zdefs.s b/lld/test/ELF/zdefs.s --- a/lld/test/ELF/zdefs.s +++ b/lld/test/ELF/zdefs.s @@ -10,6 +10,7 @@ # ERR: >>> referenced by {{.*}}:(.text+0x1) ## -z undefs allows unresolved references. -# RUN: ld.lld -z defs -z undefs -shared %t.o -o /dev/null 2>&1 | count 0 +# RUN: ld.lld -z defs -z undefs -shared %t.o -o /dev/null 2>&1 | FileCheck -check-prefix=ERR2 %s +# ERR2-NOT: error: undefined symbol callq foo@PLT diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -26,6 +26,7 @@ //===----------------------------------------------------------------------===// #include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -37,6 +38,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include "llvm/Support/PluginLoader.h" +#include "llvm/Support/SaveAndRestore.h" #include using namespace lld; @@ -128,19 +130,23 @@ return parseProgname(arg0); } +static unsigned inTestVerbosity() { + unsigned v{}; + StringRef(getenv("LLD_IN_TEST")).getAsInteger(10, v); + return v; +} + // If this function returns true, lld calls _exit() so that it quickly // exits without invoking destructors of globally allocated objects. // // We don't want to do that if we are running tests though, because // doing that breaks leak sanitizer. So, lit sets this environment variable, // and we use it to detect whether we are running tests or not. -static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; } +static bool canExitEarly() { return inTestVerbosity() == 0; } /// Universal linker main(). This linker emulates the gnu, darwin, or /// windows linker based on the argv[0] or -flavor option. -int main(int argc, const char **argv) { - InitLLVM x(argc, argv); - +int lldMain(int argc, const char **argv) { std::vector args(argv, argv + argc); switch (parseFlavor(args)) { case Gnu: @@ -154,10 +160,29 @@ case DarwinNew: return !macho::link(args, canExitEarly(), llvm::outs(), llvm::errs()); case Wasm: - return !wasm::link(args, canExitEarly(), llvm::outs(), llvm::errs()); + return !lld::wasm::link(args, canExitEarly(), llvm::outs(), llvm::errs()); default: die("lld is a generic driver.\n" "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" " (WebAssembly) instead"); } } + +int main(int argc, const char **argv) { + InitLLVM x(argc, argv); + Optional ret; + unsigned i = inTestVerbosity() > 0 ? inTestVerbosity() : 1; + while (i-- > 0) { + if (inTestVerbosity() > 0) { + SaveAndRestore sr(errorHandler().verbose, true); + log("LLD_IN_TEST (new LLD session)"); + } + int r = lldMain(argc, argv); + if (!ret) + ret = r; + else + assert(r == *ret); + cl::ResetAllOptionOccurrences(); + } + return *ret; +}