[lld] 70e62a4 - [ELF] Suggest extern "C" when an undefined reference is mangled while the definition is not
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 8 09:43:34 PST 2019
Author: Fangrui Song
Date: 2019-11-08T09:42:50-08:00
New Revision: 70e62a4fa6c2146fb49ee4460dad8e04152ce0a6
URL: https://github.com/llvm/llvm-project/commit/70e62a4fa6c2146fb49ee4460dad8e04152ce0a6
DIFF: https://github.com/llvm/llvm-project/commit/70e62a4fa6c2146fb49ee4460dad8e04152ce0a6.diff
LOG: [ELF] Suggest extern "C" when an undefined reference is mangled while the definition is not
When missing an extern "C" declaration, an undefined reference may be
mangled while the definition is not. Suggest the missing
extern "C" and the base name.
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D69592
Added:
lld/test/ELF/undef-suggest-extern-c.s
Modified:
lld/ELF/CMakeLists.txt
lld/ELF/Relocations.cpp
Removed:
################################################################################
diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt
index 1ba79bec73df..7531a94b86e2 100644
--- a/lld/ELF/CMakeLists.txt
+++ b/lld/ELF/CMakeLists.txt
@@ -52,6 +52,7 @@ add_lld_library(lldELF
BitWriter
Core
DebugInfoDWARF
+ Demangle
LTO
MC
Object
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index d3fc5e0c7635..54035d94926c 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -53,6 +53,7 @@
#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -699,7 +700,8 @@ static std::vector<UndefinedDiag> undefs;
// Suggest an alternative spelling of an "undefined symbol" diagnostic. Returns
// the suggested symbol, which is either in the symbol table, or in the same
// file of sym.
-static const Symbol *getAlternativeSpelling(const Undefined &sym) {
+static const Symbol *getAlternativeSpelling(const Undefined &sym,
+ std::string &pre_hint) {
// Build a map of local defined symbols.
DenseMap<StringRef, const Symbol *> map;
if (sym.file && !isa<SharedFile>(sym.file)) {
@@ -759,6 +761,21 @@ static const Symbol *getAlternativeSpelling(const Undefined &sym) {
return s;
}
+ // The reference may be a mangled name while the definition is not. Suggest a
+ // missing extern "C".
+ if (name.startswith("_Z")) {
+ llvm::ItaniumPartialDemangler d;
+ if (!d.partialDemangle(name.str().c_str()))
+ if (char *buf = d.getFunctionName(nullptr, nullptr)) {
+ const Symbol *s = suggest(buf);
+ free(buf);
+ if (s) {
+ pre_hint = ": extern \"C\" ";
+ return s;
+ }
+ }
+ }
+
return nullptr;
}
@@ -804,13 +821,15 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
msg += ("\n>>> referenced " + Twine(undef.locs.size() - i) + " more times")
.str();
- if (correctSpelling)
+ if (correctSpelling) {
+ std::string pre_hint = ": ";
if (const Symbol *corrected =
- getAlternativeSpelling(cast<Undefined>(sym))) {
- msg += "\n>>> did you mean: " + toString(*corrected);
+ getAlternativeSpelling(cast<Undefined>(sym), pre_hint)) {
+ msg += "\n>>> did you mean" + pre_hint + toString(*corrected);
if (corrected->file)
msg += "\n>>> defined in: " + toString(corrected->file);
}
+ }
if (sym.getName().startswith("_ZTV"))
msg += "\nthe vtable symbol may be undefined because the class is missing "
diff --git a/lld/test/ELF/undef-suggest-extern-c.s b/lld/test/ELF/undef-suggest-extern-c.s
new file mode 100644
index 000000000000..3a2544b314d8
--- /dev/null
+++ b/lld/test/ELF/undef-suggest-extern-c.s
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+## The reference is mangled while the definition is not, suggest a missing
+## extern "C".
+# RUN: echo 'call _Z3fooi' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
+# RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: foo(int)
+# CHECK-NEXT: >>> referenced by {{.*}}
+# CHECK-NEXT: >>> did you mean: extern "C" foo
+
+## Don't suggest for nested names like F::foo() and foo::foo().
+# RUN: echo 'call _ZN1F3fooEv; call _ZN3fooC1Ev' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o
+# RUN: not ld.lld %t.o %t2.o -o /dev/null 2>&1 | FileCheck /dev/null --implicit-check-not='did you mean'
+
+.globl _start, foo
+_start:
+foo:
More information about the llvm-commits
mailing list