[lld] 9b020dd - [lld][WebAssembly] Don't export deps for unused stub symbols (#173422)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 23 16:58:10 PST 2025
Author: Heejin Ahn
Date: 2025-12-23T16:58:06-08:00
New Revision: 9b020ddaabd465e1fd26667179e170e72688f258
URL: https://github.com/llvm/llvm-project/commit/9b020ddaabd465e1fd26667179e170e72688f258
DIFF: https://github.com/llvm/llvm-project/commit/9b020ddaabd465e1fd26667179e170e72688f258.diff
LOG: [lld][WebAssembly] Don't export deps for unused stub symbols (#173422)
When a stub .so file contains
```
A: B
```
And `A` is defined in bitcode that's pulled in for LTO, but both `A` and
`B` are removed in `LTO::linkRegularLTO` due to not being dead:
https://github.com/llvm/llvm-project/blob/24297bea9672722d8fbaaff137b301b0becaae9c/llvm/lib/LTO/LTO.cpp#L1042-L1054
Then the symbol `A` becomes undefined after LTO, `processStubLibraries`
tries to import `A` from JS, and tries to export its dependency `B`:
https://github.com/llvm/llvm-project/blob/24297bea9672722d8fbaaff137b301b0becaae9c/lld/wasm/Driver.cpp#L1108-L1109
But `B` is gone, causing this error:
```console
wasm-ld: error: ....: undefined symbol: B. Required by A
```
This PR checks if the symbol is used in regular objects before trying to
exporrt its dependences, ensuring the case above doesn't crash the
linker.
Added:
lld/test/wasm/lto/Inputs/funcs.ll
Modified:
lld/test/wasm/lto/Inputs/stub.so
lld/test/wasm/lto/stub-library-libcall.s
lld/test/wasm/lto/stub-library.s
lld/wasm/Driver.cpp
Removed:
lld/test/wasm/lto/Inputs/foo.ll
################################################################################
diff --git a/lld/test/wasm/lto/Inputs/foo.ll b/lld/test/wasm/lto/Inputs/funcs.ll
similarity index 57%
rename from lld/test/wasm/lto/Inputs/foo.ll
rename to lld/test/wasm/lto/Inputs/funcs.ll
index f3b54cc7d0094..695b552fc6249 100644
--- a/lld/test/wasm/lto/Inputs/foo.ll
+++ b/lld/test/wasm/lto/Inputs/funcs.ll
@@ -1,7 +1,17 @@
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-unknown"
-define void @foo() local_unnamed_addr {
+define void @foo() {
+entry:
+ ret void
+}
+
+define void @baz() {
+entry:
+ ret void
+}
+
+define void @quux() {
entry:
ret void
}
diff --git a/lld/test/wasm/lto/Inputs/stub.so b/lld/test/wasm/lto/Inputs/stub.so
index e76c890dbb435..c471b81da5064 100644
--- a/lld/test/wasm/lto/Inputs/stub.so
+++ b/lld/test/wasm/lto/Inputs/stub.so
@@ -1,3 +1,4 @@
#STUB
bar: foo
memcpy: foo
+baz: quux
diff --git a/lld/test/wasm/lto/stub-library-libcall.s b/lld/test/wasm/lto/stub-library-libcall.s
index 40e15933f7bc3..af1e5ea84cd13 100644
--- a/lld/test/wasm/lto/stub-library-libcall.s
+++ b/lld/test/wasm/lto/stub-library-libcall.s
@@ -1,15 +1,15 @@
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t_main.o %t/main.s
-# RUN: llvm-as %S/Inputs/foo.ll -o %t_foo.o
+# RUN: llvm-as %S/Inputs/funcs.ll -o %t_funcs.o
# RUN: llvm-as %S/Inputs/libcall.ll -o %t_libcall.o
-# RUN: wasm-ld -mllvm -mattr=-bulk-memory,-bulk-memory-opt %t_main.o %t_libcall.o %t_foo.o %p/Inputs/stub.so -o %t.wasm
+# RUN: wasm-ld -mllvm -mattr=-bulk-memory,-bulk-memory-opt %t_main.o %t_libcall.o %t_funcs.o %p/Inputs/stub.so -o %t.wasm
# RUN: obj2yaml %t.wasm | FileCheck %s
# The function `func_with_libcall` will generate an undefined reference to
# `memcpy` at LTO time. `memcpy` itself also declared in stub.so and depends
# on `foo`
-# If %t_foo.o is not included in the link we get an undefined symbol reported
+# If %t_funcs.o is not included in the link we get an undefined symbol reported
# to the dependency of memcpy on the foo export:
# RUN: not wasm-ld -mllvm -mattr=-bulk-memory,-bulk-memory-opt %t_main.o %t_libcall.o %p/Inputs/stub.so -o %t.wasm 2>&1 | FileCheck --check-prefix=MISSING %s
diff --git a/lld/test/wasm/lto/stub-library.s b/lld/test/wasm/lto/stub-library.s
index 36d6b7b3f38aa..f4d1d1114eee5 100644
--- a/lld/test/wasm/lto/stub-library.s
+++ b/lld/test/wasm/lto/stub-library.s
@@ -1,19 +1,23 @@
## The function `bar` is declared in stub.so and depends on `foo` which is
## defined in an LTO object. We also test the case where the LTO object is
## with an archive file.
+## The function `baz` is declared in stub.so and depends on `quux`, and both
+## `baz` and `quux` are defined in an LTO object. When `baz` and `quux` are
+## DCE'd and become undefined in the LTO process, wasm-ld should not try to
+## export the (nonexistent) `quux`.
## This verifies that stub library dependencies (which are required exports) can
## be defined in LTO objects, even when they are within archive files.
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
# RUN: mkdir -p %t
-# RUN: llvm-as %S/Inputs/foo.ll -o %t/foo.o
-# RUN: wasm-ld %t.o %t/foo.o %p/Inputs/stub.so -o %t.wasm
+# RUN: llvm-as %S/Inputs/funcs.ll -o %t/funcs.o
+# RUN: wasm-ld %t.o %t/funcs.o %p/Inputs/stub.so -o %t.wasm
# RUN: obj2yaml %t.wasm | FileCheck %s
-## Run the same test but with foo.o inside of an archive file.
-# RUN: rm -f %t/libfoo.a
-# RUN: llvm-ar rcs %t/libfoo.a %t/foo.o
-# RUN: wasm-ld %t.o %t/libfoo.a %p/Inputs/stub.so -o %t2.wasm
+## Run the same test but with funcs.o inside of an archive file.
+# RUN: rm -f %t/libfuncs.a
+# RUN: llvm-ar rcs %t/libfuncs.a %t/funcs.o
+# RUN: wasm-ld %t.o %t/libfuncs.a %p/Inputs/stub.so -o %t2.wasm
# RUN: obj2yaml %t2.wasm | FileCheck %s
.functype bar () -> ()
@@ -40,3 +44,5 @@ _start:
# CHECK-NEXT: - Name: foo
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Index: 2
+
+# CHECK-NOT: - Name: quux
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 97e50783985a8..d18126bef766f 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -1105,7 +1105,7 @@ static void processStubLibraries() {
// the names of the stub imports
for (auto [name, deps]: stub_file->symbolDependencies) {
auto* sym = symtab->find(name);
- if (sym && sym->isUndefined()) {
+ if (sym && sym->isUndefined() && sym->isUsedInRegularObj) {
depsAdded |= addStubSymbolDeps(stub_file, sym, deps);
} else {
if (sym && sym->traced)
More information about the llvm-commits
mailing list