diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -136,12 +136,16 @@ // of all references to that symbol from that file. If no debug information is // available, returns just the name of the file, else one string per actual // reference as described in the debug info. -std::vector getSymbolLocations(ObjFile *file, uint32_t symIndex) { +// Returns up to maxStrings string descriptions, along with the total number of +// locations found. +static std::pair, size_t> +getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) { struct Location { Symbol *sym; std::pair fileLine; }; std::vector locations; + size_t numLocations = 0; for (Chunk *c : file->getChunks()) { auto *sc = dyn_cast(c); @@ -150,6 +154,10 @@ for (const coff_relocation &r : sc->getRelocs()) { if (r.SymbolTableIndex != symIndex) continue; + numLocations++; + if (locations.size() >= maxStrings) + continue; + Optional> fileLine = getFileLine(sc, r.VirtualAddress); Symbol *sym = getSymbol(sc, r.VirtualAddress); @@ -160,8 +168,12 @@ } } - if (locations.empty()) - return std::vector({"\n>>> referenced by " + toString(file)}); + if (maxStrings == 0) + return std::make_pair(std::vector(), numLocations); + + if (numLocations == 0) + return std::make_pair( + std::vector{"\n>>> referenced by " + toString(file)}, 1); std::vector symbolLocations(locations.size()); size_t i = 0; @@ -175,17 +187,26 @@ if (loc.sym) os << ":(" << toString(*loc.sym) << ')'; } - return symbolLocations; + return std::make_pair(symbolLocations, numLocations); +} + +std::vector getSymbolLocations(ObjFile *file, uint32_t symIndex) { + return getSymbolLocations(file, symIndex, SIZE_MAX).first; } -std::vector getSymbolLocations(InputFile *file, - uint32_t symIndex) { +static std::pair, size_t> +getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) { if (auto *o = dyn_cast(file)) - return getSymbolLocations(o, symIndex); - if (auto *b = dyn_cast(file)) - return getSymbolLocations(b); + return getSymbolLocations(o, symIndex, maxStrings); + if (auto *b = dyn_cast(file)) { + std::vector symbolLocations = getSymbolLocations(b); + size_t numLocations = symbolLocations.size(); + if (symbolLocations.size() > maxStrings) + symbolLocations.resize(maxStrings); + return std::make_pair(symbolLocations, numLocations); + } llvm_unreachable("unsupported file type passed to getSymbolLocations"); - return {}; + return std::make_pair(std::vector(), (size_t)0); } // For an undefined symbol, stores all files referencing it and the index of @@ -205,20 +226,21 @@ os << "undefined symbol: " << toString(*undefDiag.sym); const size_t maxUndefReferences = 3; - size_t i = 0, numRefs = 0; + size_t numDisplayedRefs = 0, numRefs = 0; for (const UndefinedDiag::File &ref : undefDiag.files) { - std::vector symbolLocations = - getSymbolLocations(ref.file, ref.symIndex); - numRefs += symbolLocations.size(); + std::vector symbolLocations; + size_t totalLocations = 0; + std::tie(symbolLocations, totalLocations) = getSymbolLocations( + ref.file, ref.symIndex, maxUndefReferences - numDisplayedRefs); + + numRefs += totalLocations; + numDisplayedRefs += symbolLocations.size(); for (const std::string &s : symbolLocations) { - if (i >= maxUndefReferences) - break; os << s; - i++; } } - if (i < numRefs) - os << "\n>>> referenced " << numRefs - i << " more times"; + if (numDisplayedRefs < numRefs) + os << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times"; errorOrWarn(os.str()); } diff --git a/lld/test/COFF/Inputs/undefined-symbol-multi-lto.ll b/lld/test/COFF/Inputs/undefined-symbol-multi-lto.ll new file mode 100644 --- /dev/null +++ b/lld/test/COFF/Inputs/undefined-symbol-multi-lto.ll @@ -0,0 +1,23 @@ +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc" + +define dso_local i32 @"?baz@@YAHXZ"() #0 { + %1 = call i32 @"?foo@@YAHXZ"() + %2 = call i32 @"?foo@@YAHXZ"() + %3 = call i32 @"?bar@@YAHXZ"() + %4 = call i32 @"?bar@@YAHXZ"() + ret i32 0 +} + +declare dso_local i32 @"?foo@@YAHXZ"() #1 + +declare dso_local i32 @"?bar@@YAHXZ"() #1 + +attributes #0 = { noinline optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git bed3e1a99b41f5a9525bc0edf12ecbcf63aab0cf)"} diff --git a/lld/test/COFF/undefined-symbol-multi.s b/lld/test/COFF/undefined-symbol-multi.s --- a/lld/test/COFF/undefined-symbol-multi.s +++ b/lld/test/COFF/undefined-symbol-multi.s @@ -16,17 +16,20 @@ # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t2.obj %t.moreref.s -# RUN: not lld-link /out:/dev/null %t.obj %t2.obj 2>&1 | FileCheck %s +# RUN: llvm-as %S/Inputs/undefined-symbol-multi-lto.ll -o %t3.obj +# RUN: not lld-link /out:/dev/null %t.obj %t2.obj %t3.obj 2>&1 | FileCheck %s # CHECK: error: undefined symbol: int __cdecl foo(void) # CHECK-NEXT: >>> referenced by {{.*}}tmp.obj:(main) # CHECK-NEXT: >>> referenced by {{.*}}tmp.obj:(main) # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) -# CHECK-NEXT: >>> referenced 9 more times +# CHECK-NEXT: >>> referenced 10 more times # CHECK-EMPTY: # CHECK-NEXT: error: undefined symbol: int __cdecl bar(void) # CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) # CHECK-NEXT: >>> referenced by {{.*}}.obj:(f1) +# CHECK-NEXT: >>> referenced by {{.*}}undefined-symbol-multi-lto.ll +# CHECK-NEXT: >>> {{.*}}tmp3.obj .section .text,"xr",one_only,main .globl main