Rewrite setjmp/longjmp docs (#562)

* Provide flags for emitting the standard exception-handling
instructions.
* More further explain what flags are doing.
* Show a sample program that can be compiled both ways.
* Delegate running in a runtime to various runtimes, so remove the "run
the program" documentation here.
* Remove `wasm-opt` documentation since it's now documented how to emit
the standard instructions directly with LLVM.
main
Alex Crichton 1 week ago committed by GitHub
parent d43a936053
commit d90d7de10e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -3,80 +3,115 @@
WASI-SDK provides basic setjmp/longjmp support.
Note that it's still under active development and may change in
future versions.
future versions. The tl;dr; version of this document is to pass these flags to
the C compiler:
## Build an application
To build an application using setjmp/longjmp, you need two things:
```
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false
```
* Enable the necessary LLVM translation (`-mllvm -wasm-enable-sjlj`)
## Implementation Primitives
Support for `setjmp` and `longjmp` is built on top of the
[exception-handling](https://github.com/WebAssembly/exception-handling)
WebAssembly proposal. This proposal is now [phase
5](https://github.com/WebAssembly/proposals) and becoming part of the official
specification. Note, however, that the exception-handling proposal has a long
history and has a "legacy" version which shipped in browsers as well. This means
that there are two different, but similar, sets of instructions that can be
emitted to support `setjmp` and `longjmp`. Clang 20 and later (wasi-sdk-26 and
later) is capable of emitting both at this time via `-mllvm
-wasm-use-legacy-eh={false,true}` compiler flags.
Another important point is that exception-handling only provides structured
control flow primitives for exceptions. This means it is not possible to purely
define `setjmp` in C as otherwise it must be a function that returns twice. This
means that support for `setjmp` and `longjmp` in WebAssembly relies on a
compiler pass to transform invocations of `setjmp` at a compiler IR level. This
means that the `setjmp` symbol is not defined in wasi-libc, for example, but
instead primitives used to implement `setjmp`, in conjunction with LLVM, are
found in wasi-libc.
* Link the setjmp library (`-lsetjmp`)
## Build an application
### Example without LTO
To build an application using setjmp/longjmp, you need three sets of compiler
flags:
```shell
clang -Os -mllvm -wasm-enable-sjlj -o your_app.legacy.wasm your_app.c -lsetjmp
```
1. `-mllvm -wasm-enable-sjlj`: Enable LLVM compiler pass which replaces calls to
`setjmp` and `longjmp` with a different implementation that wasi-libc
implements and hooks into.
2. `-lsetjmp`: Link the setjmp library that wasi-libc provides which contains
these hooks that LLVM uses.
2. `-mllvm -wasm-use-legacy-eh=false`: Specify which version of the
exception-handling instructions will be emitted. Note that if this is omitted
it currently defaults to `true` meaning that the legacy instructions are
emitted, not the standard instructions.
### Example with LTO
In short, these flags are required to use `setjmp`/`longjmp`
```shell
clang -Os -flto=full -mllvm -wasm-enable-sjlj -Wl,-mllvm,-wasm-enable-sjlj -o your_app.legacy.wasm your_app.c -lsetjmp
```
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false
```
## Run an application
### Examples
To run the application built as in the previous section,
you need to use a runtime with [exception handling proposal] support.
This source code:
Unfortunately, there are two incompatible versions of
[exception handling proposal], which is commonly implemented by runtimes.
```c
#include <assert.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stdio.h>
* The latest version with `exnref`
static jmp_buf env;
* The legacy [phase3] version
static bool test_if_longjmp(void(*f)(void)) {
if (setjmp(env))
return true;
f();
return false;
}
### Example with the latest exception handling proposal
static void do_not_longjmp() {
}
By default, the current version of WASI-SDK produces the legacy
"phase3" version of [exception handling proposal] instructions.
static void do_longjmp() {
longjmp(env, 1);
}
You can tell the llvm to produce the latest version of proposal by
specifying `-mllvm -wasm-use-legacy-eh=false`. This is expected
to be the default in a future version.
int main() {
bool longjmped = test_if_longjmp(do_not_longjmp);
assert(!longjmped);
longjmped = test_if_longjmp(do_longjmp);
assert(longjmped);
return 0;
}
```
Alternatively, you can use binaryen `wasm-opt` command to convert
existing modules from the legacy "phase3" version to the "exnref" version.
can be compiled using the standard set of instructions as:
```shell
wasm-opt --translate-to-exnref -all -o your_app.wasm your_app.legacy.wasm
clang -Os -o test.wasm test.c \
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false
```
Then you can run it with a runtime supporting the "exnref" version of
the proposal.
[toywasm] is an example of such runtimes.
and then `test.wasm` can be executed in a WebAssembly runtime supporting WASI.
You can also compile for the legacy exceptions proposal with:
```shell
toywasm --wasi your_app.wasm
clang -Os -o test.wasm test.c \
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=true
```
(You may need to enable the support with `-D TOYWASM_ENABLE_WASM_EXCEPTION_HANDLING=ON`.)
### Example with the legacy phase3 exception handling proposal
If your runtime supports the legacy [phase3] version of
[exception handling proposal], which is the same version as what WASI-SDK
currently produces by default, you can run the produced module as it is.
and then `test.wasm` can be executed in a WebAssembly runtime supporting the
legacy WebAssembly instructions.
For example, the classic interpreter of [wasm-micro-runtime] is
one of such runtimes.
Note that when compiling with LTO you'll need to pass `-mllvm` flags to the
linker in addition to Clang itself, such as:
```shell
iwasm your_app.legacy.wasm
clang -Os -flto=full -o test.wasm test.c \
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false \
-Wl,-mllvm,-wasm-enable-sjlj,-mllvm,-wasm-use-legacy-eh=false
```
(You may need to enable the support with `-D WAMR_BUILD_EXCE_HANDLING=1 -D WAMR_BUILD_FAST_INTERP=0`.)
[exception handling proposal]: https://github.com/WebAssembly/exception-handling/
[phase3]: https://github.com/WebAssembly/exception-handling/tree/main/proposals/exception-handling/legacy
[toywasm]: https://github.com/yamt/toywasm
[wasm-micro-runtime]: https://github.com/bytecodealliance/wasm-micro-runtime

Loading…
Cancel
Save