[lld] r352554 - [WebAssembly] Don't load weak undefined symbols from archive files

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 29 14:26:31 PST 2019


Author: sbc
Date: Tue Jan 29 14:26:31 2019
New Revision: 352554

URL: http://llvm.org/viewvc/llvm-project?rev=352554&view=rev
Log:
[WebAssembly] Don't load weak undefined symbols from archive files

Summary: Fixes PR40494

Subscribers: dschuff, jgravelle-google, aheejin, sunfish, llvm-commits

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

Added:
    lld/trunk/test/wasm/archive-weak-undefined.ll
Modified:
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/SymbolTable.cpp
    lld/trunk/wasm/Symbols.h

Added: lld/trunk/test/wasm/archive-weak-undefined.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/archive-weak-undefined.ll?rev=352554&view=auto
==============================================================================
--- lld/trunk/test/wasm/archive-weak-undefined.ll (added)
+++ lld/trunk/test/wasm/archive-weak-undefined.ll Tue Jan 29 14:26:31 2019
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: llc -filetype=obj %S/Inputs/ret32.ll -o %t.a1.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t.a1.o
+; RUN: wasm-ld %t.o %t.a -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+declare extern_weak i32 @ret32()
+
+define void @_start() {
+entry:
+  %call1 = call i32 @ret32()
+  ret void
+}
+
+; CHECK: Name: undefined function ret32
+; CHECK-NOT: Name: ret32

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=352554&r1=352553&r2=352554&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Tue Jan 29 14:26:31 2019
@@ -297,22 +297,31 @@ static const uint8_t UnreachableFn[] = {
 // the call instruction that passes Wasm validation.
 static void handleWeakUndefines() {
   for (Symbol *Sym : Symtab->getSymbols()) {
-    if (!Sym->isUndefined() || !Sym->isWeak())
+    if (!Sym->isUndefWeak())
       continue;
-    auto *FuncSym = dyn_cast<FunctionSymbol>(Sym);
-    if (!FuncSym)
+
+    const WasmSignature *Sig = nullptr;
+
+    if (auto *FuncSym = dyn_cast<FunctionSymbol>(Sym)) {
+      // It is possible for undefined functions not to have a signature (eg. if
+      // added via "--undefined"), but weak undefined ones do have a signature.
+      assert(FuncSym->Signature);
+      Sig = FuncSym->Signature;
+    } else if (auto *LazySym = dyn_cast<LazySymbol>(Sym)) {
+      // Lazy symbols may not be functions and therefore can have a null
+      // signature.
+      Sig = LazySym->Signature;
+    }
+
+    if (!Sig)
       continue;
 
-    // It is possible for undefined functions not to have a signature (eg. if
-    // added via "--undefined"), but weak undefined ones do have a signature.
-    assert(FuncSym->Signature);
-    const WasmSignature &Sig = *FuncSym->Signature;
 
     // Add a synthetic dummy for weak undefined functions.  These dummies will
     // be GC'd if not used as the target of any "call" instructions.
     std::string SymName = toString(*Sym);
     StringRef DebugName = Saver.save("undefined function " + SymName);
-    auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
+    auto *Func = make<SyntheticFunction>(*Sig, Sym->getName(), DebugName);
     Func->setBody(UnreachableFn);
     // Ensure it compares equal to the null pointer, and so that table relocs
     // don't pull in the stub body (only call-operand relocs should do that).

Modified: lld/trunk/wasm/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=352554&r1=352553&r2=352554&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.cpp (original)
+++ lld/trunk/wasm/SymbolTable.cpp Tue Jan 29 14:26:31 2019
@@ -241,10 +241,12 @@ Symbol *SymbolTable::addDefinedFunction(
 
   if (shouldReplace(S, File, Flags)) {
     // If the new defined function doesn't have signture (i.e. bitcode
-    // functions) but the old symbols does then preserve the old signature
+    // functions) but the old symbol does then preserve the old signature
     const WasmSignature *OldSig = nullptr;
     if (auto* F = dyn_cast<FunctionSymbol>(S))
       OldSig = F->Signature;
+    if (auto *L = dyn_cast<LazySymbol>(S))
+      OldSig = L->Signature;
     auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
     if (!NewSym->Signature)
       NewSym->Signature = OldSig;
@@ -377,15 +379,31 @@ void SymbolTable::addLazy(ArchiveFile *F
   std::tie(S, WasInserted) = insert(Name, nullptr);
 
   if (WasInserted) {
-    replaceSymbol<LazySymbol>(S, Name, File, *Sym);
+    replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
     return;
   }
 
-  // If there is an existing undefined symbol, load a new one from the archive.
-  if (S->isUndefined()) {
-    LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
-    File->addMember(Sym);
+  if (!S->isUndefined())
+    return;
+
+  // The existing symbol is undefined, load a new one from the archive,
+  // unless the the existing symbol is weak in which case replace the undefined
+  // symbols with a LazySymbol.
+  if (S->isWeak()) {
+    const WasmSignature *OldSig = nullptr;
+    // In the case of an UndefinedFunction we need to preserve the expected
+    // signature.
+    if (auto *F = dyn_cast<UndefinedFunction>(S))
+      OldSig = F->Signature;
+    LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
+    auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
+                                            File, *Sym);
+    NewSym->Signature = OldSig;
+    return;
   }
+
+  LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
+  File->addMember(Sym);
 }
 
 bool SymbolTable::addComdat(StringRef Name) {

Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=352554&r1=352553&r2=352554&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Tue Jan 29 14:26:31 2019
@@ -63,6 +63,13 @@ public:
   bool isWeak() const;
   bool isHidden() const;
 
+  // True if this is an undefined weak symbol. This only works once
+  // all input files have been added.
+  bool isUndefWeak() const {
+    // See comment on lazy symbols for details.
+    return isWeak() && (isUndefined() || isLazy());
+  }
+
   // Returns the symbol name.
   StringRef getName() const { return Name; }
 
@@ -313,15 +320,31 @@ public:
   InputEvent *Event;
 };
 
+// LazySymbol represents a symbol that is not yet in the link, but we know where
+// to find it if needed. If the resolver finds both Undefined and Lazy for the
+// same name, it will ask the Lazy to load a file.
+//
+// A special complication is the handling of weak undefined symbols. They should
+// not load a file, but we have to remember we have seen both the weak undefined
+// and the lazy. We represent that with a lazy symbol with a weak binding. This
+// means that code looking for undefined symbols normally also has to take lazy
+// symbols into consideration.
 class LazySymbol : public Symbol {
 public:
-  LazySymbol(StringRef Name, InputFile *File,
+  LazySymbol(StringRef Name, uint32_t Flags, InputFile *File,
              const llvm::object::Archive::Symbol &Sym)
-      : Symbol(Name, LazyKind, 0, File), ArchiveSymbol(Sym) {}
+      : Symbol(Name, LazyKind, Flags, File), ArchiveSymbol(Sym) {}
 
   static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
   void fetch();
 
+  // Lazy symbols can have a signature because they can replace an
+  // UndefinedFunction which which case we need to be able to preserve the
+  // signture.
+  // TODO(sbc): This repetition of the signature field is inelegant.  Revisit
+  // the use of class hierarchy to represent symbol taxonomy.
+  const WasmSignature *Signature = nullptr;
+
 private:
   llvm::object::Archive::Symbol ArchiveSymbol;
 };




More information about the llvm-commits mailing list