[lld] r363962 - lld/elf: Deduplicate undefined symbol diagnostics
Nico Weber via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 20 11:25:57 PDT 2019
Author: nico
Date: Thu Jun 20 11:25:57 2019
New Revision: 363962
URL: http://llvm.org/viewvc/llvm-project?rev=363962&view=rev
Log:
lld/elf: Deduplicate undefined symbol diagnostics
Before:
```
ld.lld: error: undefined symbol: f()
>>> referenced by test.cc:3
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-9c0808.o:(g())
ld.lld: error: undefined symbol: f()
>>> referenced by test.cc:4
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-9c0808.o:(h())
ld.lld: error: undefined symbol: f()
>>> referenced by test.cc:5
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-9c0808.o:(j())
ld.lld: error: undefined symbol: k()
>>> referenced by test.cc:5
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-9c0808.o:(j())
ld.lld: error: undefined symbol: f()
>>> referenced by test2.cc:2
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test2-07b391.o:(asdf())
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```
Now:
```
ld.lld: error: undefined symbol: f()
>>> referenced by test.cc:3
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-0e07ba.o:(g())
>>> referenced by test.cc:4
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-0e07ba.o:(h())
>>> referenced by test.cc:5
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-0e07ba.o:(j())
>>> referenced by test2.cc:2
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test2-6bdb24.o:(asdf())
ld.lld: error: undefined symbol: k()
>>> referenced by test.cc:5
>>> /var/folders/c5/8d7sdn1x2mg92mj0rndghhdr0000gn/T/test-0e07ba.o:(j())
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```
If there are more than 10 references to an undefined symbol, only the
first 10 are printed.
Fixes PR42260.
Differential Revision: https://reviews.llvm.org/D63344
Added:
lld/trunk/test/ELF/undef-multi.s
Modified:
lld/trunk/ELF/Relocations.cpp
lld/trunk/ELF/Relocations.h
lld/trunk/ELF/Writer.cpp
lld/trunk/test/ELF/debug-line-obj.s
Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=363962&r1=363961&r2=363962&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Thu Jun 20 11:25:57 2019
@@ -678,27 +678,24 @@ static std::string maybeReportDiscarded(
return Msg;
}
-// Report an undefined symbol if necessary.
-// Returns true if this function printed out an error message.
-template <class ELFT>
-static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
- uint64_t Offset) {
- if (!Sym.isUndefined() || Sym.isWeak())
- return false;
+// Undefined diagnostics are collected in a vector and emitted once all of
+// them are known, so that some postprocessing on the list of undefined symbols
+// can happen before lld emits diagnostics.
+struct UndefinedDiag {
+ Symbol *Sym;
+ struct Loc {
+ InputSectionBase *Sec;
+ uint64_t Offset;
+ };
+ std::vector<Loc> Locs;
+ bool IsWarning;
+};
- bool CanBeExternal = !Sym.isLocal() && Sym.computeBinding() != STB_LOCAL &&
- Sym.Visibility == STV_DEFAULT;
- if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
- return false;
+static std::vector<UndefinedDiag> Undefs;
- // clang (as of 2019-06-12) / gcc (as of 8.2.1) PPC64 may emit a .rela.toc
- // which references a switch table in a discarded .rodata/.text section. The
- // .toc and the .rela.toc are incorrectly not placed in the comdat. The ELF
- // spec says references from outside the group to a STB_LOCAL symbol are not
- // allowed. Work around the bug.
- if (Config->EMachine == EM_PPC64 &&
- cast<Undefined>(Sym).DiscardedSecIdx != 0 && Sec.Name == ".toc")
- return false;
+template <class ELFT>
+static void reportUndefinedSymbol(const UndefinedDiag &Undef) {
+ Symbol &Sym = *Undef.Sym;
auto Visibility = [&]() -> std::string {
switch (Sym.Visibility) {
@@ -717,24 +714,83 @@ static bool maybeReportUndefined(Symbol
if (Msg.empty())
Msg = "undefined " + Visibility() + "symbol: " + toString(Sym);
- Msg += "\n>>> referenced by ";
- std::string Src = Sec.getSrcMsg(Sym, Offset);
- if (!Src.empty())
- Msg += Src + "\n>>> ";
- Msg += Sec.getObjMsg(Offset);
+ const size_t MaxUndefReferences = 10;
+ size_t I = 0;
+ for (UndefinedDiag::Loc L : Undef.Locs) {
+ if (I >= MaxUndefReferences)
+ break;
+ InputSectionBase &Sec = *L.Sec;
+ uint64_t Offset = L.Offset;
+
+ Msg += "\n>>> referenced by ";
+ std::string Src = Sec.getSrcMsg(Sym, Offset);
+ if (!Src.empty())
+ Msg += Src + "\n>>> ";
+ Msg += Sec.getObjMsg(Offset);
+ I++;
+ }
+
+ if (I < Undef.Locs.size())
+ Msg += ("\n>>> referenced " + Twine(Undef.Locs.size() - I) + " more times")
+ .str();
if (Sym.getName().startswith("_ZTV"))
Msg += "\nthe vtable symbol may be undefined because the class is missing "
"its key function (see https://lld.llvm.org/missingkeyfunction)";
- if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) ||
- Config->NoinhibitExec) {
+ if (Undef.IsWarning)
warn(Msg);
- return false;
+ else
+ error(Msg);
+}
+
+template <class ELFT> void elf::reportUndefinedSymbols() {
+ // Find the first "undefined symbol" diagnostic for each diagnostic, and
+ // collect all "referenced from" lines at the first diagnostic.
+ DenseMap<Symbol *, UndefinedDiag *> FirstRef;
+ for (UndefinedDiag &Undef : Undefs) {
+ assert(Undef.Locs.size() == 1);
+ if (UndefinedDiag *Canon = FirstRef.lookup(Undef.Sym)) {
+ Canon->Locs.push_back(Undef.Locs[0]);
+ Undef.Locs.clear();
+ } else
+ FirstRef[Undef.Sym] = &Undef;
+ }
+
+ for (const UndefinedDiag &Undef : Undefs) {
+ if (!Undef.Locs.empty())
+ reportUndefinedSymbol<ELFT>(Undef);
}
+ Undefs.clear();
+}
- error(Msg);
- return true;
+// Report an undefined symbol if necessary.
+// Returns true if the undefined symbol will produce an error message.
+template <class ELFT>
+static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
+ uint64_t Offset) {
+ if (!Sym.isUndefined() || Sym.isWeak())
+ return false;
+
+ bool CanBeExternal = !Sym.isLocal() && Sym.computeBinding() != STB_LOCAL &&
+ Sym.Visibility == STV_DEFAULT;
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
+ return false;
+
+ // clang (as of 2019-06-12) / gcc (as of 8.2.1) PPC64 may emit a .rela.toc
+ // which references a switch table in a discarded .rodata/.text section. The
+ // .toc and the .rela.toc are incorrectly not placed in the comdat. The ELF
+ // spec says references from outside the group to a STB_LOCAL symbol are not
+ // allowed. Work around the bug.
+ if (Config->EMachine == EM_PPC64 &&
+ cast<Undefined>(Sym).DiscardedSecIdx != 0 && Sec.Name == ".toc")
+ return false;
+
+ bool IsWarning =
+ (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) ||
+ Config->NoinhibitExec;
+ Undefs.push_back({&Sym, {{&Sec, Offset}}, IsWarning});
+ return !IsWarning;
}
// MIPS N32 ABI treats series of successive relocations with the same offset
@@ -1734,7 +1790,8 @@ bool ThunkCreator::createThunks(ArrayRef
Rel.Sym = T->getThunkTargetSym();
Rel.Expr = fromPlt(Rel.Expr);
- // Addend of R_PPC_PLTREL24 should be ignored after changing to R_PC.
+ // The addend of R_PPC_PLTREL24 should be ignored after changing to
+ // R_PC.
if (Config->EMachine == EM_PPC && Rel.Type == R_PPC_PLTREL24)
Rel.Addend = 0;
}
@@ -1756,3 +1813,7 @@ template void elf::scanRelocations<ELF32
template void elf::scanRelocations<ELF32BE>(InputSectionBase &);
template void elf::scanRelocations<ELF64LE>(InputSectionBase &);
template void elf::scanRelocations<ELF64BE>(InputSectionBase &);
+template void elf::reportUndefinedSymbols<ELF32LE>();
+template void elf::reportUndefinedSymbols<ELF32BE>();
+template void elf::reportUndefinedSymbols<ELF64LE>();
+template void elf::reportUndefinedSymbols<ELF64BE>();
Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=363962&r1=363961&r2=363962&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Thu Jun 20 11:25:57 2019
@@ -109,8 +109,13 @@ struct Relocation {
Symbol *Sym;
};
+// This function writes undefined symbol diagnostics to an internal buffer.
+// Call reportUndefinedSymbols() after calling scanRelocations() to emit
+// the diagnostics.
template <class ELFT> void scanRelocations(InputSectionBase &);
+template <class ELFT> void reportUndefinedSymbols();
+
void addIRelativeRelocs();
class ThunkSection;
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=363962&r1=363961&r2=363962&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Jun 20 11:25:57 2019
@@ -1737,8 +1737,10 @@ template <class ELFT> void Writer<ELFT>:
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
- if (!Config->Relocatable)
+ if (!Config->Relocatable) {
forEachRelSec(scanRelocations<ELFT>);
+ reportUndefinedSymbols<ELFT>();
+ }
addIRelativeRelocs();
Modified: lld/trunk/test/ELF/debug-line-obj.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/debug-line-obj.s?rev=363962&r1=363961&r2=363962&view=diff
==============================================================================
--- lld/trunk/test/ELF/debug-line-obj.s (original)
+++ lld/trunk/test/ELF/debug-line-obj.s Thu Jun 20 11:25:57 2019
@@ -10,7 +10,6 @@
# CHECK: error: undefined symbol: foo()
# CHECK-NEXT: >>> referenced by test.cpp:2
# CHECK-NEXT: >>> {{.*}}.o:(bar())
-# CHECK: error: undefined symbol: foo()
# CHECK-NEXT: >>> referenced by test.cpp:3
# CHECK-NEXT: >>> {{.*}}.o:(baz())
Added: lld/trunk/test/ELF/undef-multi.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/undef-multi.s?rev=363962&view=auto
==============================================================================
--- lld/trunk/test/ELF/undef-multi.s (added)
+++ lld/trunk/test/ELF/undef-multi.s Thu Jun 20 11:25:57 2019
@@ -0,0 +1,65 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o
+# RUN: not ld.lld %t.o %t2.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: zed2
+# CHECK-NEXT: >>> referenced by undef-multi.s
+# CHECK-NEXT: >>> {{.*}}:(.text+0x1)
+# CHECK-NEXT: >>> referenced by undef-multi.s
+# CHECK-NEXT: >>> {{.*}}:(.text+0x6)
+# CHECK-NEXT: >>> referenced by undef-multi.s
+# CHECK-NEXT: >>> {{.*}}:(.text+0xB)
+# CHECK-NEXT: >>> referenced by undef-multi.s
+# CHECK-NEXT: >>> {{.*}}:(.text+0x10)
+# CHECK-NEXT: >>> referenced by {{.*}}tmp2.o:(.text+0x0)
+
+# 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 zed2" >> %t.moreref.s
+# RUN: echo " call zed2" >> %t.moreref.s
+# RUN: echo " call zed2" >> %t.moreref.s
+# RUN: echo " call zed2" >> %t.moreref.s
+# RUN: echo " call zed2" >> %t.moreref.s
+# RUN: echo " call zed2" >> %t.moreref.s
+# RUN: echo " call zed2" >> %t.moreref.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t.moreref.s -o %t3.o
+# RUN: not ld.lld %t.o %t2.o %t3.o -o /dev/null -error-limit=2 2>&1 | \
+# RUN: FileCheck --check-prefix=LIMIT %s
+
+# LIMIT: error: undefined symbol: zed2
+# LIMIT-NEXT: >>> referenced by undef-multi.s
+# LIMIT-NEXT: >>> {{.*}}:(.text+0x1)
+# LIMIT-NEXT: >>> referenced by undef-multi.s
+# LIMIT-NEXT: >>> {{.*}}:(.text+0x6)
+# LIMIT-NEXT: >>> referenced by undef-multi.s
+# LIMIT-NEXT: >>> {{.*}}:(.text+0xB)
+# LIMIT-NEXT: >>> referenced by undef-multi.s
+# LIMIT-NEXT: >>> {{.*}}:(.text+0x10)
+# LIMIT-NEXT: >>> referenced by {{.*}}tmp2.o:(.text+0x0)
+# LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x1)
+# LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x6)
+# LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0xB)
+# LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x10)
+# LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x15)
+# LIMIT-NEXT: >>> referenced 2 more times
+
+.file "undef-multi.s"
+
+ .globl _start
+_start:
+ call zed2
+
+ .globl _f
+_f:
+ call zed2
+
+ .globl _g
+_g:
+ call zed2
+
+ .globl _h
+_h:
+ call zed2
More information about the llvm-commits
mailing list