[llvm-branch-commits] [lld] d24b94f - [ELF] --wrap: retain __wrap_foo if foo is defined in an object/bitcode file

Fangrui Song via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jan 22 09:26:09 PST 2021


Author: Fangrui Song
Date: 2021-01-22T09:20:29-08:00
New Revision: d24b94f070ff4e6621b66d5df4b3a15a693d52bf

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

LOG: [ELF] --wrap: retain __wrap_foo if foo is defined in an object/bitcode file

If foo is referenced in any object file, bitcode file or shared object,
`__wrap_foo` should be retained as the redirection target of sym
(f96ff3c0f8ebd941b3f6b345164c3d858b781484).

If the object file defining foo has foo references, we cannot easily distinguish
the case from cases where foo is not referenced (we haven't scanned
relocations). Retain `__wrap_foo` because we choose to wrap sym references
regardless of whether sym is defined to keep non-LTO/LTO/relocatable links' behaviors similar
https://sourceware.org/bugzilla/show_bug.cgi?id=26358 .

If foo is defined in a shared object, `__wrap_foo` can still be omitted
(`wrap-dynamic-undef.s`).

Reviewed By: andrewng

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

Added: 
    lld/test/ELF/lto/wrap-defined.ll
    lld/test/ELF/wrap-defined.s

Modified: 
    lld/ELF/Driver.cpp
    lld/ELF/Options.td
    lld/docs/ld.lld.1
    lld/test/ELF/wrap-shlib-undefined.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index de613b5c9d19..72d245e5dc01 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1922,7 +1922,13 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
 
     // Tell LTO not to eliminate these symbols.
     sym->isUsedInRegularObj = true;
-    if (sym->referenced)
+    // If sym is referenced in any object file, bitcode file or shared object,
+    // retain wrap which is the redirection target of sym. If the object file
+    // defining sym has sym references, we cannot easily distinguish the case
+    // from cases where sym is not referenced. Retain wrap because we choose to
+    // wrap sym references regardless of whether sym is defined
+    // (https://sourceware.org/bugzilla/show_bug.cgi?id=26358).
+    if (sym->referenced || sym->isDefined())
       wrap->isUsedInRegularObj = true;
   }
   return v;

diff  --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index f404fdd74385..c50aa84e30e7 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -473,8 +473,9 @@ defm whole_archive: B<"whole-archive",
     "Force load of all members in a static library",
     "Do not force load of all members in a static library (default)">;
 
-defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
-  MetaVarName<"<symbol>">;
+defm wrap : Eq<"wrap", "Redirect symbol references to __wrap_symbol and "
+                       "__real_symbol references to symbol">,
+            MetaVarName<"<symbol>">;
 
 def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
   HelpText<"Linker option extensions">;

diff  --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index 1449b02c4906..79a684def275 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -635,7 +635,14 @@ Report unresolved symbols as warnings.
 .It Fl -whole-archive
 Force load of all members in a static library.
 .It Fl -wrap Ns = Ns Ar symbol
-Use wrapper functions for symbol.
+Redirect
+.Ar symbol
+references to
+.Ar __wrap_symbol
+and
+.Ar __real_symbol
+references to
+.Ar symbol.
 .It Fl z Ar option
 Linker option extensions.
 .Bl -tag -width indent -compact

diff  --git a/lld/test/ELF/lto/wrap-defined.ll b/lld/test/ELF/lto/wrap-defined.ll
new file mode 100644
index 000000000000..8a5abf8c1d85
--- /dev/null
+++ b/lld/test/ELF/lto/wrap-defined.ll
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+;; Similar to ../wrap-defined.s but for LTO.
+
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -shared %t.o -wrap=bar -o %t.so
+; RUN: llvm-objdump -d %t.so | FileCheck %s
+
+; CHECK:      <_start>:
+; CHECK-NEXT:   jmp {{.*}} <__wrap_bar at plt>
+
+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"
+
+define void @bar() {
+  ret void
+}
+
+define void @_start() {
+  call void @bar()
+  ret void
+}

diff  --git a/lld/test/ELF/wrap-defined.s b/lld/test/ELF/wrap-defined.s
new file mode 100644
index 000000000000..026b52661726
--- /dev/null
+++ b/lld/test/ELF/wrap-defined.s
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/main.s -o %t/main.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/wrap.s -o %t/wrap.o
+# RUN: ld.lld -shared --soname=fixed %t/wrap.o -o %t/wrap.so
+
+## GNU ld does not wrap a defined symbol in an object file
+## https://sourceware.org/bugzilla/show_bug.cgi?id=26358
+## We choose to wrap defined symbols so that LTO, non-LTO and relocatable links
+## behave the same. The 'call bar' in main.o will reference __wrap_bar. We cannot
+## easily distinguish the case from cases where bar is not referenced, so we
+## export __wrap_bar whenever bar is defined, regardless of whether it is indeed
+## referenced.
+
+# RUN: ld.lld -shared %t/main.o --wrap bar -o %t1.so
+# RUN: llvm-objdump -d %t1.so | FileCheck %s
+# RUN: ld.lld %t/main.o %t/wrap.so --wrap bar -o %t1
+# RUN: llvm-objdump -d %t1 | FileCheck %s
+
+# CHECK:      <_start>:
+# CHECK-NEXT:   callq {{.*}} <__wrap_bar at plt>
+
+#--- main.s
+.globl _start, bar
+_start:
+  call bar
+bar:
+
+#--- wrap.s
+.globl __wrap_bar
+__wrap_bar:
+  retq

diff  --git a/lld/test/ELF/wrap-shlib-undefined.s b/lld/test/ELF/wrap-shlib-undefined.s
index 0c4a79171e27..2897b7e39ce2 100644
--- a/lld/test/ELF/wrap-shlib-undefined.s
+++ b/lld/test/ELF/wrap-shlib-undefined.s
@@ -23,11 +23,11 @@
 # RUN: ld.lld %t/main.o %t/bar.so --wrap=foo -o %t2
 # RUN: llvm-readelf --dyn-syms %t2 | FileCheck %s --check-prefix=CHECK2
 
-## The reference __real_foo from %t/bar.so causes foo to be exported.
-## __wrap_foo is not used, thus not exported.
-# CHECK2:      Symbol table '.dynsym' contains 3 entries:
+## See wrap-plt2.s why __wrap_foo is retained.
+# CHECK2:      Symbol table '.dynsym' contains 4 entries:
 # CHECK2:      NOTYPE  LOCAL  DEFAULT  UND
 # CHECK2-NEXT: NOTYPE  GLOBAL DEFAULT  UND bar
+# CHECK2-NEXT: NOTYPE  GLOBAL DEFAULT  UND __wrap_foo
 # CHECK2-NEXT: NOTYPE  GLOBAL DEFAULT    6 foo
 
 ## __wrap_bar is undefined.


        


More information about the llvm-branch-commits mailing list