/*1* Wizer interface for Wasm module to be initialized.2*3* This header provides several macros that allow a Wasm module written in C/C++4* to declare an initializer function, and ensure that global constructors (in5* C++'s case) are run at initialization time rather than on startup of the6* pre-initialized module.7*/8#ifndef _WIZER_H_9#define _WIZER_H_1011#ifdef __cplusplus12#define __WIZER_EXTERN_C extern "C"13#else14#define __WIZER_EXTERN_C extern15#endif1617#ifdef __clang_major__18// wasi-sdk-16 was the first wasi-sdk version that shipped with a version of19// wasi-libc that did not include __original_main. However, wasi-sdk-15 shipped20// with clang-14.0.0. To correctly identify the boundary where __original_main21// no longer exists, we check for either clang-15+ or specifically clang-14.0.4.22//23// wasi-sdk-17 ships with clang-15.0.624// wasi-sdk-16 ships with clang-14.0.425#if __clang_major__ >= 15 || \26(__clang_major__ == 14 && __clang_patchlevel__ == 4)27#define WIZER_MAIN_VOID __main_void28#else29#define WIZER_MAIN_VOID __original_main30#endif31#endif3233// We default to assuming that the compiler is new enough to provide34// __main_void.35#ifndef WIZER_MAIN_VOID36#define WIZER_MAIN_VOID __main_void37#endif3839/*40* This macro inserts the exported functions necessary to allow Wizer to41* pre-initialize a Wasm module.42*43* To use, simply invoke the macro in exactly one compilation unit (C/C++ file)44* that is compiled into the Wasm module to be pre-initialized:45*46* static void my_init_function() { ... }47*48* WIZER_INIT(my_init_function);49*50* (The macro refers to the provided init function, so it must have been defined51* or must have a forward declaration at the point the macro is used.)52*53* The resulting module should be processed by Wizer as follows:54*55* $ wizer -r _start=wizer.resume -o out.wasm in.wasm56*57* The result of this will be the following behavior:58*59* - If the `in.wasm` (the direct compilation output of a program including this60* macro invocation) is run directly according to the WASI ABI (i.e., by61* invoking `_start`), then nothing changes: global constructors are run,62* `main()` is invoked, then global destructors are run. The initialization63* function is *not* run in this case.64*65* - During pre-initialization (i.e., during this `wizer` invocation), global66* constructors will run, and then the provided initialization function will67* run. The module's memory and global-variable state is then snapshotted and68* saved into `out.wasm`.69*70* All other Wizer restrictions apply (see Wizer documentation for details):71* for example, WASI hostcalls may be blocked, depending on options, and72* invoking any other imported function will result in an immediate trap73* and failure of the Wizer run.74*75* - If the resulting `out.wasm` is then run using the WASI ABI, the program's76* global constructors are *not* re-run. Instead, execution starts directly at77* `main()`, using the heap and global-variable state left by the global78* constructor and initialization function execution during the Wizer79* invocation.80*81* If no initialization function is needed (i.e., only C++ global constructors82* should be run), use `WIZER_DEFAULT_INIT()` instead.83*/84#define WIZER_INIT(init_func) \85__WIZER_EXTERN_C void __wasm_call_ctors(); \86__WIZER_EXTERN_C void __wasm_call_dtors(); \87__WIZER_EXTERN_C void __wasi_proc_exit(int); \88__WIZER_EXTERN_C int WIZER_MAIN_VOID(); \89/* This function's export name `wizer-initialize` is specially */ \90/* recognized by Wizer. It is the direct entry point for pre-init. */ \91__attribute__((export_name("wizer-initialize"))) void __wizer_initialize() { \92/* `__wasm_call_ctors()` is generated by `wasm-ld` and invokes all */ \93/* of the global constructors. It is safe (and in fact necessary) */ \94/* to manually invoke it here because `wizer-initialize` is the */ \95/* direct entry point, and no libc startup (crt1.o or equivalent) */ \96/* is executed before this code does. */ \97__wasm_call_ctors(); \98/* We now invoke the provided init function before returning. */ \99init_func(); \100} \101/* This function replaces `_start` (the WASI-specified entry point) in */ \102/* the pre-initialized Wasm module. */ \103__attribute__((export_name("wizer.resume"))) void __wizer_resume() { \104/* `__main_void()` is defined by the WASI SDK toolchain due to */ \105/* special semantics in C/C++ for the `main()` function, i.e., ito */ \106/* can either take argc/argv or not. It collects arguments using */ \107/* the appropriate WASI calls and then invokes the user program's */ \108/* `main()`. This may change in the future; when it does, we will */ \109/* coordinate with the WASI-SDK toolchain to implement this entry */ \110/* point in an alternate way. */ \111int r = WIZER_MAIN_VOID(); \112/* Because we are replacing `_start()`, we need to manually invoke */ \113/* destructors as well. */ \114__wasm_call_dtors(); \115/* If main returned non-zero code, call `__wasi_proc_exit`. */ \116if (r != 0) { \117__wasi_proc_exit(r); \118} \119}120121/*122* This macro is like `WIZER_INIT()`, but takes no initialization function.123* Instead, the pre-initialization phase only executes C++ global constructors124* before snapshotting the module state.125*126* See documentation for `WIZER_INIT()` for more details and usage instructions.127*/128#define WIZER_DEFAULT_INIT() \129static void __empty_init() {} \130WIZER_INIT(__empty_init)131132#endif // _WIZER_H_133134135