Skip to content

Commit 70e62a4

Browse files
committed
[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
1 parent 9aff5e1 commit 70e62a4

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

lld/ELF/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ add_lld_library(lldELF
5252
BitWriter
5353
Core
5454
DebugInfoDWARF
55+
Demangle
5556
LTO
5657
MC
5758
Object

lld/ELF/Relocations.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "lld/Common/Memory.h"
5454
#include "lld/Common/Strings.h"
5555
#include "llvm/ADT/SmallSet.h"
56+
#include "llvm/Demangle/Demangle.h"
5657
#include "llvm/Support/Endian.h"
5758
#include "llvm/Support/raw_ostream.h"
5859
#include <algorithm>
@@ -699,7 +700,8 @@ static std::vector<UndefinedDiag> undefs;
699700
// Suggest an alternative spelling of an "undefined symbol" diagnostic. Returns
700701
// the suggested symbol, which is either in the symbol table, or in the same
701702
// file of sym.
702-
static const Symbol *getAlternativeSpelling(const Undefined &sym) {
703+
static const Symbol *getAlternativeSpelling(const Undefined &sym,
704+
std::string &pre_hint) {
703705
// Build a map of local defined symbols.
704706
DenseMap<StringRef, const Symbol *> map;
705707
if (sym.file && !isa<SharedFile>(sym.file)) {
@@ -759,6 +761,21 @@ static const Symbol *getAlternativeSpelling(const Undefined &sym) {
759761
return s;
760762
}
761763

764+
// The reference may be a mangled name while the definition is not. Suggest a
765+
// missing extern "C".
766+
if (name.startswith("_Z")) {
767+
llvm::ItaniumPartialDemangler d;
768+
if (!d.partialDemangle(name.str().c_str()))
769+
if (char *buf = d.getFunctionName(nullptr, nullptr)) {
770+
const Symbol *s = suggest(buf);
771+
free(buf);
772+
if (s) {
773+
pre_hint = ": extern \"C\" ";
774+
return s;
775+
}
776+
}
777+
}
778+
762779
return nullptr;
763780
}
764781

@@ -804,13 +821,15 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
804821
msg += ("\n>>> referenced " + Twine(undef.locs.size() - i) + " more times")
805822
.str();
806823

807-
if (correctSpelling)
824+
if (correctSpelling) {
825+
std::string pre_hint = ": ";
808826
if (const Symbol *corrected =
809-
getAlternativeSpelling(cast<Undefined>(sym))) {
810-
msg += "\n>>> did you mean: " + toString(*corrected);
827+
getAlternativeSpelling(cast<Undefined>(sym), pre_hint)) {
828+
msg += "\n>>> did you mean" + pre_hint + toString(*corrected);
811829
if (corrected->file)
812830
msg += "\n>>> defined in: " + toString(corrected->file);
813831
}
832+
}
814833

815834
if (sym.getName().startswith("_ZTV"))
816835
msg += "\nthe vtable symbol may be undefined because the class is missing "

lld/test/ELF/undef-suggest-extern-c.s

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3+
4+
## The reference is mangled while the definition is not, suggest a missing
5+
## extern "C".
6+
# RUN: echo 'call _Z3fooi' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
7+
# RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s
8+
9+
# CHECK: error: undefined symbol: foo(int)
10+
# CHECK-NEXT: >>> referenced by {{.*}}
11+
# CHECK-NEXT: >>> did you mean: extern "C" foo
12+
13+
## Don't suggest for nested names like F::foo() and foo::foo().
14+
# RUN: echo 'call _ZN1F3fooEv; call _ZN3fooC1Ev' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o
15+
# RUN: not ld.lld %t.o %t2.o -o /dev/null 2>&1 | FileCheck /dev/null --implicit-check-not='did you mean'
16+
17+
.globl _start, foo
18+
_start:
19+
foo:

0 commit comments

Comments
 (0)