[llvm-branch-commits] [lld] 843c2b2 - [ELF] Error for undefined foo at v1

Fangrui Song via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Dec 1 12:09:19 PST 2020


Author: Fangrui Song
Date: 2020-12-01T08:59:54-08:00
New Revision: 843c2b2303004c1a7e4fa8037905fbc70601b155

URL: https://github.com/llvm/llvm-project/commit/843c2b2303004c1a7e4fa8037905fbc70601b155
DIFF: https://github.com/llvm/llvm-project/commit/843c2b2303004c1a7e4fa8037905fbc70601b155.diff

LOG: [ELF] Error for undefined foo at v1

If an object file has an undefined foo at v1, we emit a dynamic symbol foo.
This is incorrect if at runtime a shared object provides the non-default version foo at v1
(the undefined foo may bind to foo@@v2, for example).

GNU ld issues an error for this case, even if foo at v1 is undefined weak
(https://sourceware.org/bugzilla/show_bug.cgi?id=3351). This behavior makes
sense because to represent an undefined foo at v1, we have to construct a Verneed
entry. However, without knowing the defining filename, we cannot construct a
Verneed entry (Verneed::vn_file is unavailable).

This patch implements the error.

Depends on D92258

Reviewed By: grimar

Differential Revision: https://reviews.llvm.org/D92260

Added: 
    

Modified: 
    lld/ELF/Relocations.cpp
    lld/ELF/Symbols.h
    lld/test/ELF/lto/version-script2.ll
    lld/test/ELF/symver.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 7860aeeefcc3..c545f1c81918 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -945,7 +945,15 @@ template <class ELFT> void elf::reportUndefinedSymbols() {
 // Returns true if the undefined symbol will produce an error message.
 static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
                                  uint64_t offset) {
-  if (!sym.isUndefined() || sym.isWeak())
+  if (!sym.isUndefined())
+    return false;
+  // If versioned, issue an error (even if the symbol is weak) because we don't
+  // know the defining filename which is required to construct a Verneed entry.
+  if (*sym.getVersionSuffix() == '@') {
+    undefs.push_back({&sym, {{&sec, offset}}, false});
+    return true;
+  }
+  if (sym.isWeak())
     return false;
 
   bool canBeExternal = !sym.isLocal() && sym.visibility == STV_DEFAULT;

diff  --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 48428c24f9c8..bb87ac75f9c6 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -183,7 +183,7 @@ class Symbol {
   // For @@, the name has been truncated by insert(). For @, the name has been
   // truncated by Symbol::parseSymbolVersion().
   const char *getVersionSuffix() const {
-    assert(nameSize != (uint32_t)-1);
+    (void)getName();
     return nameData + nameSize;
   }
 

diff  --git a/lld/test/ELF/lto/version-script2.ll b/lld/test/ELF/lto/version-script2.ll
index b8c8b56b4317..154e9facd450 100644
--- a/lld/test/ELF/lto/version-script2.ll
+++ b/lld/test/ELF/lto/version-script2.ll
@@ -4,13 +4,21 @@
 ;; otherwise we may get a symbol named "foo@@VER1", but not "foo" with the
 ;; version VER1.
 
-; RUN: llvm-as %s -o %t.o
+; RUN: split-file %s %t
+; RUN: llvm-as %t/ir -o %t.o
+; RUN: llvm-mc -filetype=obj -triple=x86_64 %t/asm -o %tbar.o
+; RUN: ld.lld %tbar.o -shared --soname=tbar --version-script %t.script -o %tbar.so
 ; RUN: echo "VER1 {};" > %t.script
-; RUN: ld.lld %t.o -o %t.so -shared --version-script %t.script
+
+;; Emit an error if bar at VER1 is not defined.
+; RUN: not ld.lld %t.o -o /dev/null -shared --version-script %t.script 2>&1 | FileCheck %s --check-prefix=UNDEF
+
+; UNDEF: error: undefined symbol: bar at VER1
+
+; RUN: ld.lld %t.o %tbar.so -o %t.so -shared --version-script %t.script
 ; RUN: llvm-readelf --dyn-syms %t.so | FileCheck %s
 
-;; For non-relocatable output, @ in symbol names has no effect on undefined symbols.
-; CHECK:      UND       bar{{$}}
+; CHECK:      UND       bar at VER1
 ; CHECK-NEXT: {{[1-9]}} foo@@VER1
 
 ;; For relocatable output, @ should be retained in the symbol name.
@@ -21,6 +29,7 @@
 ; RELOCATABLE:      {{[1-9]}} foo@@VER1
 ; RELOCATABLE-NEXT: UND       bar at VER1
 
+;--- ir
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
 
@@ -28,3 +37,9 @@ module asm ".global foo"
 module asm "foo: call bar"
 module asm ".symver foo,foo@@@VER1"
 module asm ".symver bar,bar@@@VER1"
+
+;--- asm
+.globl bar
+.symver bar,bar@@@VER1
+bar:
+  ret

diff  --git a/lld/test/ELF/symver.s b/lld/test/ELF/symver.s
index 2858e835622a..7111f4264f3d 100644
--- a/lld/test/ELF/symver.s
+++ b/lld/test/ELF/symver.s
@@ -5,6 +5,7 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %t/ref.s -o %t/ref.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %t/ref1.s -o %t/ref1.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %t/ref1p.s -o %t/ref1p.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/ref1w.s -o %t/ref1w.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %t/def1.s -o %t/def1.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %t/def1w.s -o %t/def1w.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %t/hid1.s -o %t/hid1.o
@@ -45,13 +46,16 @@
 # CHECK-EMPTY:
 
 ## foo@@v2 does not resolve undefined foo at v1.
-## TODO Undefined 'foo at v1' should be errored.
-# RUN: ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/def2.o -o %t2
-# RUN: llvm-readelf --dyn-syms %t2 | FileCheck %s --check-prefix=CHECK2
+# RUN: not ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/def2.o \
+# RUN:   -o /dev/null 2>&1 | FileCheck %s --check-prefix=UNDEF
 
-# CHECK2:       1: {{.*}} NOTYPE GLOBAL DEFAULT UND   foo{{$}}
-# CHECK2-NEXT:  2: {{.*}} NOTYPE GLOBAL DEFAULT [[#]] foo@@v2
-# CHECK2-EMPTY:
+# UNDEF: error: undefined symbol: foo at v1
+
+## An undefined weak unversioned symbol is not errored. However, an undefined
+## weak versioned symbol should still be errored because we cannot construct
+## a Verneed entry (Verneed::vn_file is unavailable).
+# RUN: not ld.lld -shared --version-script=%t/ver %t/ref1w.o -o /dev/null 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=UNDEF
 
 ## foo@@v2 resolves undefined foo while foo at v1 resolves undefined foo at v1.
 # RUN: ld.lld -shared --soname=t --version-script=%t/ver %t/ref.o %t/ref1.o %t/hid1.o %t/def2.o -o %t3
@@ -128,15 +132,15 @@
 
 ## Test --wrap on @ and @@.
 
-## TODO Error because __wrap_foo at v1 is not defined.
+## Error because __wrap_foo at v1 is not defined.
 ## Note: GNU ld errors "no symbol version section for versioned symbol `__wrap_foo at v1'".
-# RUN: ld.lld -shared --soname=t --version-script=%t/ver --wrap=foo at v1 %t/ref.o %t/ref1.o %t/def1.o %t/wrap.o -o %t.w3
-# RUN: llvm-readobj -r %t.w3 | FileCheck %s --check-prefix=W3REL
+# RUN: not ld.lld -shared --soname=t --version-script=%t/ver --wrap=foo at v1 %t/ref.o %t/ref1.o %t/def1.o %t/wrap.o \
+# RUN:   -o /dev/null 2>&1 | FileCheck %s --check-prefix=W3
 
-# W3REL:      .rela.plt {
-# W3REL-NEXT:   R_X86_64_JUMP_SLOT foo@@v1 0x0
-# W3REL-NEXT:   R_X86_64_JUMP_SLOT - 0x0
-# W3REL-NEXT: }
+# W3:      error: undefined symbol: __wrap_foo at v1
+# W3-NEXT: >>> referenced by {{.*}}ref1.o:(.text+0x1)
+# W3-NEXT: >>> did you mean: __wrap_foo{{$}}
+# W3-NEXT: >>> defined in: {{.*}}wrap.o
 
 ## foo at v1 is correctly wrapped.
 # RUN: ld.lld -shared --soname=t --version-script=%t/ver --wrap=foo at v1 %t/ref.o %t/ref1.o %t/def1.o %t/wrap1.o -o %t.w4
@@ -183,6 +187,11 @@ call foo
 .symver foo, foo@@@v1
 call foo
 
+#--- ref1w.s
+.weak foo
+.symver foo, foo@@@v1
+call foo
+
 #--- def1.s
 .globl foo
 .symver foo, foo@@@v1


        


More information about the llvm-branch-commits mailing list