Index: lld/ELF/Driver.h =================================================================== --- lld/ELF/Driver.h +++ lld/ELF/Driver.h @@ -46,6 +46,8 @@ std::unique_ptr lto; std::vector files; + + llvm::StringSet<> addedLibraries; }; // Parses command line options. Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -201,6 +201,13 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { using namespace sys::fs; + // If we have already added the file as a library, no need to do that again. + // However, there are a few cases when the file might be processed in + // a different way and the optimization should be avoided. + if (!config->warnBackrefs && !config->formatBinary && !inWholeArchive && + addedLibraries.contains(path)) + return; + Optional buffer = readFile(path); if (!buffer.hasValue()) return; @@ -216,6 +223,11 @@ readLinkerScript(mbref); return; case file_magic::archive: { + // The optimization is incompatible with --warn-backrefs; do not waste time + // filling the set in that case. + if (!config->warnBackrefs) + addedLibraries.insert(path); + // Handle -whole-archive. if (inWholeArchive) { for (const auto &p : getArchiveMembers(mbref)) Index: lld/test/ELF/print-archive-stats.s =================================================================== --- lld/test/ELF/print-archive-stats.s +++ lld/test/ELF/print-archive-stats.s @@ -20,7 +20,8 @@ # RUN: ld.lld %t.o %tweak.a %t1.a --print-archive-stats=- -o /dev/null | diff %t.txt - ## The second %t1.a has 0 fetched member. -# RUN: ld.lld %t.o %tweak.a %t1.a %t1.a --print-archive-stats=- -o /dev/null | \ +## Note: --warn-backrefs disables the optimization which skips repeated archives. +# RUN: ld.lld %t.o %tweak.a %t1.a %t1.a --print-archive-stats=- --warn-backrefs -o /dev/null | \ # RUN: FileCheck --check-prefix=CHECK2 %s # CHECK2: members fetched archive # CHECK2-NEXT: 1 0 {{.*}}weak.a Index: lld/test/ELF/skip-repeated-libs.s =================================================================== --- /dev/null +++ lld/test/ELF/skip-repeated-libs.s @@ -0,0 +1,26 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: echo ".global foo; foo:" | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o +# RUN: rm -f %t1.a && llvm-ar rc %t1.a %t1.o + +## The linker can resolve backrefs, so the repeated adding of the library can be skipped. +# RUN: ld.lld %t1.a %t1.a %t.o -o /dev/null --verbose 2>&1 | FileCheck %s +# CHECK: {{.*}}1.a +# CHECK-NOT: {{.*}}1.a + +## If the repeated definition is given after -whole-archive, it should not be skipped. +# RUN: ld.lld %t1.a -whole-archive %t1.a %t.o -o /dev/null --verbose 2>&1 | FileCheck %s --check-prefix=WHA +# WHA: {{.*}}1.a +# WHA-NEXT: {{.*}}1.a + +## If, for any reason, the second definition is given after -format binary, +## it should not be skipped. +# RUN: ld.lld %t.o %t1.a -format binary %t1.a -o %t +# RUN: llvm-nm %t | FileCheck --check-prefix=BINARY %s +# BINARY: D _binary_{{.+}}1_a_start + + .global _start +_start: + call foo