Skip to content

[wasm-ld] Refactor WasmSym from static globals to per-link context #134970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 25, 2025

Conversation

anutosh491
Copy link
Member

@anutosh491 anutosh491 commented Apr 9, 2025

Towards ##134809 (comment)

This change moves WasmSym from a static global struct to an instance owned by Ctx, allowing it to be reset cleanly between linker runs. This enables safe support for multiple invocations of wasm-ld within the same process

Changes done

  • Converted WasmSym from a static struct to a regular struct with instance members.

  • Added a std::unique_ptr wasmSym field inside Ctx.

  • Reset wasmSym in Ctx::reset() to clear state between links.

  • Replaced all WasmSym:: references with ctx.wasmSym->.

  • Removed global symbol definitions from Symbols.cpp that are no longer needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link invocation, preventing symbol leakage across runs—critical when using wasm-ld/lld as a reentrant library where global state can cause subtle, hard-to-debug errors.

@anutosh491
Copy link
Member Author

Use case as per #134809

While running clang-repl in the browser, we would have

  1. A main module (main.wasm) is loaded once at startup.

  2. The user compiles code snippets dynamically. Each snippet is compiled into a new side module (X.wasm) that is then dynamically linked into the main module.

  3. During the compilation of X.wasm, it may internally instantiate a helper module (Y.wasm) — for example, during interpreter initialization (e.g., Cpp::CreateInterpreter()).

  4. Each of these modules (X.wasm, Y.wasm, etc.) is produced by a separate invocation of wasm-ld, using similar command-line arguments and linker inputs but the processes are different

However, we encountered a state-leak problem in wasm-ld:

The WasmSym::initMemory symbol, once created in one link (e.g., for X.wasm), persists into subsequent linker runs (e.g., for Y.wasm) due to WasmSym being globally defined with static fields.

This causes inconsistencies such as createInitMemoryFunction() being triggered when hasPassiveInitializedSegments() is false — leading to crashes/assertions.

This surfaced as a misalignment between the actual linking context and the static WasmSym state, especially in scenarios where no segments required passive initialization, but initMemory was still marked live from a previous link.

@llvmbot
Copy link
Member

llvmbot commented Apr 9, 2025

@llvm/pr-subscribers-lld-wasm

@llvm/pr-subscribers-lld

Author: Anutosh Bhat (anutosh491)

Changes

Towards ##134809 (comment)

This change moves WasmSym from a static global struct to an instance owned by Ctx, allowing it to be reset cleanly between linker runs. This enables safe support for multiple invocations of wasm-ld within the same process


Patch is 41.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134970.diff

9 Files Affected:

  • (modified) lld/wasm/Config.h (+4)
  • (modified) lld/wasm/Driver.cpp (+32-30)
  • (modified) lld/wasm/InputChunks.cpp (+5-5)
  • (modified) lld/wasm/MarkLive.cpp (+3-3)
  • (modified) lld/wasm/OutputSections.cpp (+2-2)
  • (modified) lld/wasm/Symbols.cpp (-26)
  • (modified) lld/wasm/Symbols.h (+26-26)
  • (modified) lld/wasm/SyntheticSections.cpp (+14-14)
  • (modified) lld/wasm/Writer.cpp (+92-88)
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index ffc5b84ca38b0..ad94b2a1386dc 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -32,6 +32,7 @@ class InputTable;
 class InputGlobal;
 class InputFunction;
 class Symbol;
+struct WasmSym;
 
 // For --unresolved-symbols.
 enum class UnresolvedPolicy { ReportError, Warn, Ignore, ImportDynamic };
