[lld] r304719 - Symbols re-defined with -wrap and -defsym need to be excluded from inter-

Dmitry Mikulin via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 5 09:24:25 PDT 2017


Author: dmikulin
Date: Mon Jun  5 11:24:25 2017
New Revision: 304719

URL: http://llvm.org/viewvc/llvm-project?rev=304719&view=rev
Log:
Symbols re-defined with -wrap and -defsym need to be excluded from inter-
procedural optimizations to prevent dropping symbols and allow the linker
to process re-directs.

PR33145: --wrap doesn't work with lto.
Differential Revision: https://reviews.llvm.org/D33621

Added:
    lld/trunk/test/ELF/lto/Inputs/defsym-bar.ll
    lld/trunk/test/ELF/lto/Inputs/wrap-bar.ll
    lld/trunk/test/ELF/lto/defsym.ll
    lld/trunk/test/ELF/lto/wrap-1.ll
    lld/trunk/test/ELF/lto/wrap-2.ll
Modified:
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/LTO.cpp
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=304719&r1=304718&r2=304719&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Mon Jun  5 11:24:25 2017
@@ -67,6 +67,12 @@ struct VersionDefinition {
   size_t NameOff = 0; // Offset in the string table
 };
 
+// Structure for mapping renamed symbols
+struct RenamedSymbol {
+  Symbol *Target;
+  uint8_t OrigBinding;
+};
+
 // This struct contains the global configuration for the linker.
 // Most fields are direct mapping from the command line options
 // and such fields have the same name as the corresponding options.
@@ -98,6 +104,7 @@ struct Configuration {
   std::vector<SymbolVersion> VersionScriptGlobals;
   std::vector<SymbolVersion> VersionScriptLocals;
   std::vector<uint8_t> BuildIdVector;
+  llvm::MapVector<Symbol *, RenamedSymbol> RenamedSymbols;
   bool AllowMultipleDefinition;
   bool AsNeeded = false;
   bool Bsymbolic;

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=304719&r1=304718&r2=304719&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Mon Jun  5 11:24:25 2017
@@ -970,6 +970,14 @@ template <class ELFT> void LinkerDriver:
   Symtab.scanShlibUndefined();
   Symtab.scanVersionScript();
 
+  // Create wrapped symbols for -wrap option.
+  for (auto *Arg : Args.filtered(OPT_wrap))
+    Symtab.addSymbolWrap(Arg->getValue());
+
+  // Create alias symbols for -defsym option.
+  for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
+    Symtab.addSymbolAlias(Def.first, Def.second);
+
   Symtab.addCombinedLTOObject();
   if (ErrorCount)
     return;
@@ -979,12 +987,8 @@ template <class ELFT> void LinkerDriver:
   for (StringRef Sym : Script->Opt.ReferencedSymbols)
     Symtab.addUndefined(Sym);
 
-  for (auto *Arg : Args.filtered(OPT_wrap))
-    Symtab.wrap(Arg->getValue());
-
-  // Handle --defsym=sym=alias option.
-  for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
-    Symtab.alias(Def.first, Def.second);
+  // Apply symbol renames for -wrap and -defsym
+  Symtab.applySymbolRenames();
 
   // Now that we have a complete list of input files.
   // Beyond this point, no new files are added.

Modified: lld/trunk/ELF/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LTO.cpp?rev=304719&r1=304718&r2=304719&view=diff
==============================================================================
--- lld/trunk/ELF/LTO.cpp (original)
+++ lld/trunk/ELF/LTO.cpp Mon Jun  5 11:24:25 2017
@@ -136,6 +136,7 @@ void BitcodeCompiler::add(BitcodeFile &F
         Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
     if (R.Prevailing)
       undefine(Sym);
+    R.LinkerRedefined = Config->RenamedSymbols.count(Sym);
   }
   checkError(LTOObj->add(std::move(F.Obj), Resols));
 }

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=304719&r1=304718&r2=304719&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Mon Jun  5 11:24:25 2017
@@ -156,7 +156,7 @@ template <class ELFT> void SymbolTable<E
 
 // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
 // Used to implement --wrap.
-template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
+template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) {
   SymbolBody *B = find(Name);
   if (!B)
     return;
@@ -164,16 +164,16 @@ template <class ELFT> void SymbolTable<E
   Symbol *Real = addUndefined(Saver.save("__real_" + Name));
   Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
 
-  // We rename symbols by replacing the old symbol's SymbolBody with the new
-  // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
-  // old symbol to instead refer to the new symbol.
-  memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body));
-  memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
+  // Tell LTO not to eliminate this symbol
+  Wrap->IsUsedInRegularObj = true;
+
+  Config->RenamedSymbols[Real] = RenamedSymbol{Sym, Real->Binding};
+  Config->RenamedSymbols[Sym] = RenamedSymbol{Wrap, Sym->Binding};
 }
 
 // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
-template <class ELFT>
-void SymbolTable<ELFT>::alias(StringRef Alias, StringRef Name) {
+template <class ELFT> void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias,
+                                                             StringRef Name) {
   SymbolBody *B = find(Name);
   if (!B) {
     error("-defsym: undefined symbol: " + Name);
@@ -181,7 +181,27 @@ void SymbolTable<ELFT>::alias(StringRef
   }
   Symbol *Sym = B->symbol();
   Symbol *AliasSym = addUndefined(Alias);
-  memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body));
+
+  // Tell LTO not to eliminate this symbol
+  Sym->IsUsedInRegularObj = true;
+  Config->RenamedSymbols[AliasSym] = RenamedSymbol{Sym, AliasSym->Binding};
+}
+
+// Apply symbol renames created by -wrap and -defsym. The renames are created
+// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform
+// LTO (if LTO is running) not to include these symbols in IPO. Now that the
+// symbols are finalized, we can perform the replacement.
+template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() {
+  for (auto &KV : Config->RenamedSymbols) {
+    Symbol *Sym = KV.first;
+    Symbol *Rename = KV.second.Target;
+    Sym->Binding = KV.second.OrigBinding;
+
+    // We rename symbols by replacing the old symbol's SymbolBody with the new
+    // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
+    // old symbol to instead refer to the new symbol.
+    memcpy(Sym->Body.buffer, Rename->Body.buffer, sizeof(Sym->Body));
+  }
 }
 
 static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=304719&r1=304718&r2=304719&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Mon Jun  5 11:24:25 2017
@@ -39,6 +39,9 @@ template <class ELFT> class SymbolTable
 public:
   void addFile(InputFile *File);
   void addCombinedLTOObject();
+  void addSymbolAlias(StringRef Alias, StringRef Name);
+  void addSymbolWrap(StringRef Name);
+  void applySymbolRenames();
 
   ArrayRef<Symbol *> getSymbols() const { return SymVector; }
   ArrayRef<ObjectFile<ELFT> *> getObjectFiles() const { return ObjectFiles; }
@@ -85,8 +88,6 @@ public:
   SymbolBody *findInCurrentDSO(StringRef Name);
 
   void trace(StringRef Name);
-  void wrap(StringRef Name);
-  void alias(StringRef Alias, StringRef Name);
 
 private:
   std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);

Added: lld/trunk/test/ELF/lto/Inputs/defsym-bar.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/Inputs/defsym-bar.ll?rev=304719&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/Inputs/defsym-bar.ll (added)
+++ lld/trunk/test/ELF/lto/Inputs/defsym-bar.ll Mon Jun  5 11:24:25 2017
@@ -0,0 +1,21 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @this_is_bar1()
+declare void @this_is_bar2()
+declare void @this_is_bar3()
+
+define hidden void @bar1() {
+  call void @this_is_bar1()
+  ret void
+}
+
+define hidden void @bar2() {
+  call void @this_is_bar2()
+  ret void
+}
+
+define hidden void @bar3() {
+  call void @this_is_bar3()
+  ret void
+}

Added: lld/trunk/test/ELF/lto/Inputs/wrap-bar.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/Inputs/wrap-bar.ll?rev=304719&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/Inputs/wrap-bar.ll (added)
+++ lld/trunk/test/ELF/lto/Inputs/wrap-bar.ll Mon Jun  5 11:24:25 2017
@@ -0,0 +1,14 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define hidden void @bar() {
+  ret void
+}
+
+define hidden void @__real_bar() {
+  ret void
+}
+
+define hidden void @__wrap_bar() {
+  ret void
+}

Added: lld/trunk/test/ELF/lto/defsym.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/defsym.ll?rev=304719&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/defsym.ll (added)
+++ lld/trunk/test/ELF/lto/defsym.ll Mon Jun  5 11:24:25 2017
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o
+; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3
+; RUN: llvm-objdump -d %t.so | FileCheck %s
+
+; Call to bar2() should not be inlined and should be routed to bar3()
+; Symbol bar3 should not be eliminated
+
+; CHECK:      foo:
+; CHECK-NEXT: pushq	%rax
+; CHECK-NEXT: callq
+; CHECK-NEXT: callq{{.*}}<bar3>
+; CHECK-NEXT: callq
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar1()
+declare void @bar2()
+declare void @bar3()
+
+define void @foo() {
+  call void @bar1()
+  call void @bar2()
+  call void @bar3()
+  ret void
+}

Added: lld/trunk/test/ELF/lto/wrap-1.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/wrap-1.ll?rev=304719&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/wrap-1.ll (added)
+++ lld/trunk/test/ELF/lto/wrap-1.ll Mon Jun  5 11:24:25 2017
@@ -0,0 +1,35 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps
+; RUN: llvm-readobj -t %t.out | FileCheck %s
+; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s
+
+; CHECK:      Name: __wrap_bar
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+
+; Make sure that the 'r' (linker redefined) bit is set for bar and __wrap_bar
+; in the resolutions file.
+; RESOLS: ,bar,r
+; RESOLS: ,__wrap_bar,px
+; RESOLS: ,__real_bar,pxr
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+
+define void @_start() {
+  call void @bar()
+  ret void
+}
+
+define void @__wrap_bar() {
+  ret void
+}
+
+define void @__real_bar() {
+  ret void
+}

Added: lld/trunk/test/ELF/lto/wrap-2.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/wrap-2.ll?rev=304719&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/wrap-2.ll (added)
+++ lld/trunk/test/ELF/lto/wrap-2.ll Mon Jun  5 11:24:25 2017
@@ -0,0 +1,36 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o
+; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar
+; RUN: llvm-objdump -d %t.so | FileCheck %s
+; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s
+
+; Make sure that calls in foo() are not eliminated and that bar is
+; routed to __wrap_bar and __real_bar is routed to bar.
+
+; CHECK:      foo:
+; CHECK-NEXT: pushq	%rax
+; CHECK-NEXT: callq{{.*}}<__wrap_bar>
+; CHECK-NEXT: callq{{.*}}<bar>
+
+; Check that bar and __wrap_bar retain their original binding.
+; BIND:      Name: bar
+; BIND-NEXT: Value:
+; BIND-NEXT: Size:
+; BIND-NEXT: Binding: Local
+; BIND:      Name: __wrap_bar
+; BIND-NEXT: Value:
+; BIND-NEXT: Size:
+; BIND-NEXT: Binding: Local
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+declare void @__real_bar()
+
+define void @foo() {
+  call void @bar()
+  call void @__real_bar()
+  ret void
+}




More information about the llvm-commits mailing list