[lld] r364285 - Port r363962 to COFF: Deduplicate undefined symbol diagnostics

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 25 02:55:55 PDT 2019


Author: nico
Date: Tue Jun 25 02:55:55 2019
New Revision: 364285

URL: http://llvm.org/viewvc/llvm-project?rev=364285&view=rev
Log:
Port r363962 to COFF: Deduplicate undefined symbol diagnostics

lld/coff already deduplicated undefined symbols on a TU level: It would
group all references to a symbol from a single TU. This makes it so that
references from all TUs to a single symbol are grouped together.

Since lld/coff almost did what I thought it did already, the patch is
much smaller than the elf version. The only not local change is that
getSymbolLocations() now returns a vector<string> instead of a string,
so that the undefined symbol reporting code can know how many references
to a symbol exist in a given TU.

Fixes PR42260 for lld/coff.

Differential Revision: https://reviews.llvm.org/D63646

Added:
    lld/trunk/test/COFF/undefined-symbol-multi.s
Modified:
    lld/trunk/COFF/Chunks.cpp
    lld/trunk/COFF/SymbolTable.cpp
    lld/trunk/COFF/SymbolTable.h

Modified: lld/trunk/COFF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=364285&r1=364284&r2=364285&view=diff
==============================================================================
--- lld/trunk/COFF/Chunks.cpp (original)
+++ lld/trunk/COFF/Chunks.cpp Tue Jun 25 02:55:55 2019
@@ -336,8 +336,15 @@ static void maybeReportRelocationToDisca
     File->getCOFFObj()->getSymbolName(COFFSym, Name);
   }
 
-  error("relocation against symbol in discarded section: " + Name +
-        getSymbolLocations(File, Rel.SymbolTableIndex));
+  std::vector<std::string> SymbolLocations =
+      getSymbolLocations(File, Rel.SymbolTableIndex);
+
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  OS << "relocation against symbol in discarded section: " + Name;
+  for (const std::string &S : SymbolLocations)
+    OS << S;
+  error(OS.str());
 }
 
 void SectionChunk::writeTo(uint8_t *Buf) const {

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=364285&r1=364284&r2=364285&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Tue Jun 25 02:55:55 2019
@@ -79,7 +79,11 @@ static Symbol *getSymbol(SectionChunk *S
   return Candidate;
 }
 
-std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+// Given a file and the index of a symbol in that file, returns a description
+// 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<std::string> getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
   struct Location {
     Symbol *Sym;
     std::pair<StringRef, uint32_t> FileLine;
@@ -102,11 +106,12 @@ std::string getSymbolLocations(ObjFile *
   }
 
   if (Locations.empty())
-    return "\n>>> referenced by " + toString(File);
+    return std::vector<std::string>({"\n>>> referenced by " + toString(File)});
 
-  std::string Out;
-  llvm::raw_string_ostream OS(Out);
+  std::vector<std::string> SymbolLocations(Locations.size());
+  size_t I = 0;
   for (Location Loc : Locations) {
+    llvm::raw_string_ostream OS(SymbolLocations[I++]);
     OS << "\n>>> referenced by ";
     if (!Loc.FileLine.first.empty())
       OS << Loc.FileLine.first << ":" << Loc.FileLine.second
@@ -115,7 +120,41 @@ std::string getSymbolLocations(ObjFile *
     if (Loc.Sym)
       OS << ":(" << toString(*Loc.Sym) << ')';
   }
-  return OS.str();
+  return SymbolLocations;
+}
+
+// For an undefined symbol, stores all files referencing it and the index of
+// the undefined symbol in each file.
+struct UndefinedDiag {
+  Symbol *Sym;
+  struct File {
+    ObjFile *File;
+    uint64_t SymIndex;
+  };
+  std::vector<File> Files;
+};
+
+static void reportUndefinedSymbol(const UndefinedDiag &UndefDiag) {
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  OS << "undefined symbol: " << toString(*UndefDiag.Sym);
+
+  const size_t MaxUndefReferences = 10;
+  size_t I = 0, NumRefs = 0;
+  for (const UndefinedDiag::File &Ref : UndefDiag.Files) {
+    std::vector<std::string> SymbolLocations =
+        getSymbolLocations(Ref.File, Ref.SymIndex);
+    NumRefs += 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";
+  errorOrWarn(OS.str());
 }
 
 void SymbolTable::loadMinGWAutomaticImports() {
@@ -263,15 +302,24 @@ void SymbolTable::reportRemainingUndefin
              " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
   }
 
+  std::vector<UndefinedDiag> UndefDiags;
+  DenseMap<Symbol *, int> FirstDiag;
+
   for (ObjFile *File : ObjFile::Instances) {
     size_t SymIndex = (size_t)-1;
     for (Symbol *Sym : File->getSymbols()) {
       ++SymIndex;
       if (!Sym)
         continue;
-      if (Undefs.count(Sym))
-        errorOrWarn("undefined symbol: " + toString(*Sym) +
-                    getSymbolLocations(File, SymIndex));
+      if (Undefs.count(Sym)) {
+        auto it = FirstDiag.find(Sym);
+        if (it == FirstDiag.end()) {
+          FirstDiag[Sym] = UndefDiags.size();
+          UndefDiags.push_back({Sym, {{File, SymIndex}}});
+        } else {
+          UndefDiags[it->second].Files.push_back({File, SymIndex});
+        }
+      }
       if (Config->WarnLocallyDefinedImported)
         if (Symbol *Imp = LocalImports.lookup(Sym))
           warn(toString(File) +
@@ -279,6 +327,9 @@ void SymbolTable::reportRemainingUndefin
                " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
     }
   }
+
+  for (const UndefinedDiag& UndefDiag : UndefDiags)
+    reportUndefinedSymbol(UndefDiag);
 }
 
 std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {

Modified: lld/trunk/COFF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=364285&r1=364284&r2=364285&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.h (original)
+++ lld/trunk/COFF/SymbolTable.h Tue Jun 25 02:55:55 2019
@@ -123,7 +123,7 @@ private:
 
 extern SymbolTable *Symtab;
 
-std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex);
+std::vector<std::string> getSymbolLocations(ObjFile *File, uint32_t SymIndex);
 
 } // namespace coff
 } // namespace lld

Added: lld/trunk/test/COFF/undefined-symbol-multi.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/undefined-symbol-multi.s?rev=364285&view=auto
==============================================================================
--- lld/trunk/test/COFF/undefined-symbol-multi.s (added)
+++ lld/trunk/test/COFF/undefined-symbol-multi.s Tue Jun 25 02:55:55 2019
@@ -0,0 +1,47 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
+
+# All references to a single undefined symbol count as a single error -- but
+# at most 10 references are printed.
+# RUN: echo ".globl bar" > %t.moreref.s
+# RUN: echo "bar:" >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# RUN: echo '  call "?foo@@YAHXZ"' >> %t.moreref.s
+# 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
+
+# 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 by {{.*}}tmp2.obj:(bar)
+# CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar)
+# CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar)
+# CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar)
+# CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar)
+# CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar)
+# CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar)
+# CHECK-NEXT: >>> referenced 2 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)
+
+        .section        .text,"xr",one_only,main
+.globl main
+main:
+	call	"?foo@@YAHXZ"
+	call	"?foo@@YAHXZ"
+	call	"?bar@@YAHXZ"
+
+f1:
+	call	"?bar@@YAHXZ"
+.Lfunc_end1:




More information about the llvm-commits mailing list