@@ -141,6 +142,9 @@ struct Ctx {
   llvm::SmallVector<InputGlobal *, 0> syntheticGlobals;
   llvm::SmallVector<InputTable *, 0> syntheticTables;
 
+  // Linker-generated symbols like __wasm_init_memory, __heap_base, etc.
+  std::unique_ptr<WasmSym> wasmSym;
+
   // True if we are creating position-independent code.
   bool isPic = false;
 
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index de976947474e1..b43632d5e420b 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -70,6 +70,8 @@ void Ctx::reset() {
   isPic = false;
   legacyFunctionTable = false;
   emitBssSegments = false;
+  wasmSym.reset();
+  wasmSym = std::make_unique<WasmSym>();
 }
 
 namespace {
@@ -945,14 +947,14 @@ static void createSyntheticSymbols() {
                                                             true};
   static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64,
                                                             true};
-  WasmSym::callCtors = symtab->addSyntheticFunction(
+  ctx.wasmSym->callCtors = symtab->addSyntheticFunction(
       "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
       make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
 
   bool is64 = ctx.arg.is64.value_or(false);
 
   if (ctx.isPic) {
-    WasmSym::stackPointer =
+    ctx.wasmSym->stackPointer =
         createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false)
                                                      ? &mutableGlobalTypeI64
                                                      : &mutableGlobalTypeI32);
@@ -962,21 +964,21 @@ static void createSyntheticSymbols() {
     // See:
     // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
     auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;
-    WasmSym::memoryBase = createUndefinedGlobal("__memory_base", globalType);
-    WasmSym::tableBase = createUndefinedGlobal("__table_base", globalType);
-    WasmSym::memoryBase->markLive();
-    WasmSym::tableBase->markLive();
+    ctx.wasmSym->memoryBase = createUndefinedGlobal("__memory_base", globalType);
+    ctx.wasmSym->tableBase = createUndefinedGlobal("__table_base", globalType);
+    ctx.wasmSym->memoryBase->markLive();
+    ctx.wasmSym->tableBase->markLive();
   } else {
     // For non-PIC code
-    WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true);
-    WasmSym::stackPointer->markLive();
+    ctx.wasmSym->stackPointer = createGlobalVariable("__stack_pointer", true);
+    ctx.wasmSym->stackPointer->markLive();
   }
 
   if (ctx.arg.sharedMemory) {
-    WasmSym::tlsBase = createGlobalVariable("__tls_base", true);
-    WasmSym::tlsSize = createGlobalVariable("__tls_size", false);
-    WasmSym::tlsAlign = createGlobalVariable("__tls_align", false);
-    WasmSym::initTLS = symtab->addSyntheticFunction(
+    ctx.wasmSym->tlsBase = createGlobalVariable("__tls_base", true);
+    ctx.wasmSym->tlsSize = createGlobalVariable("__tls_size", false);
+    ctx.wasmSym->tlsAlign = createGlobalVariable("__tls_align", false);
+    ctx.wasmSym->initTLS = symtab->addSyntheticFunction(
         "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,
         make<SyntheticFunction>(
             is64 ? i64ArgSignature : i32ArgSignature,
@@ -988,25 +990,25 @@ static void createOptionalSymbols() {
   if (ctx.arg.relocatable)
     return;
 
-  WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
+  ctx.wasmSym->dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
 
   if (!ctx.arg.shared)
-    WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end");
+    ctx.wasmSym->dataEnd = symtab->addOptionalDataSymbol("__data_end");
 
   if (!ctx.isPic) {
-    WasmSym::stackLow = symtab->addOptionalDataSymbol("__stack_low");
-    WasmSym::stackHigh = symtab->addOptionalDataSymbol("__stack_high");
-    WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base");
-    WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base");
-    WasmSym::heapEnd = symtab->addOptionalDataSymbol("__heap_end");
-    WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
-    WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base");
+    ctx.wasmSym->stackLow = symtab->addOptionalDataSymbol("__stack_low");
+    ctx.wasmSym->stackHigh = symtab->addOptionalDataSymbol("__stack_high");
+    ctx.wasmSym->globalBase = symtab->addOptionalDataSymbol("__global_base");
+    ctx.wasmSym->heapBase = symtab->addOptionalDataSymbol("__heap_base");
+    ctx.wasmSym->heapEnd = symtab->addOptionalDataSymbol("__heap_end");
+    ctx.wasmSym->definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
+    ctx.wasmSym->definedTableBase = symtab->addOptionalDataSymbol("__table_base");
   }
 
-  WasmSym::firstPageEnd =
+  ctx.wasmSym->firstPageEnd =
       symtab->addOptionalDataSymbol("__wasm_first_page_end");
-  if (WasmSym::firstPageEnd)
-    WasmSym::firstPageEnd->setVA(ctx.arg.pageSize);
+  if (ctx.wasmSym->firstPageEnd)
+    ctx.wasmSym->firstPageEnd->setVA(ctx.arg.pageSize);
 
   // For non-shared memory programs we still need to define __tls_base since we
   // allow object files built with TLS to be linked into single threaded
@@ -1018,7 +1020,7 @@ static void createOptionalSymbols() {
   // __tls_size and __tls_align are not needed in this case since they are only
   // needed for __wasm_init_tls (which we do not create in this case).
   if (!ctx.arg.sharedMemory)
-    WasmSym::tlsBase = createOptionalGlobal("__tls_base", false);
+    ctx.wasmSym->tlsBase = createOptionalGlobal("__tls_base", false);
 }
 
 static void processStubLibrariesPreLTO() {
@@ -1393,9 +1395,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   // by libc/etc., because destructors are registered dynamically with
   // `__cxa_atexit` and friends.
   if (!ctx.arg.relocatable && !ctx.arg.shared &&
-      !WasmSym::callCtors->isUsedInRegularObj &&
-      WasmSym::callCtors->getName() != ctx.arg.entry &&
-      !ctx.arg.exportedSymbols.count(WasmSym::callCtors->getName())) {
+      !ctx.wasmSym->callCtors->isUsedInRegularObj &&
+      ctx.wasmSym->callCtors->getName() != ctx.arg.entry &&
+      !ctx.arg.exportedSymbols.count(ctx.wasmSym->callCtors->getName())) {
     if (Symbol *callDtors =
             handleUndefined("__wasm_call_dtors", "<internal>")) {
       if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) {
@@ -1404,7 +1406,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
              !callDtorsFunc->signature->Returns.empty())) {
           error("__wasm_call_dtors must have no argument or return values");
         }
-        WasmSym::callDtors = callDtorsFunc;
+        ctx.wasmSym->callDtors = callDtorsFunc;
       } else {
         error("__wasm_call_dtors must be a function");
       }
@@ -1497,7 +1499,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   markLive();
 
   // Provide the indirect function table if needed.
-  WasmSym::indirectFunctionTable =
+  ctx.wasmSym->indirectFunctionTable =
       symtab->resolveIndirectFunctionTable(/*required =*/false);
 
   if (errorCount())
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index 3668697382238..ac89f313ca4b5 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -411,9 +411,9 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
     if (ctx.isPic) {
       writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
       if (isTLS())
-        writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "tls_base");
+        writeUleb128(os, ctx.wasmSym->tlsBase->getGlobalIndex(), "tls_base");
       else
-        writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
+        writeUleb128(os, ctx.wasmSym->memoryBase->getGlobalIndex(), "memory_base");
       writeU8(os, opcode_ptr_add, "ADD");
     }
 
@@ -436,12 +436,12 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
       }
     } else {
       assert(ctx.isPic);
-      const GlobalSymbol* baseSymbol = WasmSym::memoryBase;
+      const GlobalSymbol* baseSymbol = ctx.wasmSym->memoryBase;
       if (rel.Type == R_WASM_TABLE_INDEX_I32 ||
           rel.Type == R_WASM_TABLE_INDEX_I64)
-        baseSymbol = WasmSym::tableBase;
+        baseSymbol = ctx.wasmSym->tableBase;
       else if (sym->isTLS())
-        baseSymbol = WasmSym::tlsBase;
+        baseSymbol = ctx.wasmSym->tlsBase;
       writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
       writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
       writeU8(os, opcode_reloc_const, "CONST");
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index 13c7a3d894fe3..40b105821056d 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -114,8 +114,8 @@ void MarkLive::run() {
     if (sym->isNoStrip() || sym->isExported())
       enqueue(sym);
 
-  if (WasmSym::callDtors)
-    enqueue(WasmSym::callDtors);
+  if (ctx.wasmSym->callDtors)
+    enqueue(ctx.wasmSym->callDtors);
 
   for (const ObjFile *obj : ctx.objectFiles)
     if (obj->isLive()) {
@@ -131,7 +131,7 @@ void MarkLive::run() {
   // If we have any non-discarded init functions, mark `__wasm_call_ctors` as
   // live so that we assign it an index and call it.
   if (isCallCtorsLive())
-    WasmSym::callCtors->markLive();
+    ctx.wasmSym->callCtors->markLive();
 }
 
 void MarkLive::mark() {
diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp
index 5038cd8ea965b..1864e4532fc36 100644
--- a/lld/wasm/OutputSections.cpp
+++ b/lld/wasm/OutputSections.cpp
@@ -124,7 +124,7 @@ void DataSection::finalizeContents() {
     if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
       if (ctx.isPic && ctx.arg.extendedConst) {
         writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get");
-        writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
+        writeUleb128(os, ctx.wasmSym->memoryBase->getGlobalIndex(),
                      "literal (global index)");
         if (segment->startVA) {
           writePtrConst(os, segment->startVA, is64, "offset");
@@ -137,7 +137,7 @@ void DataSection::finalizeContents() {
         if (ctx.isPic) {
           assert(segment->startVA == 0);
           initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
-          initExpr.Inst.Value.Global = WasmSym::memoryBase->getGlobalIndex();
+          initExpr.Inst.Value.Global = ctx.wasmSym->memoryBase->getGlobalIndex();
         } else {
           initExpr = intConst(segment->startVA, is64);
         }
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index af5ecf4f38f73..f2040441e6257 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -77,32 +77,6 @@ std::string toString(wasm::Symbol::Kind kind) {
 }
 
 namespace wasm {
-DefinedFunction *WasmSym::callCtors;
-DefinedFunction *WasmSym::callDtors;
-DefinedFunction *WasmSym::initMemory;
-DefinedFunction *WasmSym::applyGlobalRelocs;
-DefinedFunction *WasmSym::applyTLSRelocs;
-DefinedFunction *WasmSym::applyGlobalTLSRelocs;
-DefinedFunction *WasmSym::initTLS;
-DefinedData *WasmSym::firstPageEnd;
-DefinedFunction *WasmSym::startFunction;
-DefinedData *WasmSym::dsoHandle;
-DefinedData *WasmSym::dataEnd;
-DefinedData *WasmSym::globalBase;
-DefinedData *WasmSym::heapBase;
-DefinedData *WasmSym::heapEnd;
-DefinedData *WasmSym::initMemoryFlag;
-GlobalSymbol *WasmSym::stackPointer;
-DefinedData *WasmSym::stackLow;
-DefinedData *WasmSym::stackHigh;
-GlobalSymbol *WasmSym::tlsBase;
-GlobalSymbol *WasmSym::tlsSize;
-GlobalSymbol *WasmSym::tlsAlign;
-UndefinedGlobal *WasmSym::tableBase;
-DefinedData *WasmSym::definedTableBase;
-UndefinedGlobal *WasmSym::memoryBase;
-DefinedData *WasmSym::definedMemoryBase;
-TableSymbol *WasmSym::indirectFunctionTable;
 
 WasmSymbolType Symbol::getWasmType() const {
   if (isa<FunctionSymbol>(this))
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 03a74da7230d0..4197fc7a17b14 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -541,32 +541,32 @@ class LazySymbol : public Symbol {
 struct WasmSym {
   // __global_base
   // Symbol marking the start of the global section.
-  static DefinedData *globalBase;
+  DefinedData *globalBase = nullptr;
 
   // __stack_pointer/__stack_low/__stack_high
   // Global that holds current value of stack pointer and data symbols marking
   // the start and end of the stack region.  stackPointer is initialized to
   // stackHigh and grows downwards towards stackLow
-  static GlobalSymbol *stackPointer;
-  static DefinedData *stackLow;
-  static DefinedData *stackHigh;
+  GlobalSymbol *stackPointer = nullptr;
+  DefinedData *stackLow = nullptr;
+  DefinedData *stackHigh = nullptr;
 
   // __tls_base
   // Global that holds the address of the base of the current thread's
   // TLS block.
-  static GlobalSymbol *tlsBase;
+  GlobalSymbol *tlsBase = nullptr;
 
   // __tls_size
   // Symbol whose value is the size of the TLS block.
-  static GlobalSymbol *tlsSize;
+  GlobalSymbol *tlsSize = nullptr;
 
   // __tls_size
   // Symbol whose value is the alignment of the TLS block.
-  static GlobalSymbol *tlsAlign;
+  GlobalSymbol *tlsAlign = nullptr;
 
   // __data_end
   // Symbol marking the end of the data and bss.
-  static DefinedData *dataEnd;
+  DefinedData *dataEnd = nullptr;
 
   // __heap_base/__heap_end
   // Symbols marking the beginning and end of the "heap". It starts at the end
@@ -574,70 +574,70 @@ struct WasmSym {
   // memory allocated by wasm-ld. This region of memory is not used by the
   // linked code, so it may be used as a backing store for `sbrk` or `malloc`
   // implementations.
-  static DefinedData *heapBase;
-  static DefinedData *heapEnd;
+  DefinedData *heapBase = nullptr;
+  DefinedData *heapEnd = nullptr;
 
   // __wasm_first_page_end
   // A symbol whose address is the end of the first page in memory (if any).
-  static DefinedData *firstPageEnd;
+  DefinedData *firstPageEnd = nullptr;
 
   // __wasm_init_memory_flag
   // Symbol whose contents are nonzero iff memory has already been initialized.
-  static DefinedData *initMemoryFlag;
+  DefinedData *initMemoryFlag = nullptr;
 
   // __wasm_init_memory
   // Function that initializes passive data segments during instantiation.
-  static DefinedFunction *initMemory;
+  DefinedFunction *initMemory = nullptr;
 
   // __wasm_call_ctors
   // Function that directly calls all ctors in priority order.
-  static DefinedFunction *callCtors;
+  DefinedFunction *callCtors = nullptr;
 
   // __wasm_call_dtors
   // Function that calls the libc/etc. cleanup function.
-  static DefinedFunction *callDtors;
+  DefinedFunction *callDtors = nullptr;
 
   // __wasm_apply_global_relocs
   // Function that applies relocations to wasm globals post-instantiation.
   // Unlike __wasm_apply_data_relocs this needs to run on every thread.
-  static DefinedFunction *applyGlobalRelocs;
+  DefinedFunction *applyGlobalRelocs = nullptr;
 
   // __wasm_apply_tls_relocs
   // Like __wasm_apply_data_relocs but for TLS section.  These must be
   // delayed until __wasm_init_tls.
-  static DefinedFunction *applyTLSRelocs;
+  DefinedFunction *applyTLSRelocs = nullptr;
 
   // __wasm_apply_global_tls_relocs
   // Like applyGlobalRelocs but for globals that hold TLS addresses.  These
   // must be delayed until __wasm_init_tls.
-  static DefinedFunction *applyGlobalTLSRelocs;
+  DefinedFunction *applyGlobalTLSRelocs = nullptr;
 
   // __wasm_init_tls
   // Function that allocates thread-local storage and initializes it.
-  static DefinedFunction *initTLS;
+  DefinedFunction *initTLS = nullptr;
 
   // Pointer to the function that is to be used in the start section.
   // (normally an alias of initMemory, or applyGlobalRelocs).
-  static DefinedFunction *startFunction;
+  DefinedFunction *startFunction = nullptr;
 
   // __dso_handle
   // Symbol used in calls to __cxa_atexit to determine current DLL
-  static DefinedData *dsoHandle;
+  DefinedData *dsoHandle = nullptr;
 
   // __table_base
   // Used in PIC code for offset of indirect function table
-  static UndefinedGlobal *tableBase;
-  static DefinedData *definedTableBase;
+  UndefinedGlobal *tableBase = nullptr;
+  DefinedData *definedTableBase = nullptr;
 
   // __memory_base
   // Used in PIC code for offset of global data
-  static UndefinedGlobal *memoryBase;
-  static DefinedData *definedMemoryBase;
+  UndefinedGlobal *memoryBase = nullptr;
+  DefinedData *definedMemoryBase = nullptr;
 
   // __indirect_function_table
   // Used as an address space for function pointers, with each function that is
   // used as a function pointer being allocated a slot.
-  static TableSymbol *indirectFunctionTable;
+  TableSymbol *indirectFunctionTable = nullptr;
 };
 
 // A buffer class that is large enough to hold any Symbol-derived
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index c88a6f742c35e..ce71e8f915fef 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -328,8 +328,8 @@ void TableSection::addTable(InputTable *table) {
   // Some inputs require that the indirect function table be assigned to table
   // number 0.
   if (ctx.legacyFunctionTable &&
-      isa<DefinedTable>(WasmSym::indirectFunctionTable) &&
-      cast<DefinedTable>(WasmSym::indirectFunctionTable)->table == table) {
+      isa<DefinedTable>(ctx.wasmSym->indirectFunctionTable) &&
+      cast<DefinedTable>(ctx.wasmSym->indirectFunctionTable)->table == table) {
     if (out.importSec->getNumImportedTables()) {
       // Alack!  Some other input imported a table, meaning that we are unable
       // to assign table number 0 to the indirect function table.
@@ -408,8 +408,8 @@ void GlobalSection::assignIndexes() {
 }
 
 static void ensureIndirectFunctionTable() {
-  if (!WasmSym::indirectFunctionTable)
-    WasmSym::indirectFunctionTable =
+  if (!ctx.wasmSym->indirectFunctionTable)
+    ctx.wasmSym->indirectFunctionTable =
         symtab->resolveIndirectFunctionTable(/*required =*/true);
 }
 
@@ -443,9 +443,9 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
       // Get __memory_base
       writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
       if (sym->isTLS())
-        writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "__tls_base");
+        writeUleb128(os, ctx.wasmSym->tlsBase->getGlobalIndex(), "__tls_base");
       else
-        writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
+        writeUleb128(os, ctx.wasmSym->memoryBase->getGlobalIndex(),
                      "__memory_base");
 
       // Add the virtual address of the data symbol
@@ -456,7 +456,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
         continue;
       // Get __table_base
       writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
-      writeUleb128(os, WasmSym::tableBase->getGlobalIndex(), "__table_base");
+      writeUleb128(os, ctx.wasmSym->tableBase->getGlobalIndex(), "__table_base");
 
       // Add the table index to __table_base
       writeU8(os, opcode_ptr_const, "CONST");
@@ -503,13 +503,13 @@ void GlobalSection::writeBody() {
     if (ctx.arg.extendedConst && ctx.isPic) {
       if (auto *d = dyn_cast<DefinedData>(sym)) {
         if (!sym->isTLS()) {
-          globalIdx = WasmSym::memoryBase->getGlobalIndex();
+          globalIdx = ctx.wasmSym->memoryBase->getGlobalIndex();
           offset = d->getVA();
           useExtendedConst = true;
         }
       } else if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
         if (!sym->isStub) {
-          globalIdx = WasmSym::tableBase->getGlobalIndex();
+          globalIdx = ctx.wasmSym->tableBase->getGlobalIndex();
           offset = f->getTableIndex();
           useExtendedConst = true;
         }
@@ -564,12 +564,12 @@ void ExportSection::writeBody() {
 }
 
 bool StartSection::isNeeded() const {
-  return WasmSym::startFunction != nullptr;
+  return ctx.wasmSym->startFunction != nullptr;
 }
 
 void StartSection::writeBody() {
   raw_ostream &os = bodyOutputStream;
-  writeUleb128(os, WasmSym::startFunction->getFunct...
[truncated]

Copy link

github-actions bot commented Apr 9, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@anutosh491
Copy link
Member Author

Hey @sbc100

Would be great if you could tell me if I am heading towards the correct direction (shall look into why the tests fail after that)

@anutosh491
Copy link
Member Author

anutosh491 commented Apr 9, 2025

If we want to go the much simpler route where we don't introduce anything in ctx, we can probably just reset the existing static globals in WasmSym to nullptr before each link. Something like this

https://github.com/anutosh491/llvm-project/pull/1/files (made the changes in my local fork as an alternative solution)

Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@sbc100
Copy link
Collaborator

sbc100 commented Apr 9, 2025

Looks like maybe you need to run git clang-format origin/main to update the formatting of the changed lines.

@anutosh491
Copy link
Member Author

Thanks a lot @sbc100 for the quick reviews here
Much appreciated :)

I have made the changes related to git formatting in the latest commit .

@anutosh491
Copy link
Member Author

anutosh491 commented Apr 9, 2025

Squashed the commits into 2 meaningful commits. The CI on the commit passes too.

I think this would now be ready from my side.

EDIT: Also tried running the failing usecase I had (#134970 (comment)) with a local build with these changes. Works pretty smoothly !

@anutosh491 anutosh491 requested a review from sbc100 April 9, 2025 20:47
@anutosh491
Copy link
Member Author

Hey @sbc100 ,

Thanks for the review already but I would like to point out that once you're satisfied with the changes, something that would really help me would be if you could add a milestone label (so that the changes are picked up by llvm 20.1.3)

Cause this ends up being a major blocker while running clang-repl in the browser (as one state affects the next state when we run cells one by one). Also should help me migrate xeus-cpp-lite to llvm 20 !

@anutosh491
Copy link
Member Author

Gentle ping @sbc100
I think this is ready from my end.

@anutosh491
Copy link
Member Author

Tagging @MaskRay who might be able to help us with the reviews. Also cause I haven't heard from Sam since the PR was approved last week.

As discussed above the PR is trying to replicate your work on the ELF linker (03be619#diff-ba5e9bcbcabe54e23f58f9466afb49d9720373eb11b9b3a42ddc2d653b035594) but for wasm-ld.

Would be great if you could let me know if anything else is pending here. Thanks.

@MaskRay
Copy link
Member

MaskRay commented Apr 16, 2025

(I will have limited internet access between April 20th and May 4th, and my response time may be delayed..)

This is indeed similar to the ELF port and I hope we can move forward with this, but this needs @sbc100's approval.

@anutosh491
Copy link
Member Author

(I will have limited internet access between April 20th and May 4th, and my response time may be delayed..)

No issues !

Thanks a lot for going through the PR.

Copy link
Member

@MaskRay MaskRay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems that sbc100 actually approved before. LGTM

@anutosh491
Copy link
Member Author

Seems that sbc100 actually approved before. LGTM

Thank you !

@anutosh491
Copy link
Member Author

Hey @sbc100

This Pr stands approved right now (also approved by you in the past)

Would be grateful if you could help us take this in. Thank you !

@vgvassilev
Copy link
Contributor

This PR seems critical for downstream consumers. I'd like to merge it when the bots are green.

@anutosh491
Copy link
Member Author

anutosh491 commented Apr 25, 2025

Hey @vgvassilev,

Thanks for pushing this as I didn't hear much after the approvals. Could you please also apply a milestone label so that this is picked up for the next release.

Thanks again, the CI is green and this should be ready !

@MaskRay MaskRay merged commit 9cbbb74 into llvm:main Apr 25, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 25, 2025

LLVM Buildbot has detected a new failure on builder lldb-aarch64-ubuntu running on linaro-lldb-aarch64-ubuntu while building lld at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/59/builds/16649

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteCompletion.py (1207 of 2147)
UNSUPPORTED: lldb-api :: tools/lldb-server/TestGdbRemoteForkResume.py (1208 of 2147)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteExitCode.py (1209 of 2147)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteHostInfo.py (1210 of 2147)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteModuleInfo.py (1211 of 2147)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteAuxvSupport.py (1212 of 2147)
PASS: lldb-api :: terminal/TestEditlineCompletions.py (1213 of 2147)
UNSUPPORTED: lldb-api :: tools/lldb-server/TestGdbRemoteSaveCore.py (1214 of 2147)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteKill.py (1215 of 2147)
UNRESOLVED: lldb-api :: tools/lldb-dap/variables/TestDAP_variables.py (1216 of 2147)
******************** TEST 'lldb-api :: tools/lldb-dap/variables/TestDAP_variables.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --arch aarch64 --build-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/variables -p TestDAP_variables.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision 9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4)
  clang revision 9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4
  llvm revision 9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_darwin_dwarf_missing_obj (TestDAP_variables.TestDAP_variables) (requires one of macosx, darwin, ios, tvos, watchos, bridgeos, iphonesimulator, watchsimulator, appletvsimulator) 
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled (TestDAP_variables.TestDAP_variables) (requires one of macosx, darwin, ios, tvos, watchos, bridgeos, iphonesimulator, watchsimulator, appletvsimulator) 
========= DEBUG ADAPTER PROTOCOL LOGS =========
1745592272.641777039 --> (stdin/stdout) {"command":"initialize","type":"request","arguments":{"adapterID":"lldb-native","clientID":"vscode","columnsStartAt1":true,"linesStartAt1":true,"locale":"en-us","pathFormat":"path","supportsRunInTerminalRequest":true,"supportsVariablePaging":true,"supportsVariableType":true,"supportsStartDebuggingRequest":true,"supportsProgressReporting":true,"$__lldb_sourceInitFile":false},"seq":1}
1745592272.643809795 <-- (stdin/stdout) {"body":{"$__lldb_version":"lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision 9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4)\n  clang revision 9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4\n  llvm revision 9cbbb74d370c09e13b8412f21dccb7d2c4afc6a4","completionTriggerCharacters":["."," ","\t"],"exceptionBreakpointFilters":[{"default":false,"filter":"cpp_catch","label":"C++ Catch"},{"default":false,"filter":"cpp_throw","label":"C++ Throw"},{"default":false,"filter":"objc_catch","label":"Objective-C Catch"},{"default":false,"filter":"objc_throw","label":"Objective-C Throw"}],"supportTerminateDebuggee":true,"supportsBreakpointLocationsRequest":true,"supportsCancelRequest":true,"supportsCompletionsRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsDataBreakpoints":true,"supportsDelayedStackTraceLoading":true,"supportsDisassembleRequest":true,"supportsEvaluateForHovers":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":true,"supportsFunctionBreakpoints":true,"supportsHitConditionalBreakpoints":true,"supportsInstructionBreakpoints":true,"supportsLogPoints":true,"supportsModulesRequest":true,"supportsReadMemoryRequest":true,"supportsRestartRequest":true,"supportsSetVariable":true,"supportsStepInTargetsRequest":true,"supportsSteppingGranularity":true,"supportsValueFormattingOptions":true},"command":"initialize","request_seq":1,"seq":0,"success":true,"type":"response"}
1745592272.644073963 --> (stdin/stdout) {"command":"launch","type":"request","arguments":{"program":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/variables/TestDAP_variables.test_indexedVariables/a.out","initCommands":["settings clear -all","settings set symbols.enable-external-lookup false","settings set target.inherit-tcc true","settings set target.disable-aslr false","settings set target.detach-on-error false","settings set target.auto-apply-fixits false","settings set plugin.process.gdb-remote.packet-timeout 60","settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"","settings set use-color false","settings set show-statusline false"],"disableASLR":false,"enableAutoVariableSummaries":false,"enableSyntheticChildDebugging":false,"displayExtendedBacktrace":false,"commandEscapePrefix":null},"seq":2}
1745592272.644310713 <-- (stdin/stdout) {"body":{"category":"console","output":"Running initCommands:\n"},"event":"output","seq":0,"type":"event"}
1745592272.644341707 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings clear -all\n"},"event":"output","seq":0,"type":"event"}
1745592272.644352913 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set symbols.enable-external-lookup false\n"},"event":"output","seq":0,"type":"event"}
1745592272.644362688 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.inherit-tcc true\n"},"event":"output","seq":0,"type":"event"}
1745592272.644371510 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.disable-aslr false\n"},"event":"output","seq":0,"type":"event"}
1745592272.644379616 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.detach-on-error false\n"},"event":"output","seq":0,"type":"event"}
1745592272.644387722 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.auto-apply-fixits false\n"},"event":"output","seq":0,"type":"event"}
1745592272.644395590 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set plugin.process.gdb-remote.packet-timeout 60\n"},"event":"output","seq":0,"type":"event"}
1745592272.644417524 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"\n"},"event":"output","seq":0,"type":"event"}
1745592272.644428015 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set use-color false\n"},"event":"output","seq":0,"type":"event"}
1745592272.644435883 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set show-statusline false\n"},"event":"output","seq":0,"type":"event"}
1745592272.723302364 <-- (stdin/stdout) {"command":"launch","request_seq":2,"seq":0,"success":true,"type":"response"}
1745592272.723435402 <-- (stdin/stdout) {"body":{"isLocalProcess":true,"name":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/variables/TestDAP_variables.test_indexedVariables/a.out","startMethod":"launch","systemProcessId":514119},"event":"process","seq":0,"type":"event"}
1745592272.723446131 <-- (stdin/stdout) {"event":"initialized","seq":0,"type":"event"}
1745592272.723707438 --> (stdin/stdout) {"command":"setBreakpoints","type":"request","arguments":{"source":{"name":"main.cpp","path":"main.cpp"},"sourceModified":false,"lines":[40],"breakpoints":[{"line":40}]},"seq":3}
1745592272.725100994 <-- (stdin/stdout) {"body":{"breakpoints":[{"column":1,"id":1,"instructionReference":"0xAAAAE3960C54","line":41,"source":{"name":"main.cpp","path":"main.cpp"},"verified":true}]},"command":"setBreakpoints","request_seq":3,"seq":0,"success":true,"type":"response"}

@anutosh491 anutosh491 deleted the fix_wasmSym branch April 25, 2025 16:11
@vgvassilev vgvassilev added this to the LLVM 20.X Release milestone Apr 28, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Apr 28, 2025
@anutosh491
Copy link
Member Author

/cherry-pick 9cbbb74

@llvmbot
Copy link
Member

llvmbot commented Apr 28, 2025

Failed to cherry-pick: 9cbbb74

https://github.com/llvm/llvm-project/actions/runs/14705758050

Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request

@anutosh491
Copy link
Member Author

/cherry-pick 9cbbb74

@llvmbot
Copy link
Member

llvmbot commented Apr 28, 2025

Failed to cherry-pick: 9cbbb74

https://github.com/llvm/llvm-project/actions/runs/14706009216

Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request

anutosh491 added a commit to anutosh491/llvm-project that referenced this pull request Apr 28, 2025
…lvm#134970)

Towards

This change moves WasmSym from a static global struct to an instance
owned by Ctx, allowing it to be reset cleanly between linker runs. This
enables safe support for multiple invocations of wasm-ld within the same
process

Changes done

- Converted WasmSym from a static struct to a regular struct with
instance members.

- Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx.

- Reset wasmSym in Ctx::reset() to clear state between links.

- Replaced all WasmSym:: references with ctx.wasmSym->.

- Removed global symbol definitions from Symbols.cpp that are no longer
needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link
invocation, preventing symbol leakage across runs—critical when using
wasm-ld/lld as a reentrant library where global state can cause subtle,
hard-to-debug errors.

---------

Co-authored-by: Vassil Vassilev <[email protected]>
(cherry picked from commit 9cbbb74)
jyli0116 pushed a commit to jyli0116/llvm-project that referenced this pull request Apr 28, 2025
…lvm#134970)

Towards
#llvm#134809 (comment)

This change moves WasmSym from a static global struct to an instance
owned by Ctx, allowing it to be reset cleanly between linker runs. This
enables safe support for multiple invocations of wasm-ld within the same
process

Changes done 

- Converted WasmSym from a static struct to a regular struct with
instance members.

- Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx.

- Reset wasmSym in Ctx::reset() to clear state between links.

- Replaced all WasmSym:: references with ctx.wasmSym->.

- Removed global symbol definitions from Symbols.cpp that are no longer
needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link
invocation, preventing symbol leakage across runs—critical when using
wasm-ld/lld as a reentrant library where global state can cause subtle,
hard-to-debug errors.

---------

Co-authored-by: Vassil Vassilev <[email protected]>
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#134970)

Towards
#llvm#134809 (comment)

This change moves WasmSym from a static global struct to an instance
owned by Ctx, allowing it to be reset cleanly between linker runs. This
enables safe support for multiple invocations of wasm-ld within the same
process

Changes done 

- Converted WasmSym from a static struct to a regular struct with
instance members.

- Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx.

- Reset wasmSym in Ctx::reset() to clear state between links.

- Replaced all WasmSym:: references with ctx.wasmSym->.

- Removed global symbol definitions from Symbols.cpp that are no longer
needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link
invocation, preventing symbol leakage across runs—critical when using
wasm-ld/lld as a reentrant library where global state can cause subtle,
hard-to-debug errors.

---------

Co-authored-by: Vassil Vassilev <[email protected]>
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#134970)

Towards
#llvm#134809 (comment)

This change moves WasmSym from a static global struct to an instance
owned by Ctx, allowing it to be reset cleanly between linker runs. This
enables safe support for multiple invocations of wasm-ld within the same
process

Changes done 

- Converted WasmSym from a static struct to a regular struct with
instance members.

- Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx.

- Reset wasmSym in Ctx::reset() to clear state between links.

- Replaced all WasmSym:: references with ctx.wasmSym->.

- Removed global symbol definitions from Symbols.cpp that are no longer
needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link
invocation, preventing symbol leakage across runs—critical when using
wasm-ld/lld as a reentrant library where global state can cause subtle,
hard-to-debug errors.

---------

Co-authored-by: Vassil Vassilev <[email protected]>
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#134970)

Towards
#llvm#134809 (comment)

This change moves WasmSym from a static global struct to an instance
owned by Ctx, allowing it to be reset cleanly between linker runs. This
enables safe support for multiple invocations of wasm-ld within the same
process

Changes done 

- Converted WasmSym from a static struct to a regular struct with
instance members.

- Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx.

- Reset wasmSym in Ctx::reset() to clear state between links.

- Replaced all WasmSym:: references with ctx.wasmSym->.

- Removed global symbol definitions from Symbols.cpp that are no longer
needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link
invocation, preventing symbol leakage across runs—critical when using
wasm-ld/lld as a reentrant library where global state can cause subtle,
hard-to-debug errors.

---------

Co-authored-by: Vassil Vassilev <[email protected]>
Ankur-0429 pushed a commit to Ankur-0429/llvm-project that referenced this pull request May 9, 2025
…lvm#134970)

Towards
#llvm#134809 (comment)

This change moves WasmSym from a static global struct to an instance
owned by Ctx, allowing it to be reset cleanly between linker runs. This
enables safe support for multiple invocations of wasm-ld within the same
process

Changes done 

- Converted WasmSym from a static struct to a regular struct with
instance members.

- Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx.

- Reset wasmSym in Ctx::reset() to clear state between links.

- Replaced all WasmSym:: references with ctx.wasmSym->.

- Removed global symbol definitions from Symbols.cpp that are no longer
needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link
invocation, preventing symbol leakage across runs—critical when using
wasm-ld/lld as a reentrant library where global state can cause subtle,
hard-to-debug errors.

---------

Co-authored-by: Vassil Vassilev <[email protected]>
@tstellar
Copy link
Collaborator

Failed to cherry-pick: 9cbbb74

https://github.com/llvm/llvm-project/actions/runs/14706009216

Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request

@anutosh491 Were you able to manually create a pull request?

@anutosh491
Copy link
Member Author

Hey @tstellar

Here's the PR that stands approved #137620

Thanks !

@anutosh491
Copy link
Member Author

Here's the PR that stands approved #137620

I upgraded the branch (as some changes had gone in in the release branch)

@tstellar tstellar moved this from Needs Triage to Done in LLVM Release Status May 10, 2025
swift-ci pushed a commit to swiftlang/llvm-project that referenced this pull request May 10, 2025
…lvm#134970)

Towards

This change moves WasmSym from a static global struct to an instance
owned by Ctx, allowing it to be reset cleanly between linker runs. This
enables safe support for multiple invocations of wasm-ld within the same
process

Changes done

- Converted WasmSym from a static struct to a regular struct with
instance members.

- Added a std::unique_ptr<WasmSym> wasmSym field inside Ctx.

- Reset wasmSym in Ctx::reset() to clear state between links.

- Replaced all WasmSym:: references with ctx.wasmSym->.

- Removed global symbol definitions from Symbols.cpp that are no longer
needed.

Clearing wasmSym in ctx.reset() ensures a clean slate for each link
invocation, preventing symbol leakage across runs—critical when using
wasm-ld/lld as a reentrant library where global state can cause subtle,
hard-to-debug errors.

---------

Co-authored-by: Vassil Vassilev <[email protected]>
(cherry picked from commit 9cbbb74)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

7 participants