Skip to content

enable exception support for shared libraries - #648

Closed
dicej wants to merge 10 commits into
WebAssembly:mainfrom
dicej:shared-library-exceptions
Closed

enable exception support for shared libraries#648
dicej wants to merge 10 commits into
WebAssembly:mainfrom
dicej:shared-library-exceptions

Conversation

@dicej

@dicej dicej commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

This backports llvm/llvm-project#209282 to resolve the remaining LLVM issues with Wasm exceptions and shared libraries.

I've updated tests/CMakeLists.txt to run all p2 and p3 tests as shared libraries as well as normal executables. As usual my CMake skills are underwhelming; very open to feedback.

Currently a few of the p3 tests are failing in shared library mode, apparently due to TLS-related issues. I'll work on debugging those.

@dicej
dicej requested a review from alexcrichton July 30, 2026 19:05
This backports llvm/llvm-project#209282 to resolve the
remaining LLVM issues with Wasm exceptions and shared libraries.

I've updated `tests/CMakeLists.txt` to run all p2 and p3 tests as shared
libraries as well as normal executables.  As usual my CMake skills are
underwhelming; very open to feedback.

Currently a few of the p3 tests are failing in shared library mode, apparently
due to TLS-related issues.  I'll work on debugging those.
@dicej
dicej force-pushed the shared-library-exceptions branch from 185ad7f to 6683f1b Compare July 30, 2026 20:31
dicej added 2 commits July 30, 2026 16:25
This helps ensure that `libc.so` is instantiated first, which matters because
other libraries like `libunwind.so` have start functions which call functions
like `__wasm_set_tls_base` imported from `libc.so`.

Specifically, there's a dependency cycle between `libc.so` and the application
`.so` because `libc.so` imports `__main_argc_argv` and the application `.so`
imports a bunch of stuff from `libc.so`.  `wit-component` will try to break that
cycle by having the synthesized `env` module re-export functions using
`call_indirect`, but that only works if the start functions of each library
participating in the cycle don't call imports from each other, since the table
used by the `call_indirect` calls is only initialized as part of the last
`__init` module's instantiation.  `wit-component` isn't smart enough inspect the
code and figure all that out, but it will attempt to preserve the order
libraries were specified (programatically or via the CLI), so if we specify
`libc.so` first, it will be instantiated first in its "cyclical dependency"
group.

@alexcrichton alexcrichton left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm, but it looks like bytecodealliance/wasm-tools#2584 I forgot to handle shared libraries and with WebAssembly/wasi-libc#856 coupled that means that I broke shared libraries again

In theory a pretty easy fix within wasm-tools I think though? Should be easy enough to publish a new version + a new wasm-component-ld

@alexcrichton

Copy link
Copy Markdown
Collaborator

@dicej I've applied this locally:

commit 6f6f7fa82584ff85c5bdca690a1e0f2a6ce3f12a
Author: Alex Crichton <alex@alexcrichton.com>
Date:   Mon Aug 10 12:24:44 2026 -0700

    Update wasi-libc to fix TLS

