[llvm] [WebAssembly] Define `__funcref_call_table` in generated asm and objects (PR #180900)

Demetrius Kanios via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 11 00:37:14 PST 2026


https://github.com/QuantumSegfault created https://github.com/llvm/llvm-project/pull/180900

Currently, calls into funcref (`call addrspace(20)`) are lowered into a store of the ref into a special single-element `__funcref_call_table`, a call_indirect into said table, then a store of null into it.

It functions just fine when `-filetype=asm` (default), but when emitting an object file directly from llc it fails with `LLVM ERROR: undefined table symbol cannot be weak`

This fixes said error by "defining" it during `WebAssemblyAsmPrinter`, and ensuring it is definitely emitted as weak (so duplicate tables in multiple objects are merged into a single one).

>From 80479a78a5128012ec0b09f780bea1d8710337f4 Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Wed, 11 Feb 2026 00:26:33 -0800
Subject: [PATCH] Define `__funcref_call_table` in generated asm and objects

---
 .../Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 16 ++++++++++++++++
 llvm/test/CodeGen/WebAssembly/funcref-call.ll    |  1 +
 2 files changed, 17 insertions(+)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 1cacdb04fa74d..afe834b077909 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -392,6 +392,22 @@ void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
   // emitDecls() is not called until now.
   emitDecls(M);
 
+  {
+    StringRef Name = "__funcref_call_table";
+    auto *Sym = static_cast<MCSymbolWasm *>(OutContext.lookupSymbol(Name));
+    if (Sym) {
+      if (!Sym->isFunctionTable())
+        OutContext.reportError(SMLoc(), "symbol is not a wasm funcref table");
+
+      if (Sym->isWeak()) {
+        OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
+      }
+      if (!Sym->isDefined()) {
+        OutStreamer->emitLabel(Sym);
+        OutStreamer->addBlankLine();
+      }
+    }
+  }
   // When a function's address is taken, a TABLE_INDEX relocation is emitted
   // against the function symbol at the use site.  However the relocation
   // doesn't explicitly refer to the table.  In the future we may want to
diff --git a/llvm/test/CodeGen/WebAssembly/funcref-call.ll b/llvm/test/CodeGen/WebAssembly/funcref-call.ll
index 9904df2280e81..4f6025de4759c 100644
--- a/llvm/test/CodeGen/WebAssembly/funcref-call.ll
+++ b/llvm/test/CodeGen/WebAssembly/funcref-call.ll
@@ -1,6 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc < %s --mtriple=wasm32-unknown-unknown -fast-isel=0 -mattr=+reference-types | FileCheck %s
 ; RUN: llc < %s --mtriple=wasm32-unknown-unknown -fast-isel=1 -mattr=+reference-types | FileCheck %s
+; RUN: llc < %s --mtriple=wasm32-unknown-unknown --filetype=obj
 
 %funcref = type ptr addrspace(20) ;; addrspace 20 is nonintegral
 



More information about the llvm-commits mailing list