summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Symbols.cpp18
-rw-r--r--lld/ELF/Symbols.h12
-rw-r--r--lld/test/ELF/weak-undef-shared.s46
-rw-r--r--lld/test/ELF/weak-undef-shared2.s21
4 files changed, 72 insertions, 25 deletions
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 9a4de4faf10..00ecc41524f 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -410,13 +410,22 @@ void Symbol::resolveUndefined(const Undefined &Other) {
if (Traced)
printTraceSymbol(&Other);
- if (isShared() || isLazy() || (isUndefined() && Other.Binding != STB_WEAK))
- Binding = Other.Binding;
-
- if (isLazy()) {
+ if (isUndefined()) {
+ // The binding may "upgrade" from weak to non-weak.
+ if (Other.Binding != STB_WEAK)
+ Binding = Other.Binding;
+ } else if (auto *S = dyn_cast<SharedSymbol>(this)) {
+ // The binding of a SharedSymbol will be weak if there is at least one
+ // reference and all are weak. The binding has one opportunity to change to
+ // weak: if the first reference is weak.
+ if (Other.Binding != STB_WEAK || !S->Referenced)
+ Binding = Other.Binding;
+ S->Referenced = true;
+ } else if (isLazy()) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (Other.Binding == STB_WEAK) {
+ Binding = STB_WEAK;
Type = Other.Type;
return;
}
@@ -635,5 +644,6 @@ void Symbol::resolveShared(const SharedSymbol &Other) {
uint8_t Bind = Binding;
replace(Other);
Binding = Bind;
+ cast<SharedSymbol>(this)->Referenced = true;
}
}
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 0782cf01f17..6ca24d4413a 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -335,8 +335,8 @@ public:
SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
uint32_t Alignment, uint32_t VerdefIndex)
- : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
- Alignment(Alignment), Value(Value), Size(Size) {
+ : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value),
+ Size(Size), Alignment(Alignment) {
this->VerdefIndex = VerdefIndex;
// GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the
@@ -360,10 +360,14 @@ public:
SharedFile &getFile() const { return *cast<SharedFile>(File); }
- uint32_t Alignment;
-
uint64_t Value; // st_value
uint64_t Size; // st_size
+ uint32_t Alignment;
+
+ // This is true if there has been at least one undefined reference to the
+ // symbol. The binding may change to STB_WEAK if the first undefined reference
+ // is weak.
+ bool Referenced = false;
};
// LazyArchive and LazyObject represent a symbols that is not yet in the link,
diff --git a/lld/test/ELF/weak-undef-shared.s b/lld/test/ELF/weak-undef-shared.s
index 301bb0f6b56..8688fd533aa 100644
--- a/lld/test/ELF/weak-undef-shared.s
+++ b/lld/test/ELF/weak-undef-shared.s
@@ -1,19 +1,31 @@
-// REQUIRES: x86
-// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
-// RUN: llvm-mc %p/Inputs/shared.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
-// RUN: ld.lld %t2.o -o %t2.so -shared
-// RUN: ld.lld %t.o %t2.so -o %t.exe
-// RUN: llvm-readobj --symbols %t.exe | FileCheck %s
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
-// CHECK: Name: bar
-// CHECK-NEXT: Value: 0x201020
-// CHECK-NEXT: Size: 0
-// CHECK-NEXT: Binding: Weak
-// CHECK-NEXT: Type: Function
-// CHECK-NEXT: Other: 0
-// CHECK-NEXT: Section: Undefined
+# RUN: echo '.data; .weak foo; .quad foo' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
+# RUN: echo '.data; .quad foo' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o
-.global _start
-_start:
- .weak bar
- .quad bar
+## If the first undefined reference is weak, the binding changes to
+## STB_WEAK.
+# RUN: ld.lld %t1.o %t.so -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s
+# RUN: ld.lld %t.so %t1.o -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s
+
+## The binding remains STB_WEAK if there is no STB_GLOBAL undefined reference.
+# RUN: ld.lld %t1.o %t.so %t1.o -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s
+# RUN: ld.lld %t.so %t1.o %t1.o -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s
+
+## The binding changes back to STB_GLOBAL if there is a STB_GLOBAL undefined reference.
+# RUN: ld.lld %t1.o %t.so %t2.o -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=GLOBAL %s
+# RUN: ld.lld %t2.o %t.so %t1.o -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=GLOBAL %s
+
+# WEAK: NOTYPE WEAK DEFAULT UND foo
+# GLOBAL: NOTYPE GLOBAL DEFAULT UND foo
+
+.globl foo
+foo:
diff --git a/lld/test/ELF/weak-undef-shared2.s b/lld/test/ELF/weak-undef-shared2.s
new file mode 100644
index 00000000000..cdd65b8c80b
--- /dev/null
+++ b/lld/test/ELF/weak-undef-shared2.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: echo '.globl f; f:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
+# RUN: echo '.weak f; .data; .quad f' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o
+# RUN: ld.lld -shared %t1.o -o %t1.so
+# RUN: ld.lld -shared %t2.o -o %t2.so
+
+## The undefined reference is STB_GLOBAL in %t.o while STB_WEAK in %t2.so.
+## Check the binding of the result is STB_GLOBAL.
+
+# RUN: ld.lld %t.o %t1.so %t2.so -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck %s
+# RUN: ld.lld %t1.so %t.o %t2.so -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck %s
+# RUN: ld.lld %t1.so %t2.so %t.o -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck %s
+
+# CHECK: NOTYPE GLOBAL DEFAULT UND f
+
+.data
+.quad f
OpenPOWER on IntegriCloud