diff --git a/cmake/wasi-sdk-toolchain.cmake b/cmake/wasi-sdk-toolchain.cmake
index c2e69779..2585f50b 100644
--- a/cmake/wasi-sdk-toolchain.cmake
+++ b/cmake/wasi-sdk-toolchain.cmake
@@ -278,7 +278,7 @@ install(DIRECTORY ${wasi_tmp_install}/bin ${wasi_tmp_install}/lib ${wasi_tmp_ins
 # Build logic for `wasm-component-ld` installed from Rust code.
 set(wasm_component_ld_root ${CMAKE_CURRENT_BINARY_DIR}/wasm-component-ld)
 set(wasm_component_ld ${wasm_component_ld_root}/bin/wasm-component-ld${CMAKE_EXECUTABLE_SUFFIX})
-set(wasm_component_ld_version 0.5.28)
+set(wasm_component_ld_version 0.5.29)
 if(RUST_TARGET)
   set(rust_target_flag --target=${RUST_TARGET})
 endif()
diff --git a/src/wasi-libc b/src/wasi-libc
index 6d8745c8..79c1a738 160000
--- a/src/wasi-libc
+++ b/src/wasi-libc
@@ -1 +1 @@
-Subproject commit 6d8745c8cec1aaa82c24f2e3d7a544f7ea9c2089
+Subproject commit 79c1a738e1b3df432545666a1a579c49a82b4514

and I'm still seeing failures:

The following tests FAILED:
	 47 - test-wasm32-wasip3.-O0.shared.argc_argv_main.cc (Failed)
	 49 - test-wasm32-wasip3.-O2.shared.argc_argv_main.cc (Failed)
	 51 - test-wasm32-wasip3.-O2.-flto.shared.argc_argv_main.cc (Failed)
	119 - test-wasm32-wasip3.-O0.shared.cpp_thread_local.cc (Failed)
	121 - test-wasm32-wasip3.-O2.shared.cpp_thread_local.cc (Failed)
	123 - test-wasm32-wasip3.-O2.-flto.shared.cpp_thread_local.cc (Failed)
	155 - test-wasm32-wasip3.-O0.shared.ctors_dtors.cc (Failed)
	157 - test-wasm32-wasip3.-O2.shared.ctors_dtors.cc (Failed)
	159 - test-wasm32-wasip3.-O2.-flto.shared.ctors_dtors.cc (Failed)
	245 - test-wasm32-wasip3.-O0.shared.exceptions.cc (Failed)
	247 - test-wasm32-wasip3.-O2.shared.exceptions.cc (Failed)
	249 - test-wasm32-wasip3.-O2.-flto.shared.exceptions.cc (Failed)
	281 - test-wasm32-wasip3.-O0.shared.iostream_main.cc (Failed)
	283 - test-wasm32-wasip3.-O2.shared.iostream_main.cc (Failed)
	285 - test-wasm32-wasip3.-O2.-flto.shared.iostream_main.cc (Failed)
	353 - test-wasm32-wasip3.-O0.shared.no_arg_main.cc (Failed)
	355 - test-wasm32-wasip3.-O2.shared.no_arg_main.cc (Failed)
	357 - test-wasm32-wasip3.-O2.-flto.shared.no_arg_main.cc (Failed)
	515 - test-wasm32-wasip3.-O0.shared.void_main.cc (Failed)
	517 - test-wasm32-wasip3.-O2.shared.void_main.cc (Failed)
	519 - test-wasm32-wasip3.-O2.-flto.shared.void_main.cc (Failed)

for example:

522/522 Test #519: test-wasm32-wasip3.-O2.-flto.shared.void_main.cc ...........................***Failed  Required regular expression not found. Regex=[hello from C\+\+ void main
]  0.65 sec
Error: failed to run main module `/home/alex/code/wasi-sdk/build/sysroot/tests/general/wasm32-wasip3.-O2.-flto.shared.void_main.cc.wasm`

Caused by:
    0: error while executing at wasm backtrace:
    0:  0x2c5f5 - <unknown>!<wasm function 1207>
    1: 0x2b64c3 - libunwind.so!__wasm_init_memory
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
    1: wasm trap: wasm `unreachable` instruction executed

IIRC you fixed this by passing -lc in a different order or something like that, do you remember? Otherwise though with a wasm-component-ld + wasi-libc update I think this should be ready to land

@dicej

dicej commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Yeah, the order in which libraries are passed to wasm-tools component link matters. I'll take a look shortly.

@dicej

dicej commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@alexcrichton I took a closer look, and the latest issues are unrelated to the instantiation order issue we saw earlier. Instead, libunwind.so is calling __wasm_set_tls_base which wit-component assumes should never be called.

@alexcrichton

Copy link
Copy Markdown
Collaborator

Oh, right, we need to patch the driver to export the TLS size symbols in clang

@alexcrichton

Copy link
Copy Markdown
Collaborator

Ok I've added a commit to export TLS information and I've also spun off the final test failures into WebAssembly/tool-conventions#270 and ignored those tests for now. Gonna see if this is green to land...

@alexcrichton
alexcrichton enabled auto-merge (squash) August 10, 2026 22:43
@alexcrichton

Copy link
Copy Markdown
Collaborator

Ok this is getting messy enough I'm going to avoid landing this for now. Exceptions + shared libraries are known to be broken on coop threads with no known fix, and it's also known now that one of the patches included here won't be included in LLVM. Testing here is also getting pretty messy trying to deal with system-toolchains-vs-not, so I think it may be best to revisit this once shared libraries are supported for exceptions.

@dicej

dicej commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Closing this for now; we can either reopen this or create a new one later once we've sorted out how shared libraries, TLS, and exceptions should interact in LLVM.

@dicej dicej closed this Aug 11, 2026
auto-merge was automatically disabled August 11, 2026 23:32

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants