[ELF] resolveUndefined: ignore undefined symbols in SharedFile for Undefined and...
authorFangrui Song <maskray@google.com>
Thu, 4 Jul 2019 10:38:04 +0000 (10:38 +0000)
committerFangrui Song <maskray@google.com>
Thu, 4 Jul 2019 10:38:04 +0000 (10:38 +0000)
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

lld/ELF/Symbols.cpp
lld/test/ELF/archive-fetch.s
lld/test/ELF/weak-undef-shared.s

index 172bdf1..6a0f9ef 100644 (file)
@@ -410,18 +410,7 @@ void Symbol::resolveUndefined(const Undefined &Other) {
   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 @@ void Symbol::resolveUndefined(const Undefined &Other) {
     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;
   }
 }
 
index 201218f..cefbc05 100644 (file)
@@ -9,7 +9,14 @@
 # RUN: llvm-ar rcs %t.a %tfoo.o %tbar.o
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: ld.lld %t.a %t.o -o /dev/null
+# RUN: ld.lld %t.a %t.o -o %t
+# RUN: llvm-nm %t | FileCheck %s
+
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: ld.lld %t.a %t.so -o %t
+# RUN: llvm-nm %t | FileCheck %s
+
+# CHECK: T foo
 
 _start:
 callq foo
index 8688fd5..713a1d3 100644 (file)
 # RUN: ld.lld %t2.o %t.so %t1.o -o %t
 # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=GLOBAL %s
 
+## Check the binding (weak) is not affected by the STB_GLOBAL undefined
+## reference in %t2.so
+# RUN: ld.lld %t1.o %t2.so -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s
+
 # WEAK:   NOTYPE WEAK   DEFAULT UND foo
 # GLOBAL: NOTYPE GLOBAL DEFAULT UND foo