diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -894,7 +894,14 @@ std::string pre_hint = ": ", post_hint; if (const Symbol *corrected = getAlternativeSpelling( cast(sym), pre_hint, post_hint)) { - msg += "\n>>> did you mean" + pre_hint + toString(*corrected) + post_hint; + msg += "\n>>> did you mean" + pre_hint + toString(*corrected); + StringRef name = corrected->getName(); + // The symbol name may be truncated by Symbol::parseSymbolVersion(). In + // that case, it ends with. This check is safe because every symbol name + // in symtab ends with '\0'. + if (name.data()[name.size()] == '@') + msg += name.data() + name.size(); + msg += post_hint; if (corrected->file) msg += "\n>>> defined in: " + toString(corrected->file); } diff --git a/lld/test/ELF/undef-suggest-version.s b/lld/test/ELF/undef-suggest-version.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/undef-suggest-version.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: echo 'v1 {};' > %t.ver +# RUN: ld.lld -shared --version-script %t.ver %t.o -o %t.so + +# RUN: echo 'call foo; call _Z3fooi' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o +# RUN: not ld.lld %t.so %t1.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: foo +# CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x1) +# CHECK-NEXT: >>> did you mean: foo@v1 +# CHECK-NEXT: >>> defined in: {{.*}}.so +# CHECK-EMPTY: +# CHECK-NEXT: error: undefined symbol: foo(int) +# CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x6) +# CHECK-NEXT: >>> did you mean: foo(int)@v1 +# CHECK-NEXT: >>> defined in: {{.*}}.so + +.globl foo.v1, _Z3fooi.v1 +.symver foo.v1,foo@v1 +.symver _Z3fooi.v1,_Z3fooi@v1 +foo.v1: +_Z3fooi.v1: