[lld] r361639 - [WebAssebmly] Add support for --wrap

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri May 24 07:14:25 PDT 2019


Author: sbc
Date: Fri May 24 07:14:25 2019
New Revision: 361639

URL: http://llvm.org/viewvc/llvm-project?rev=361639&view=rev
Log:
[WebAssebmly] Add support for --wrap

The code for implementing this features is taken almost verbatim
from the ELF backend.

Fixes: https://bugs.llvm.org/show_bug.cgi?id=41681

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

Added:
    lld/trunk/test/wasm/wrap.ll
Modified:
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/include/lld/Common/LLVM.h
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/InputFiles.h
    lld/trunk/wasm/LTO.cpp
    lld/trunk/wasm/Options.td
    lld/trunk/wasm/SymbolTable.cpp
    lld/trunk/wasm/SymbolTable.h
    lld/trunk/wasm/Symbols.h

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Fri May 24 07:14:25 2019
@@ -1522,7 +1522,7 @@ static void wrapSymbols(ArrayRef<Wrapped
 
   // Update pointers in input files.
   parallelForEach(ObjectFiles, [&](InputFile *File) {
-    std::vector<Symbol *> &Syms = File->getMutableSymbols();
+    MutableArrayRef<Symbol *> Syms = File->getMutableSymbols();
     for (size_t I = 0, E = Syms.size(); I != E; ++I)
       if (Symbol *S = Map.lookup(Syms[I]))
         Syms[I] = S;

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri May 24 07:14:25 2019
@@ -90,7 +90,7 @@ public:
   // function on files of other types.
   ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }
 
-  std::vector<Symbol *> &getMutableSymbols() {
+  MutableArrayRef<Symbol *> getMutableSymbols() {
     assert(FileKind == BinaryKind || FileKind == ObjKind ||
            FileKind == BitcodeKind);
     return Symbols;

Modified: lld/trunk/include/lld/Common/LLVM.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Common/LLVM.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/include/lld/Common/LLVM.h (original)
+++ lld/trunk/include/lld/Common/LLVM.h Fri May 24 07:14:25 2019
@@ -29,6 +29,7 @@ class Twine;
 class MemoryBuffer;
 class MemoryBufferRef;
 template <typename T> class ArrayRef;
+template <typename T> class MutableArrayRef;
 template <unsigned InternalLen> class SmallString;
 template <typename T, unsigned N> class SmallVector;
 template <typename T> class ErrorOr;
@@ -62,6 +63,7 @@ using llvm::isa;
 
 // ADT's.
 using llvm::ArrayRef;
+using llvm::MutableArrayRef;
 using llvm::Error;
 using llvm::ErrorOr;
 using llvm::Expected;

Added: lld/trunk/test/wasm/wrap.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/wrap.ll?rev=361639&view=auto
==============================================================================
--- lld/trunk/test/wasm/wrap.ll (added)
+++ lld/trunk/test/wasm/wrap.ll Fri May 24 07:14:25 2019
@@ -0,0 +1,40 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: wasm-ld -wrap nosuchsym -wrap foo -o %t.wasm %t.o
+; RUN: wasm-ld -emit-relocs -wrap foo -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define i32 @foo() {
+  ret i32 1
+}
+
+define void @_start() {
+entry:
+  call i32 @foo()
+  ret void
+}
+
+declare i32 @__real_foo()
+
+define i32 @__wrap_foo() {
+  %rtn = call i32 @__real_foo()
+  ret i32 %rtn
+}
+
+; CHECK:      - Type:            CODE
+; CHECK-NEXT:   Relocations:     
+; CHECK-NEXT:     - Type:            R_WASM_FUNCTION_INDEX_LEB
+; CHECK-NEXT:       Index:           2
+; CHECK-NEXT:       Offset:          0x00000009
+; CHECK-NEXT:     - Type:            R_WASM_FUNCTION_INDEX_LEB
+; CHECK-NEXT:       Index:           0
+; CHECK-NEXT:       Offset:          0x00000013
+
+; CHECK:        FunctionNames:
+; CHECK-NEXT:      - Index:           0
+; CHECK-NEXT:        Name:            foo
+; CHECK-NEXT:      - Index:           1
+; CHECK-NEXT:        Name:            _start
+; CHECK-NEXT:      - Index:           2
+; CHECK-NEXT:        Name:            __wrap_foo

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Fri May 24 07:14:25 2019
@@ -535,6 +535,84 @@ static std::string createResponseFile(co
   return Data.str();
 }
 
+// The --wrap option is a feature to rename symbols so that you can write
+// wrappers for existing functions. If you pass `-wrap=foo`, all
+// occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
+// expected to write `wrap_foo` function as a wrapper). The original
+// symbol becomes accessible as `real_foo`, so you can call that from your
+// wrapper.
+//
+// This data structure is instantiated for each -wrap option.
+struct WrappedSymbol {
+  Symbol *Sym;
+  Symbol *Real;
+  Symbol *Wrap;
+};
+
+static Symbol *addUndefined(StringRef Name) {
+  return Symtab->addUndefinedFunction(Name, "", "", 0, nullptr, nullptr);
+}
+
+// Handles -wrap option.
+//
+// This function instantiates wrapper symbols. At this point, they seem
+// like they are not being used at all, so we explicitly set some flags so
+// that LTO won't eliminate them.
+static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) {
+  std::vector<WrappedSymbol> V;
+  DenseSet<StringRef> Seen;
+
+  for (auto *Arg : Args.filtered(OPT_wrap)) {
+    StringRef Name = Arg->getValue();
+    if (!Seen.insert(Name).second)
+      continue;
+
+    Symbol *Sym = Symtab->find(Name);
+    if (!Sym)
+      continue;
+
+    Symbol *Real = addUndefined(Saver.save("__real_" + Name));
+    Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
+    V.push_back({Sym, Real, Wrap});
+
+    // We want to tell LTO not to inline symbols to be overwritten
+    // because LTO doesn't know the final symbol contents after renaming.
+    Real->CanInline = false;
+    Sym->CanInline = false;
+
+    // Tell LTO not to eliminate these symbols.
+    Sym->IsUsedInRegularObj = true;
+    Wrap->IsUsedInRegularObj = true;
+    Real->IsUsedInRegularObj = false;
+  }
+  return V;
+}
+
+// Do renaming for -wrap by updating pointers to symbols.
+//
+// When this function is executed, only InputFiles and symbol table
+// contain pointers to symbol objects. We visit them to replace pointers,
+// so that wrapped symbols are swapped as instructed by the command line.
+static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
+  DenseMap<Symbol *, Symbol *> Map;
+  for (const WrappedSymbol &W : Wrapped) {
+    Map[W.Sym] = W.Wrap;
+    Map[W.Real] = W.Sym;
+  }
+
+  // Update pointers in input files.
+  parallelForEach(Symtab->ObjectFiles, [&](InputFile *File) {
+    MutableArrayRef<Symbol *> Syms = File->getMutableSymbols();
+    for (size_t I = 0, E = Syms.size(); I != E; ++I)
+      if (Symbol *S = Map.lookup(Syms[I]))
+        Syms[I] = S;
+  });
+
+  // Update pointers in the symbol table.
+  for (const WrappedSymbol &W : Wrapped)
+    Symtab->wrap(W.Sym, W.Real, W.Wrap);
+}
+
 void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
   WasmOptTable Parser;
   opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@@ -628,6 +706,9 @@ void LinkerDriver::link(ArrayRef<const c
   for (auto *Arg : Args.filtered(OPT_export))
     handleUndefined(Arg->getValue());
 
+  // Create wrapped symbols for -wrap option.
+  std::vector<WrappedSymbol> Wrapped = addWrappedSymbols(Args);
+
   // Do link-time optimization if given files are LLVM bitcode files.
   // This compiles bitcode files into real object files.
   Symtab->addCombinedLTOObject();
@@ -640,6 +721,10 @@ void LinkerDriver::link(ArrayRef<const c
   if (errorCount())
     return;
 
+  // Apply symbol renames for -wrap.
+  if (!Wrapped.empty())
+    wrapSymbols(Wrapped);
+
   for (auto *Arg : Args.filtered(OPT_export)) {
     Symbol *Sym = Symtab->find(Arg->getValue());
     if (Sym && Sym->isDefined())

Modified: lld/trunk/wasm/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/InputFiles.h (original)
+++ lld/trunk/wasm/InputFiles.h Fri May 24 07:14:25 2019
@@ -61,6 +61,8 @@ public:
 
   ArrayRef<Symbol *> getSymbols() const { return Symbols; }
 
+  MutableArrayRef<Symbol *> getMutableSymbols() { return Symbols; }
+
 protected:
   InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
   MemoryBufferRef MB;

Modified: lld/trunk/wasm/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/LTO.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/LTO.cpp (original)
+++ lld/trunk/wasm/LTO.cpp Fri May 24 07:14:25 2019
@@ -108,6 +108,11 @@ void BitcodeCompiler::add(BitcodeFile &F
                             (R.Prevailing && Sym->isExported());
     if (R.Prevailing)
       undefine(Sym);
+
+    // We tell LTO to not apply interprocedural optimization for wrapped
+    // (with --wrap) symbols because otherwise LTO would inline them while
+    // their values are still not final.
+    R.LinkerRedefined = !Sym->CanInline;
   }
   checkError(LTOObj->add(std::move(F.Obj), Resols));
 }

Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Fri May 24 07:14:25 2019
@@ -112,6 +112,9 @@ def version: F<"version">, HelpText<"Dis
 def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
   HelpText<"Linker option extensions">;
 
+defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
+  MetaVarName<"<symbol>=<symbol>">;
+
 // The follow flags are unique to wasm
 
 def allow_undefined: F<"allow-undefined">,

Modified: lld/trunk/wasm/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.cpp (original)
+++ lld/trunk/wasm/SymbolTable.cpp Fri May 24 07:14:25 2019
@@ -65,7 +65,8 @@ void SymbolTable::addCombinedLTOObject()
 }
 
 void SymbolTable::reportRemainingUndefines() {
-  for (Symbol *Sym : SymVector) {
+  for (const auto& Pair : SymMap) {
+    const Symbol *Sym = SymVector[Pair.second];
     if (!Sym->isUndefined() || Sym->isWeak())
       continue;
     if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
@@ -104,6 +105,7 @@ std::pair<Symbol *, bool> SymbolTable::i
 
   Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
   Sym->IsUsedInRegularObj = false;
+  Sym->CanInline = true;
   Sym->Traced = Trace;
   SymVector.emplace_back(Sym);
   return {Sym, true};
@@ -539,6 +541,19 @@ void SymbolTable::trace(StringRef Name)
   SymMap.insert({CachedHashStringRef(Name), -1});
 }
 
+void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) {
+  // Swap symbols as instructed by -wrap.
+  int &OrigIdx = SymMap[CachedHashStringRef(Sym->getName())];
+  int &RealIdx= SymMap[CachedHashStringRef(Real->getName())];
+  int &WrapIdx = SymMap[CachedHashStringRef(Wrap->getName())];
+  LLVM_DEBUG(dbgs() << "wrap: " << Sym->getName() << "\n");
+
+  // Anyone looking up __real symbols should get the original
+  RealIdx = OrigIdx;
+  // Anyone looking up the original should get the __wrap symbol
+  OrigIdx = WrapIdx;
+}
+
 static const uint8_t UnreachableFn[] = {
     0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
     0x00 /* opcode unreachable */, 0x0b /* opcode end */

Modified: lld/trunk/wasm/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.h (original)
+++ lld/trunk/wasm/SymbolTable.h Fri May 24 07:14:25 2019
@@ -35,14 +35,11 @@ class InputSegment;
 // There is one add* function per symbol type.
 class SymbolTable {
 public:
+  void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap);
+
   void addFile(InputFile *File);
-  void addCombinedLTOObject();
 
-  std::vector<ObjFile *> ObjectFiles;
-  std::vector<SharedFile *> SharedFiles;
-  std::vector<BitcodeFile *> BitcodeFiles;
-  std::vector<InputFunction *> SyntheticFunctions;
-  std::vector<InputGlobal *> SyntheticGlobals;
+  void addCombinedLTOObject();
 
   void reportRemainingUndefines();
 
@@ -87,6 +84,12 @@ public:
   void handleSymbolVariants();
   void handleWeakUndefines();
 
+  std::vector<ObjFile *> ObjectFiles;
+  std::vector<SharedFile *> SharedFiles;
+  std::vector<BitcodeFile *> BitcodeFiles;
+  std::vector<InputFunction *> SyntheticFunctions;
+  std::vector<InputGlobal *> SyntheticGlobals;
+
 private:
   std::pair<Symbol *, bool> insert(StringRef Name, const InputFile *File);
   std::pair<Symbol *, bool> insertName(StringRef Name);

Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=361639&r1=361638&r2=361639&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Fri May 24 07:14:25 2019
@@ -114,6 +114,11 @@ public:
   // command line flag)
   unsigned ForceExport : 1;
 
+  // False if LTO shouldn't inline whatever this symbol points to. If a symbol
+  // is overwritten after LTO, LTO shouldn't inline the symbol because it
+  // doesn't know the final contents of the symbol.
+  unsigned CanInline : 1;
+
   // True if this symbol is specified by --trace-symbol option.
   unsigned Traced : 1;
 
@@ -131,8 +136,8 @@ public:
 
 protected:
   Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
-      : IsUsedInRegularObj(false), ForceExport(false), Traced(false),
-        Name(Name), SymbolKind(K), Flags(Flags), File(F),
+      : IsUsedInRegularObj(false), ForceExport(false), CanInline(false),
+        Traced(false), Name(Name), SymbolKind(K), Flags(Flags), File(F),
         Referenced(!Config->GcSections) {}
 
   StringRef Name;
@@ -474,6 +479,7 @@ T *replaceSymbol(Symbol *S, ArgT &&... A
   T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
   S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
   S2->ForceExport = SymCopy.ForceExport;
+  S2->CanInline = SymCopy.CanInline;
   S2->Traced = SymCopy.Traced;
 
   // Print out a log message if --trace-symbol was specified.




More information about the llvm-commits mailing list