[ELF] resolveUndefined: ignore undefined symbols in SharedFile for Undefined and SharedSymbol
If %t1.o has a weak reference on foo, and %t2.so has a non-weak
reference on foo: `ld.lld %t1.o %t2.so -o %t`
We incorrectly set the binding of the undefined foo to STB_GLOBAL.
Fix this by ignoring undefined symbols in a SharedFile for Undefined and
SharedSymbol.
This fixes the binding of pthread_once when the program links against
both librt.so and libpthread.so
```
a.o: STB_WEAK reference to pthread_once
librt.so: STB_GLOBAL reference to pthread_once # should be ignored
libstdc++.so: STB_WEAK reference to pthread_once # should be ignored
libgcc_s.so.1: STB_WEAK reference to pthread_once # should be ignored
```
The STB_GLOBAL pthread_once issue (not fixed by D63974) can cause a link error when the result
DSO is used to link another DSO with -z defs if -lpthread is not specified. (libstdc++.so.6 not having a dependency on libpthread.so is a really nasty hack...)
We happened to create a weak undef before D63974 because libgcc_s.so.1
was linked the last and it changed the binding again to weak.
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D64136
llvm-svn: 365129
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 172bdf1..6a0f9ef 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -410,18 +410,7 @@
if (Traced)
printTraceSymbol(&Other);
- 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()) {
+ 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) {
@@ -489,6 +478,24 @@
if (Backref && !isWeak())
warn("backward reference detected: " + Other.getName() + " in " +
toString(Other.File) + " refers to " + toString(File));
+ return;
+ }
+
+ // Undefined symbols in a SharedFile do not change the binding.
+ if (dyn_cast_or_null<SharedFile>(Other.File))
+ return;
+
+ 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;
}
}