[lld] b0f18af - [lld][WebAssemby] Demote LazySymbols back to undefined symbols if they are not loaded

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 29 14:05:29 PDT 2022


Author: Sam Clegg
Date: 2022-07-29T13:53:54-07:00
New Revision: b0f18af30ba71382feda64fe523baac151d9a43f

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

LOG: [lld][WebAssemby] Demote LazySymbols back to undefined symbols if they are not loaded

A LazySymbol is one that lives in `.a` archive and gets pulled in by a
strong reference.  However, weak references to such symbols do not
result in them be loaded from the archive.  In this case we want to
treat such symbols at undefined rather then lazy, once symbols
resolution is complete.

This fixes a crash bug in the linker when weakly referenced symbol that
lives in an archive file is live at the end of the link.  In the case of
dynamic linking this is expected to turn into an import with (in the
case of a function symbol) a function index.

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

Added: 
    

Modified: 
    lld/test/wasm/shared-weak-undefined.s
    lld/wasm/Driver.cpp
    lld/wasm/SymbolTable.cpp
    lld/wasm/Symbols.h

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/shared-weak-undefined.s b/lld/test/wasm/shared-weak-undefined.s
index 5560ccecb807d..cb3e29b5a9b7b 100644
--- a/lld/test/wasm/shared-weak-undefined.s
+++ b/lld/test/wasm/shared-weak-undefined.s
@@ -3,11 +3,24 @@
 # RUN: obj2yaml %t.wasm | FileCheck %s
 # RUN: llvm-objdump -d %t.wasm | FileCheck %s -check-prefix=ASM
 
+# Run the same test but include a definition of ret32 in a library file.
+# This verifies that LazySymbols (those found in library archives) are correctly
+# demoted to undefined symbols in the final link when they are only weakly
+# referenced.
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.ret32.o %p/Inputs/ret32.s
+# RUN: rm -f %T/libret32.a
+# RUN: llvm-ar cru %T/libret32.a %t.ret32.o
+# RUN: wasm-ld --experimental-pic -shared -o %t.ret32.wasm %t.o %T/libret32.a
+# RUN: obj2yaml %t.wasm | FileCheck %s
+# RUN: llvm-objdump -d %t.wasm | FileCheck %s -check-prefix=ASM
+
 # Verify the weak undefined symbols are marked as such in the
 # dylink section.
 
 .weak weak_func
 .functype weak_func () -> (i32)
+.weak ret32
+.functype ret32 (f32) -> (i32)
 
 .globl call_weak
 call_weak:
@@ -18,6 +31,19 @@ call_weak:
   end_function
 # ASM-NEXT:      0b                     end
 
+# This function is defined in library archive, but since our reference to it
+# is weak we don't expect this definition to be used.  Instead we expect it to
+# act like an undefined reference and result in an imported function.
+.globl call_weak_libfunc
+call_weak_libfunc:
+# ASM: <call_weak_libfunc>:
+  .functype call_weak_libfunc () -> (i32)
+  f32.const 1.0
+  call ret32
+# ASM:           10 81 80 80 80 00 call 1
+  end_function
+# ASM-NEXT:      0b                     end
+
 #      CHECK: Sections:
 # CHECK-NEXT:   - Type:            CUSTOM
 # CHECK-NEXT:     Name:            dylink.0
@@ -30,3 +56,6 @@ call_weak:
 # CHECK-NEXT:       - Module:          env
 # CHECK-NEXT:         Field:           weak_func
 # CHECK-NEXT:         Flags:           [ BINDING_WEAK, UNDEFINED ]
+# CHECK-NEXT:       - Module:          env
+# CHECK-NEXT:         Field:           ret32
+# CHECK-NEXT:         Flags:           [ BINDING_WEAK, UNDEFINED ]

diff  --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 0a0f0c8a05bd7..99725095c8f41 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -570,6 +570,21 @@ static void handleLibcall(StringRef name) {
   }
 }
 
+// Equivalent of demote demoteSharedAndLazySymbols() in the ELF linker
+static void demoteLazySymbols() {
+  for (Symbol *sym : symtab->getSymbols()) {
+    if (auto* s = dyn_cast<LazySymbol>(sym)) {
+      if (s->signature) {
+        LLVM_DEBUG(llvm::dbgs()
+                   << "demoting lazy func: " << s->getName() << "\n");
+        replaceSymbol<UndefinedFunction>(s, s->getName(), None, None,
+                                         WASM_SYMBOL_BINDING_WEAK, s->getFile(),
+                                         s->signature);
+      }
+    }
+  }
+}
+
 static UndefinedGlobal *
 createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
   auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal(
@@ -1030,6 +1045,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   // collection.
   splitSections();
 
+  // Any remaining lazy symbols should be demoted to Undefined
+  demoteLazySymbols();
+
   // Do size optimizations: garbage collection
   markLive();
 

diff  --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 2969d99e3ab9a..db529312d1101 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -112,6 +112,7 @@ std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
   sym->canInline = true;
   sym->traced = trace;
   sym->forceExport = false;
+  sym->referenced = !config->gcSections;
   symVector.emplace_back(sym);
   return {sym, true};
 }

diff  --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index c17b720a90fae..d2a0cb0becc37 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -500,7 +500,7 @@ class LazySymbol : public Symbol {
   MemoryBufferRef getMemberBuffer();
 
   // Lazy symbols can have a signature because they can replace an
-  // UndefinedFunction which which case we need to be able to preserve the
+  // UndefinedFunction in which case we need to be able to preserve the
   // signature.
   // TODO(sbc): This repetition of the signature field is inelegant.  Revisit
   // the use of class hierarchy to represent symbol taxonomy.
@@ -649,6 +649,7 @@ T *replaceSymbol(Symbol *s, ArgT &&... arg) {
   s2->forceExport = symCopy.forceExport;
   s2->canInline = symCopy.canInline;
   s2->traced = symCopy.traced;
+  s2->referenced = symCopy.referenced;
 
   // Print out a log message if --trace-symbol was specified.
   // This is for debugging.


        


More information about the llvm-commits mailing list