[lld] 22c4f95 - [lld][WebAssembly] Improve merging multiple occurrences of an undefined symbol (#178550)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 29 09:27:27 PST 2026


Author: Sam Clegg
Date: 2026-01-29T09:27:22-08:00
New Revision: 22c4f9534a404680c798cbe22784fca6ebdd4dc4

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

LOG: [lld][WebAssembly] Improve merging multiple occurrences of an undefined symbol (#178550)

This change renames `setImportAttributes` to `updateExistingUndefined`
which better defines what it does. We also now call this function for
all different symbol types.

In addition we preserve the `NO_STRIP` symbol attribute if any undefined
reference is tagged as such.

This is partial fix for #174676, although there seems to be anther crash
that occurs after this issue is fixed.

Added: 
    lld/test/wasm/merge-undefined-symbols.s

Modified: 
    lld/wasm/SymbolTable.cpp

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/merge-undefined-symbols.s b/lld/test/wasm/merge-undefined-symbols.s
new file mode 100644
index 0000000000000..62856d6ed86a7
--- /dev/null
+++ b/lld/test/wasm/merge-undefined-symbols.s
@@ -0,0 +1,41 @@
+# Verify that the `no_strip` attribute on undefined symbols is preserved
+# as long as one of the undefined references is `no_strip`.
+# The indirect function table is created by the linker in the case that
+# the __indirect_function_table symbol is live (i.e. marked as no_strip).
+# This test verifies that the undefined symbol is NO_STRIP, even if the first
+# undefined reference is not NO_STRIP.
+#
+# RUN: split-file %s %t
+# RUN: llvm-mc -mattr=+reference-types -filetype=obj -triple=wasm32-unknown-unknown -o %t/main.o %t/main.s
+# RUN: llvm-mc -mattr=+reference-types -filetype=obj -triple=wasm32-unknown-unknown -o %t/other.o %t/other.s
+#
+# RUN: wasm-ld %t/main.o %t/other.o -o %t.wasm
+# RUN: obj2yaml %t.wasm | FileCheck %s
+#
+# RUN: wasm-ld %t/other.o %t/main.o -o %t2.wasm
+# RUN: obj2yaml %t2.wasm | FileCheck %s
+
+#--- main.s
+.globl __indirect_function_table
+.tabletype __indirect_function_table, funcref
+.no_dead_strip __indirect_function_table
+
+.globl _start
+_start:
+  .functype _start () -> ()
+  end_function
+
+#--- other.s
+# This file contains a reference to __indirect_function_table that is not
+# marked as `.no_dead_strip`.
+.globl __indirect_function_table
+.tabletype __indirect_function_table, funcref
+
+# CHECK:       - Type:            TABLE
+# CHECK-NEXT:    Tables:
+# CHECK-NEXT:      - Index:           0
+# CHECK-NEXT:        ElemType:        FUNCREF
+# CHECK-NEXT:        Limits:
+# CHECK-NEXT:          Flags:           [ HAS_MAX ]
+# CHECK-NEXT:          Minimum:         0x1
+# CHECK-NEXT:          Maximum:         0x1

diff  --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 5c811e0ff42a7..33a68b5defd72 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -582,11 +582,10 @@ Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags,
 // With LTO these attributes are not available when the bitcode is read and only
 // become available when the LTO object is read.  In this case we silently
 // replace the empty attributes with the valid ones.
-template <typename T>
-static void setImportAttributes(T *existing,
-                                std::optional<StringRef> importName,
-                                std::optional<StringRef> importModule,
-                                uint32_t flags, InputFile *file) {
+static void
+updateExistingUndefined(Symbol *existing, uint32_t flags, InputFile *file,
+                        std::optional<StringRef> importName = {},
+                        std::optional<StringRef> importModule = {}) {
   if (importName) {
     if (!existing->importName)
       existing->importName = importName;
@@ -612,6 +611,10 @@ static void setImportAttributes(T *existing,
   if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) {
     existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding;
   }
+
+  // Certain flags such as NO_STRIP should be maintianed if either old or
+  // new symbol is marked as such.
+  existing->flags |= flags & WASM_SYMBOL_NO_STRIP;
 }
 
 Symbol *SymbolTable::addUndefinedFunction(StringRef name,
@@ -675,12 +678,10 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name,
         replaceSym();
     }
     if (existingUndefined) {
-      setImportAttributes(existingUndefined, importName, importModule, flags,
-                          file);
+      updateExistingUndefined(existingUndefined, flags, file, importName,
+                              importModule);
       if (isCalledDirectly)
         existingUndefined->isCalledDirectly = true;
-      if (s->isWeak())
-        s->flags = flags;
     }
   }
 
@@ -707,8 +708,8 @@ Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
       lazy->extract();
   } else if (s->isDefined()) {
     checkDataType(s, file);
-  } else if (s->isWeak()) {
-    s->flags = flags;
+  } else {
+    updateExistingUndefined(s, flags, file);
   }
   return s;
 }
@@ -734,8 +735,8 @@ Symbol *SymbolTable::addUndefinedGlobal(StringRef name,
     lazy->extract();
   else if (s->isDefined())
     checkGlobalType(s, file, type);
-  else if (s->isWeak())
-    s->flags = flags;
+  else
+    updateExistingUndefined(s, flags, file);
   return s;
 }
 
@@ -760,8 +761,8 @@ Symbol *SymbolTable::addUndefinedTable(StringRef name,
     lazy->extract();
   else if (s->isDefined())
     checkTableType(s, file, type);
-  else if (s->isWeak())
-    s->flags = flags;
+  else
+    updateExistingUndefined(s, flags, file);
   return s;
 }
 
@@ -786,12 +787,13 @@ Symbol *SymbolTable::addUndefinedTag(StringRef name,
     lazy->extract();
   else if (s->isDefined())
     checkTagType(s, file, sig);
-  else if (s->isWeak())
-    s->flags = flags;
+  else
+    updateExistingUndefined(s, flags, file);
   return s;
 }
 
 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
+  LLVM_DEBUG(llvm::dbgs() << "createUndefinedIndirectFunctionTable\n");
   WasmLimits limits{0, 0, 0, 0}; // Set by the writer.
   WasmTableType *type = make<WasmTableType>();
   type->ElemType = ValType::FUNCREF;
@@ -806,6 +808,7 @@ TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
 }
 
 TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) {
+  LLVM_DEBUG(llvm::dbgs() << "createDefinedIndirectFunctionTable\n");
   const uint32_t invalidIndex = -1;
   WasmLimits limits{0, 0, 0, 0}; // Set by the writer.
   WasmTableType type{ValType::FUNCREF, limits};


        


More information about the llvm-commits mailing list