diff --git a/expected/wasm32-wasi-threads/defined-symbols.txt b/expected/wasm32-wasi-threads/defined-symbols.txt index 65169b4d3..1f0808866 100644 --- a/expected/wasm32-wasi-threads/defined-symbols.txt +++ b/expected/wasm32-wasi-threads/defined-symbols.txt @@ -532,6 +532,8 @@ __wasilibc_tls_align __wasilibc_tls_size __wasilibc_unlinkat __wasilibc_utimens +__wasix_init +__wasix_resume __wasm_call_dtors __wasm_signal __wcscoll_l diff --git a/expected/wasm32-wasi/defined-symbols.txt b/expected/wasm32-wasi/defined-symbols.txt index 7a59c64e5..bcb8523f3 100644 --- a/expected/wasm32-wasi/defined-symbols.txt +++ b/expected/wasm32-wasi/defined-symbols.txt @@ -538,6 +538,8 @@ __wasilibc_tls_align __wasilibc_tls_size __wasilibc_unlinkat __wasilibc_utimens +__wasix_init +__wasix_resume __wasm_call_dtors __wasm_signal __wcscoll_l diff --git a/expected/wasm64-wasi/defined-symbols.txt b/expected/wasm64-wasi/defined-symbols.txt index 7a59c64e5..bcb8523f3 100644 --- a/expected/wasm64-wasi/defined-symbols.txt +++ b/expected/wasm64-wasi/defined-symbols.txt @@ -538,6 +538,8 @@ __wasilibc_tls_align __wasilibc_tls_size __wasilibc_unlinkat __wasilibc_utimens +__wasix_init +__wasix_resume __wasm_call_dtors __wasm_signal __wcscoll_l diff --git a/libc-bottom-half/crt/crt1-command.c b/libc-bottom-half/crt/crt1-command.c index fb9ee71fb..a6fec5108 100644 --- a/libc-bottom-half/crt/crt1-command.c +++ b/libc-bottom-half/crt/crt1-command.c @@ -7,27 +7,40 @@ extern void __wasm_call_ctors(void); extern int __main_void(void); extern void __wasm_call_dtors(void); +// We use `volatile` here to prevent the store to `started` from being +// sunk past any subsequent code, and to prevent any compiler from +// optimizing based on the knowledge that `_start` is the program +// entrypoint. +#ifdef _REENTRANT +static volatile _Atomic int __wasix_started = 0; +static volatile _Atomic int __wasix_resumed = 0; +#else +static volatile int __wasix_started = 0; +static volatile int __wasix_resumed = 0; +#endif + __attribute__((export_name("_start"))) void _start(void) { // Commands should only be called once per instance. This simple check // ensures that the `_start` function isn't started more than once. - // - // We use `volatile` here to prevent the store to `started` from being - // sunk past any subsequent code, and to prevent any compiler from - // optimizing based on the knowledge that `_start` is the program - // entrypoint. #ifdef _REENTRANT - static volatile _Atomic int started = 0; int expected = 0; - if (!atomic_compare_exchange_strong(&started, &expected, 1)) { - __builtin_trap(); + int resume_expected = 0; + if (!atomic_compare_exchange_strong(&__wasix_started, &expected, 1)) { + __builtin_trap(); + } + if (!atomic_compare_exchange_strong(&__wasix_resumed, &resume_expected, 1)) { + __builtin_trap(); } #else - static volatile int started = 0; - if (started != 0) { - __builtin_trap(); + if (__wasix_started != 0) { + __builtin_trap(); + } + __wasix_started = 1; + if (__wasix_resumed != 0) { + __builtin_trap(); } - started = 1; + __wasix_resumed = 1; #endif #ifdef _REENTRANT @@ -51,3 +64,61 @@ void _start(void) { __wasi_proc_exit(r); } } + +// This function acts as the top "half" of _start, up until the call to +// __main_void. This is useful when a module needs to do initialization +// separately, e.g. when using partial evaluation tools. When used with +// __wasix_resume, they perform the same logic as calling _start once. +__attribute__((export_name("__wasix_init"))) +void __wasix_init(void) { +#ifdef _REENTRANT + int expected = 0; + if (!atomic_compare_exchange_strong(&__wasix_started, &expected, 1)) { + __builtin_trap(); + } +#else + if (__wasix_started != 0) { + __builtin_trap(); + } + __wasix_started = 1; +#endif + +#ifdef _REENTRANT + __wasi_init_tp(); +#endif + + __wasm_call_ctors(); +} + +// This is the bottom "half" of _start, which can be called after +// __wasix_init to continue executing the module normally. This +// function also checks the value of __wasix_started to make sure +// __wasix_init was called beforehand. +__attribute__((export_name("__wasix_resume"))) +void __wasix_resume(void) { +#ifdef _REENTRANT + if (atomic_load(&__wasix_started) != 1) { + __builtin_trap(); + } + int expected = 0; + if (!atomic_compare_exchange_strong(&__wasix_resumed, &expected, 1)) { + __builtin_trap(); + } +#else + if (__wasix_started != 1) { + __builtin_trap(); + } + if (__wasix_resumed != 0) { + __builtin_trap(); + } + __wasix_resumed = 1; +#endif + + int r = __main_void(); + + __wasm_call_dtors(); + + if (r != 0) { + __wasi_proc_exit(r); + } +} \ No newline at end of file