[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