[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