-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathwizer.h
107 lines (103 loc) · 5.31 KB
/
wizer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
* Wizer interface for Wasm module to be initialized.
*
* This header provides several macros that allow a Wasm module written in C/C++
* to declare an initializer function, and ensure that global constructors (in
* C++'s case) are run at initialization time rather than on startup of the
* pre-initialized module.
*/
#ifndef _WIZER_H_
#define _WIZER_H_
#ifdef __cplusplus
#define __WIZER_EXTERN_C extern "C"
#else
#define __WIZER_EXTERN_C extern
#endif
/*
* This macro inserts the exported functions necessary to allow Wizer to
* pre-initialize a Wasm module.
*
* To use, simply invoke the macro in exactly one compilation unit (C/C++ file)
* that is compiled into the Wasm module to be pre-initialized:
*
* static void my_init_function() { ... }
*
* WIZER_INIT(my_init_function);
*
* (The macro refers to the provided init function, so it must have been defined
* or must have a forward declaration at the point the macro is used.)
*
* The resulting module should be processed by Wizer as follows:
*
* $ wizer -r _start=wizer.resume -o out.wasm in.wasm
*
* The result of this will be the following behavior:
*
* - If the `in.wasm` (the direct compilation output of a program including this
* macro invocation) is run directly according to the WASI ABI (i.e., by
* invoking `_start`), then nothing changes: global constructors are run,
* `main()` is invoked, then global destructors are run. The initialization
* function is *not* run in this case.
*
* - During pre-initialization (i.e., during this `wizer` invocation), global
* constructors will run, and then the provided initialization function will
* run. The module's memory and global-variable state is then snapshotted and
* saved into `out.wasm`.
*
* All other Wizer restrictions apply (see Wizer documentation for details):
* for example, WASI hostcalls may be blocked, depending on options, and
* invoking any other imported function will result in an immediate trap
* and failure of the Wizer run.
*
* - If the resulting `out.wasm` is then run using the WASI ABI, the program's
* global constructors are *not* re-run. Instead, execution starts directly at
* `main()`, using the heap and global-variable state left by the global
* constructor and initialization function execution during the Wizer
* invocation.
*
* If no initialization function is needed (i.e., only C++ global constructors
* should be run), use `WIZER_DEFAULT_INIT()` instead.
*/
#define WIZER_INIT(init_func) \
__WIZER_EXTERN_C void __wasm_call_ctors(); \
__WIZER_EXTERN_C void __wasm_call_dtors(); \
__WIZER_EXTERN_C int __original_main(); \
/* This function's export name `wizer.initialize` is specially */ \
/* recognized by Wizer. It is the direct entry point for pre-init. */ \
__attribute__((export_name("wizer.initialize"))) void \
__wizer_initialize() { \
/* `__wasm_call_ctors()` is generated by `wasm-ld` and invokes all */ \
/* of the global constructors. It is safe (and in fact necessary) */ \
/* to manually invoke it here because `wizer.initialize` is the */ \
/* direct entry point, and no libc startup (crt1.o or equivalent) */ \
/* is executed before this code does. */ \
__wasm_call_ctors(); \
/* We now invoke the provided init function before returning. */ \
init_func(); \
} \
/* This function replaces `_start` (the WASI-specified entry point) in */ \
/* the pre-initialized Wasm module. */ \
__attribute__((export_name("wizer.resume"))) void __wizer_resume() { \
/* `__original_main()` is defined by the WASI SDK toolchain due to */ \
/* special semantics in C/C++ for the `main()` function, i.e., ito */ \
/* can either take argc/argv or not. It collects arguments using */ \
/* the appropriate WASI calls and then invokes the user program's */ \
/* `main()`. This may change in the future; when it does, we will */ \
/* coordinate with the WASI-SDK toolchain to implement this entry */ \
/* point in an alternate way. */ \
__original_main(); \
/* Because we are replacing `_start()`, we need to manually invoke */ \
/* destructors as well. */ \
__wasm_call_dtors(); \
}
/*
* This macro is like `WIZER_INIT()`, but takes no initialization function.
* Instead, the pre-initialization phase only executes C++ global constructors
* before snapshotting the module state.
*
* See documentation for `WIZER_INIT()` for more details and usage instructions.
*/
#define WIZER_DEFAULT_INIT() \
static void __empty_init() {} \
WIZER_INIT(__empty_init)
#endif // _WIZER_H_