[lld] [llvm] [WebAssembly] Add support for shared tags (PR #188367)
Jasmine Tang via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 4 22:04:37 PDT 2026
https://github.com/badumbatish updated https://github.com/llvm/llvm-project/pull/188367
>From 22e1c0573be1c785d8d6a44c0815881d2aeee6fb Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Mon, 23 Mar 2026 23:29:52 -0700
Subject: [PATCH 1/4] Precommit test
---
lld/test/wasm/Inputs/tag-export.s | 3 +++
lld/test/wasm/shared-tag.s | 22 ++++++++++++++++++++++
2 files changed, 25 insertions(+)
create mode 100644 lld/test/wasm/Inputs/tag-export.s
create mode 100644 lld/test/wasm/shared-tag.s
diff --git a/lld/test/wasm/Inputs/tag-export.s b/lld/test/wasm/Inputs/tag-export.s
new file mode 100644
index 0000000000000..1eb64b98b2228
--- /dev/null
+++ b/lld/test/wasm/Inputs/tag-export.s
@@ -0,0 +1,3 @@
+ .globl __cpp_exception
+ .tagtype __cpp_exception i32
+__cpp_exception:
diff --git a/lld/test/wasm/shared-tag.s b/lld/test/wasm/shared-tag.s
new file mode 100644
index 0000000000000..b5ddb010fdd88
--- /dev/null
+++ b/lld/test/wasm/shared-tag.s
@@ -0,0 +1,22 @@
+# REQUIRES: wasm
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -mattr=+exception-handling -o %t.o %s
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/tag-export.s -o %t.tag.o
+# RUN: wasm-ld -shared --experimental-pic -o %t.tag.so %t.tag.o
+
+## Test that wasm-ld cannot resolve tags exported by shared libraries.
+## See https://github.com/llvm/llvm-project/issues/188120
+
+# RUN: not wasm-ld --experimental-pic -pie -o %t.wasm %t.o %t.tag.so 2>&1 | FileCheck %s
+
+
+ .tagtype __cpp_exception i32
+
+ .globl _start
+_start:
+ .functype _start () -> ()
+ i32.const 0
+ throw __cpp_exception
+ end_function
+
+
+# CHECK: error: {{.*}}shared-tag.s.tmp.o: undefined symbol: __cpp_exception
>From 692e60daec6a26df0142ea8dc5777b7c56d3164f Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Tue, 24 Mar 2026 15:16:24 -0700
Subject: [PATCH 2/4] Fix shared tag issue
---
lld/test/wasm/shared-tag.s | 9 ++++---
lld/wasm/InputFiles.cpp | 3 +++
lld/wasm/SymbolTable.cpp | 38 ++++++++++++++++++++++++++++++
lld/wasm/SymbolTable.h | 2 ++
lld/wasm/Symbols.cpp | 2 ++
lld/wasm/Symbols.h | 17 +++++++++++--
llvm/lib/Object/WasmObjectFile.cpp | 4 ++++
7 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/lld/test/wasm/shared-tag.s b/lld/test/wasm/shared-tag.s
index b5ddb010fdd88..7dc304264094a 100644
--- a/lld/test/wasm/shared-tag.s
+++ b/lld/test/wasm/shared-tag.s
@@ -3,10 +3,11 @@
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/tag-export.s -o %t.tag.o
# RUN: wasm-ld -shared --experimental-pic -o %t.tag.so %t.tag.o
-## Test that wasm-ld cannot resolve tags exported by shared libraries.
+## Test that wasm-ld can resolve tags exported by shared libraries.
## See https://github.com/llvm/llvm-project/issues/188120
-# RUN: not wasm-ld --experimental-pic -pie -o %t.wasm %t.o %t.tag.so 2>&1 | FileCheck %s
+# RUN: wasm-ld --experimental-pic -pie -o %t.wasm %t.o %t.tag.so
+# RUN: obj2yaml %t.wasm | FileCheck %s
.tagtype __cpp_exception i32
@@ -19,4 +20,6 @@ _start:
end_function
-# CHECK: error: {{.*}}shared-tag.s.tmp.o: undefined symbol: __cpp_exception
+# CHECK: Field: __cpp_exception
+# CHECK-NEXT: Kind: TAG
+# CHECK-NEXT: SigIndex: 0
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index dcdd138508c1e..ad7f207259a5b 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -453,6 +453,9 @@ void SharedFile::parse() {
case WASM_SYMBOL_TYPE_DATA:
s = symtab->addSharedData(name, flags, this);
break;
+ case WASM_SYMBOL_TYPE_TAG:
+ s = symtab->addSharedTag(name, flags, this, wasmSym.Signature);
+ break;
default:
continue;
}
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 9bd93f317c3c5..11ca4fc23d0b1 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -352,6 +352,44 @@ static void reportFunctionSignatureMismatch(StringRef symName,
isError);
}
+Symbol *SymbolTable::addSharedTag(StringRef name, uint32_t flags,
+ InputFile *file, const WasmSignature *sig) {
+ LLVM_DEBUG(dbgs() << "addSharedTag: " << name << " [" << toString(*sig)
+ << "]\n");
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
+
+ auto replaceSym = [&](Symbol *sym) {
+ replaceSymbol<SharedTagSymbol>(sym, name, flags, file, sig);
+ };
+
+ // same as addSharedFunction, but this is in its own function
+ if (wasInserted || s->isLazy()) {
+ replaceSym(s);
+ return s;
+ }
+
+ if (!isa<TagSymbol>(s)) {
+ reportTypeError(s, file, WASM_SYMBOL_TYPE_TAG);
+ return s;
+ }
+
+ if (s->isDefined()) {
+ return s;
+ }
+
+ // undefined existing sym
+ auto *existingTag = cast<TagSymbol>(s);
+ const WasmSignature *oldSig = existingTag->signature;
+ if (oldSig && sig && *oldSig != *sig)
+ warn("Tag signature mismatch: " + name + "\n>>> defined as " +
+ toString(*oldSig) + " in " + toString(existingTag->getFile()) +
+ "\n>>> defined as " + toString(*sig) + " in " + toString(file));
+ replaceSym(s);
+ return s;
+}
+
Symbol *SymbolTable::addSharedFunction(StringRef name, uint32_t flags,
InputFile *file,
const WasmSignature *sig) {
diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h
index 649614298c52b..0667cedecdb4f 100644
--- a/lld/wasm/SymbolTable.h
+++ b/lld/wasm/SymbolTable.h
@@ -53,6 +53,8 @@ class SymbolTable {
Symbol *addSharedFunction(StringRef name, uint32_t flags, InputFile *file,
const WasmSignature *sig);
Symbol *addSharedData(StringRef name, uint32_t flags, InputFile *file);
+ Symbol *addSharedTag(StringRef name, uint32_t flags, InputFile *file,
+ const WasmSignature *sig);
Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file,
InputFunction *function);
Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file,
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 97a9871a06308..9ce2a9f9f5091 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -72,6 +72,8 @@ std::string toString(wasm::Symbol::Kind kind) {
return "SharedFunctionKind";
case wasm::Symbol::SharedDataKind:
return "SharedDataKind";
+ case wasm::Symbol::SharedTagKind:
+ return "SharedTagSymbol";
}
llvm_unreachable("invalid symbol kind");
}
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 3dda36f88d5e3..47f1b3ad54ea2 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -62,6 +62,7 @@ class Symbol {
LazyKind,
SharedFunctionKind,
SharedDataKind,
+ SharedTagKind,
};
Kind kind() const { return symbolKind; }
@@ -77,7 +78,8 @@ class Symbol {
bool isLazy() const { return symbolKind == LazyKind; }
bool isShared() const {
- return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind;
+ return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind ||
+ symbolKind == SharedTagKind;
}
bool isLocal() const;
@@ -461,7 +463,8 @@ class UndefinedTable : public TableSymbol {
class TagSymbol : public Symbol {
public:
static bool classof(const Symbol *s) {
- return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind;
+ return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind ||
+ s->kind() == SharedTagKind;
}
// Get/set the tag index
@@ -501,6 +504,15 @@ class UndefinedTag : public TagSymbol {
static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }
};
+class SharedTagSymbol : public TagSymbol {
+public:
+ SharedTagSymbol(StringRef name, uint32_t flags, InputFile *f,
+ const WasmSignature *sig)
+ : TagSymbol(name, SharedTagKind, flags, f, sig) {}
+
+ static bool classof(const Symbol *s) { return s->kind() == SharedTagKind; }
+};
+
class SharedFunctionSymbol : public FunctionSymbol {
public:
SharedFunctionSymbol(StringRef name, uint32_t flags, InputFile *file,
@@ -553,6 +565,7 @@ union SymbolUnion {
alignas(UndefinedTable) char j[sizeof(UndefinedTable)];
alignas(SectionSymbol) char k[sizeof(SectionSymbol)];
alignas(SharedFunctionSymbol) char l[sizeof(SharedFunctionSymbol)];
+ alignas(SharedTagSymbol) char m[sizeof(SharedTagSymbol)];
};
// It is important to keep the size of SymbolUnion small for performance and
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 852dc23f99e54..5f125ffb10198 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1547,6 +1547,10 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
object_error::parse_failed);
Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG;
Info.ElementIndex = Ex.Index;
+ if (isDefinedTagIndex(Ex.Index)) {
+ unsigned TagIndex = Ex.Index - NumImportedTags;
+ Signature = &Signatures[Tags[TagIndex].SigIndex];
+ }
break;
case wasm::WASM_EXTERNAL_MEMORY:
break;
>From 75f3296674f3b972a26370993ecb658b2dec5a37 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Tue, 31 Mar 2026 21:30:25 -0700
Subject: [PATCH 3/4] Addresses PR review
---
lld/test/wasm/Inputs/libsearch-dyn.s | 6 +++++-
lld/test/wasm/Inputs/tag-export.s | 3 ---
lld/test/wasm/dylink.s | 11 ++++++++---
lld/test/wasm/shared-tag.s | 25 -------------------------
lld/wasm/SymbolTable.cpp | 10 +++++-----
5 files changed, 18 insertions(+), 37 deletions(-)
delete mode 100644 lld/test/wasm/Inputs/tag-export.s
delete mode 100644 lld/test/wasm/shared-tag.s
diff --git a/lld/test/wasm/Inputs/libsearch-dyn.s b/lld/test/wasm/Inputs/libsearch-dyn.s
index bb59580b830f5..11c5a1099e4b5 100644
--- a/lld/test/wasm/Inputs/libsearch-dyn.s
+++ b/lld/test/wasm/Inputs/libsearch-dyn.s
@@ -1,4 +1,4 @@
-.globl _bar,_dynamic
+.globl _bar,_dynamic,__foo_exception
.section .data,"",@
_bar:
@@ -6,3 +6,7 @@ _bar:
_dynamic:
.size _dynamic,4
+
+
+.tagtype __foo_exception i32
+__foo_exception:
diff --git a/lld/test/wasm/Inputs/tag-export.s b/lld/test/wasm/Inputs/tag-export.s
deleted file mode 100644
index 1eb64b98b2228..0000000000000
--- a/lld/test/wasm/Inputs/tag-export.s
+++ /dev/null
@@ -1,3 +0,0 @@
- .globl __cpp_exception
- .tagtype __cpp_exception i32
-__cpp_exception:
diff --git a/lld/test/wasm/dylink.s b/lld/test/wasm/dylink.s
index ab604fc1adc18..3736b029ec7da 100644
--- a/lld/test/wasm/dylink.s
+++ b/lld/test/wasm/dylink.s
@@ -1,4 +1,4 @@
-# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten -o %t.o %s
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten -mattr=+exception-handling -o %t.o %s
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten %p/Inputs/ret32.s -o %t.ret32.o
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten %p/Inputs/libsearch-dyn.s -o %t.dyn.o
# RUN: wasm-ld --experimental-pic -shared %t.ret32.o %t.dyn.o -o %t.lib.so
@@ -8,7 +8,7 @@
# Same again for wasm64
-# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten -o %t.o %s
+# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten -mattr=+exception-handling -o %t.o %s
# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten %p/Inputs/ret32.s -o %t.ret32.o
# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten %p/Inputs/libsearch-dyn.s -o %t.dyn.o
# RUN: wasm-ld --experimental-pic -mwasm64 -shared %t.ret32.o %t.dyn.o -o %t.lib.so
@@ -19,7 +19,7 @@
# ERROR: error: {{.*}}: undefined symbol: ret32
# ERROR: error: {{.*}}: undefined symbol: _bar
.functype ret32 (f32) -> (i32)
-
+.tagtype __foo_exception i32
.globl _start
_start:
.functype _start () -> ()
@@ -28,6 +28,8 @@ _start:
drop
i32.const _bar at GOT
drop
+ i32.const 0
+ throw __foo_exception
end_function
# CHECK: Sections:
@@ -39,3 +41,6 @@ _start:
# CHECK-NEXT: TableAlignment: 0
# CHECK-NEXT: Needed:
# CHECK-NEXT: - {{.*}}.lib.so
+# CHECK: Field: __foo_exception
+# CHECK-NEXT: Kind: TAG
+# CHECK-NEXT: SigIndex: 1
diff --git a/lld/test/wasm/shared-tag.s b/lld/test/wasm/shared-tag.s
deleted file mode 100644
index 7dc304264094a..0000000000000
--- a/lld/test/wasm/shared-tag.s
+++ /dev/null
@@ -1,25 +0,0 @@
-# REQUIRES: wasm
-# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -mattr=+exception-handling -o %t.o %s
-# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/tag-export.s -o %t.tag.o
-# RUN: wasm-ld -shared --experimental-pic -o %t.tag.so %t.tag.o
-
-## Test that wasm-ld can resolve tags exported by shared libraries.
-## See https://github.com/llvm/llvm-project/issues/188120
-
-# RUN: wasm-ld --experimental-pic -pie -o %t.wasm %t.o %t.tag.so
-# RUN: obj2yaml %t.wasm | FileCheck %s
-
-
- .tagtype __cpp_exception i32
-
- .globl _start
-_start:
- .functype _start () -> ()
- i32.const 0
- throw __cpp_exception
- end_function
-
-
-# CHECK: Field: __cpp_exception
-# CHECK-NEXT: Kind: TAG
-# CHECK-NEXT: SigIndex: 0
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 11ca4fc23d0b1..05e653ea23eda 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -370,7 +370,8 @@ Symbol *SymbolTable::addSharedTag(StringRef name, uint32_t flags,
return s;
}
- if (!isa<TagSymbol>(s)) {
+ auto *existingTag = dyn_cast<TagSymbol>(s);
+ if (!existingTag) {
reportTypeError(s, file, WASM_SYMBOL_TYPE_TAG);
return s;
}
@@ -380,12 +381,11 @@ Symbol *SymbolTable::addSharedTag(StringRef name, uint32_t flags,
}
// undefined existing sym
- auto *existingTag = cast<TagSymbol>(s);
const WasmSignature *oldSig = existingTag->signature;
if (oldSig && sig && *oldSig != *sig)
- warn("Tag signature mismatch: " + name + "\n>>> defined as " +
- toString(*oldSig) + " in " + toString(existingTag->getFile()) +
- "\n>>> defined as " + toString(*sig) + " in " + toString(file));
+ error("Tag signature mismatch: " + name + "\n>>> defined as " +
+ toString(*oldSig) + " in " + toString(existingTag->getFile()) +
+ "\n>>> defined as " + toString(*sig) + " in " + toString(file));
replaceSym(s);
return s;
}
>From 25adedf0b4ad742345e4e5370c16c1ae4650205f Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Sat, 4 Apr 2026 22:04:23 -0700
Subject: [PATCH 4/4] Addresses PR reviews
---
lld/test/wasm/Inputs/libsearch-dyn.s | 7 +++----
lld/test/wasm/dylink.s | 8 +++++---
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/lld/test/wasm/Inputs/libsearch-dyn.s b/lld/test/wasm/Inputs/libsearch-dyn.s
index 11c5a1099e4b5..96c351d6262f8 100644
--- a/lld/test/wasm/Inputs/libsearch-dyn.s
+++ b/lld/test/wasm/Inputs/libsearch-dyn.s
@@ -1,4 +1,4 @@
-.globl _bar,_dynamic,__foo_exception
+.globl _bar,_dynamic,_foo_tag
.section .data,"",@
_bar:
@@ -7,6 +7,5 @@ _bar:
_dynamic:
.size _dynamic,4
-
-.tagtype __foo_exception i32
-__foo_exception:
+.tagtype _foo_tag i32
+_foo_tag:
diff --git a/lld/test/wasm/dylink.s b/lld/test/wasm/dylink.s
index 3736b029ec7da..d40778c3b2d6f 100644
--- a/lld/test/wasm/dylink.s
+++ b/lld/test/wasm/dylink.s
@@ -18,8 +18,9 @@
# ERROR: error: {{.*}}: undefined symbol: ret32
# ERROR: error: {{.*}}: undefined symbol: _bar
+# ERROR: error: {{.*}}: undefined symbol: _foo_tag
.functype ret32 (f32) -> (i32)
-.tagtype __foo_exception i32
+.tagtype _foo_tag i32
.globl _start
_start:
.functype _start () -> ()
@@ -29,7 +30,7 @@ _start:
i32.const _bar at GOT
drop
i32.const 0
- throw __foo_exception
+ throw _foo_tag
end_function
# CHECK: Sections:
@@ -41,6 +42,7 @@ _start:
# CHECK-NEXT: TableAlignment: 0
# CHECK-NEXT: Needed:
# CHECK-NEXT: - {{.*}}.lib.so
-# CHECK: Field: __foo_exception
+#
+# CHECK: Field: _foo_tag
# CHECK-NEXT: Kind: TAG
# CHECK-NEXT: SigIndex: 1
More information about the llvm-commits
mailing list