diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 1c9b8a1f7..d3dff3169 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -325,6 +325,61 @@ impl<'a> EmscriptenData<'a> { } } +/// Call the global constructors for C++ and set up the emscripten environment. +/// +/// Note that this function does not completely set up Emscripten to be called. +/// before calling this function, please initialize `Ctx::data` with a pointer +/// to [`EmscriptenData`]. +pub fn set_up_emscripten(instance: &mut Instance) -> CallResult<()> { + // ATINIT + // (used by C++) + if let Ok(_func) = instance.dyn_func("globalCtors") { + instance.call("globalCtors", &[])?; + } + + if let Ok(_func) = instance.dyn_func("___emscripten_environ_constructor") { + instance.call("___emscripten_environ_constructor", &[])?; + } + Ok(()) +} + +/// Call the main function in emscripten, assumes that the emscripten state is +/// set up. +/// +/// If you don't want to set it up yourself, consider using [`run_emscripten_instance`]. +pub fn emscripten_call_main(instance: &mut Instance, path: &str, args: &[&str]) -> CallResult<()> { + let (func_name, main_func) = match instance.dyn_func("_main") { + Ok(func) => Ok(("_main", func)), + Err(_e) => match instance.dyn_func("main") { + Ok(func) => Ok(("main", func)), + Err(e) => Err(e), + }, + }?; + let num_params = main_func.signature().params().len(); + let _result = match num_params { + 2 => { + let mut new_args = vec![path]; + new_args.extend(args); + let (argc, argv) = store_module_arguments(instance.context_mut(), new_args); + instance.call( + func_name, + &[Value::I32(argc as i32), Value::I32(argv as i32)], + )?; + } + 0 => { + instance.call(func_name, &[])?; + } + _ => { + return Err(CallError::Resolve(ResolveError::ExportWrongType { + name: "main".to_string(), + })) + } + }; + + Ok(()) +} + +/// Top level function to execute emscripten pub fn run_emscripten_instance( _module: &Module, instance: &mut Instance, @@ -338,15 +393,7 @@ pub fn run_emscripten_instance( let data_ptr = &mut data as *mut _ as *mut c_void; instance.context_mut().data = data_ptr; - // ATINIT - // (used by C++) - if let Ok(_func) = instance.dyn_func("globalCtors") { - instance.call("globalCtors", &[])?; - } - - if let Ok(_func) = instance.dyn_func("___emscripten_environ_constructor") { - instance.call("___emscripten_environ_constructor", &[])?; - } + set_up_emscripten(instance)?; // println!("running emscripten instance"); @@ -356,33 +403,7 @@ pub fn run_emscripten_instance( //let (argc, argv) = store_module_arguments(instance.context_mut(), args); instance.call(&ep, &[Value::I32(arg as i32)])?; } else { - let (func_name, main_func) = match instance.dyn_func("_main") { - Ok(func) => Ok(("_main", func)), - Err(_e) => match instance.dyn_func("main") { - Ok(func) => Ok(("main", func)), - Err(e) => Err(e), - }, - }?; - let num_params = main_func.signature().params().len(); - let _result = match num_params { - 2 => { - let mut new_args = vec![path]; - new_args.extend(args); - let (argc, argv) = store_module_arguments(instance.context_mut(), new_args); - instance.call( - func_name, - &[Value::I32(argc as i32), Value::I32(argv as i32)], - )?; - } - 0 => { - instance.call(func_name, &[])?; - } - _ => { - return Err(CallError::Resolve(ResolveError::ExportWrongType { - name: "main".to_string(), - })) - } - }; + emscripten_call_main(instance, path, &args)?; } // TODO atexit for emscripten diff --git a/lib/runtime-c-api/src/import/emscripten.rs b/lib/runtime-c-api/src/import/emscripten.rs index caced6a62..7a9b111dd 100644 --- a/lib/runtime-c-api/src/import/emscripten.rs +++ b/lib/runtime-c-api/src/import/emscripten.rs @@ -1,10 +1,11 @@ //! Functions and types for dealing with Emscripten imports use super::*; -use crate::module::wasmer_module_t; +use crate::{get_slice_checked, instance::wasmer_instance_t, module::wasmer_module_t}; + use std::ptr; use wasmer_emscripten::EmscriptenGlobals; -use wasmer_runtime::Module; +use wasmer_runtime::{Instance, Module}; /// Type used to construct an import_object_t with Emscripten imports. #[repr(C)] @@ -40,9 +41,88 @@ pub unsafe extern "C" fn wasmer_emscripten_destroy_emscripten_globals( let _ = Box::from_raw(globals); } +/// Execute global constructors (required if the module is compiled from C++) +/// and sets up the internal environment. +/// +/// This function sets the data pointer in the same way that +/// [`wasmer_instance_context_data_set`] does. +#[no_mangle] +pub unsafe extern "C" fn wasmer_emscripten_set_up_emscripten( + instance: *mut wasmer_instance_t, + globals: *mut wasmer_emscripten_globals_t, +) -> wasmer_result_t { + if globals.is_null() || instance.is_null() { + return wasmer_result_t::WASMER_ERROR; + } + let instance = &mut *(instance as *mut Instance); + instance.context_mut().data = globals as *mut c_void; + match wasmer_emscripten::set_up_emscripten(instance) { + Ok(_) => wasmer_result_t::WASMER_OK, + Err(e) => { + update_last_error(e); + wasmer_result_t::WASMER_ERROR + } + } +} + +/// Convenience function for setting up arguments and calling the Emscripten +/// main function. +/// +/// WARNING: +/// +/// Do not call this function on untrusted code when operating without +/// additional sandboxing in place. +/// Emscripten has access to many host system calls and therefore may do very +/// bad things. +#[no_mangle] +pub unsafe extern "C" fn wasmer_emscripten_call_main( + instance: *mut wasmer_instance_t, + args: *const wasmer_byte_array, + args_len: c_uint, +) -> wasmer_result_t { + if instance.is_null() || args.is_null() { + return wasmer_result_t::WASMER_ERROR; + } + let instance = &mut *(instance as *mut Instance); + + let arg_list = get_slice_checked(args, args_len as usize); + let arg_process_result: Result, _> = + arg_list.iter().map(|arg| arg.as_str()).collect(); + let arg_vec = match arg_process_result.as_ref() { + Ok(arg_vec) => arg_vec, + Err(err) => { + update_last_error(*err); + return wasmer_result_t::WASMER_ERROR; + } + }; + + let prog_name = if let Some(prog_name) = arg_vec.first() { + prog_name + } else { + update_last_error(CApiError { + msg: "First argument (program name) is required to execute Emscripten's main function" + .to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + + match wasmer_emscripten::emscripten_call_main(instance, prog_name, &arg_vec[1..]) { + Ok(_) => wasmer_result_t::WASMER_OK, + Err(e) => { + update_last_error(e); + wasmer_result_t::WASMER_ERROR + } + } +} + /// Create a `wasmer_import_object_t` with Emscripten imports, use /// `wasmer_emscripten_get_emscripten_globals` to get a /// `wasmer_emscripten_globals_t` from a `wasmer_module_t`. +/// +/// WARNING: +///1 +/// This `import_object_t` contains thin-wrappers around host system calls. +/// Do not use this to execute untrusted code without additional sandboxing. #[no_mangle] pub unsafe extern "C" fn wasmer_emscripten_generate_import_object( globals: *mut wasmer_emscripten_globals_t, diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index cbc7f3b1f..b62699da3 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -26,4 +26,5 @@ test-module-imports test-module-serialize test-tables test-validate -test-wasi-import-object \ No newline at end of file +test-wasi-import-object +test-emscripten-import-object \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 20f7dea13..f9aecd4d6 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -22,6 +22,11 @@ if (DEFINED WASI_TESTS) add_executable(test-wasi-import-object test-wasi-import-object.c) endif() +if (DEFINED EMSCRIPTEN_TESTS) + add_executable(test-emscripten-import-object test-emscripten-import-object.c) +endif() + + find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so wasmer_runtime_c_api.dll PATHS ${CMAKE_SOURCE_DIR}/../../../target/release/ @@ -74,6 +79,12 @@ if (DEFINED WASI_TESTS) add_test(test-wasi-import-object test-wasi-import-object) endif() +if (DEFINED EMSCRIPTEN_TESTS) + target_link_libraries(test-emscripten-import-object general ${WASMER_LIB}) + target_compile_options(test-emscripten-import-object PRIVATE ${COMPILER_OPTIONS}) + add_test(test-emscripten-import-object test-emscripten-import-object) +endif() + target_link_libraries(test-instantiate general ${WASMER_LIB}) target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS}) add_test(test-instantiate test-instantiate) diff --git a/lib/runtime-c-api/tests/assets/emscripten_hello_world.c b/lib/runtime-c-api/tests/assets/emscripten_hello_world.c new file mode 100644 index 000000000..998892f20 --- /dev/null +++ b/lib/runtime-c-api/tests/assets/emscripten_hello_world.c @@ -0,0 +1,10 @@ +#include + +int main(int argc, char *argv[]) { + printf("Hello, world\n"); + for ( int i = 0; i < argc; ++i ) { + printf("Arg %d: '%s'\n", i, argv[i]); + } + return 0; +} + diff --git a/lib/runtime-c-api/tests/assets/emscripten_hello_world.wasm b/lib/runtime-c-api/tests/assets/emscripten_hello_world.wasm new file mode 100644 index 000000000..96100d4e4 Binary files /dev/null and b/lib/runtime-c-api/tests/assets/emscripten_hello_world.wasm differ diff --git a/lib/runtime-c-api/tests/runtime_c_api_tests.rs b/lib/runtime-c-api/tests/runtime_c_api_tests.rs index ed4146363..a53706082 100644 --- a/lib/runtime-c-api/tests/runtime_c_api_tests.rs +++ b/lib/runtime-c-api/tests/runtime_c_api_tests.rs @@ -8,8 +8,10 @@ fn test_c_api() { ".", #[cfg(feature = "wasi")] "-DWASI_TESTS=ON", + #[cfg(feature = "emscripten")] + "-DEMSCRIPTEN_TESTS=ON", ]; - // we use -f so it doesn't fail if the fiel doesn't exist + // we use -f so it doesn't fail if the file doesn't exist run_command("rm", project_tests_dir, vec!["-f", "CMakeCache.txt"]); run_command("cmake", project_tests_dir, cmake_args); run_command("make", project_tests_dir, vec!["-Wdev", "-Werror=dev"]); diff --git a/lib/runtime-c-api/tests/test-emscripten-import-object.c b/lib/runtime-c-api/tests/test-emscripten-import-object.c new file mode 100644 index 000000000..03b196f59 --- /dev/null +++ b/lib/runtime-c-api/tests/test-emscripten-import-object.c @@ -0,0 +1,235 @@ +#include +#include "../wasmer.h" +#include +#include +#include + +static bool host_print_called = false; + +// Host function that will be imported into the Web Assembly Instance +void host_print(const wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) +{ + host_print_called = true; + const wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); + uint32_t mem_len = wasmer_memory_length(memory); + uint8_t *mem_bytes = wasmer_memory_data(memory); + printf("%.*s", len, mem_bytes + ptr); +} + +// Use the last_error API to retrieve error messages +void print_wasmer_error() +{ + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); +} + +// helper function to print byte array to stdout +void print_byte_array(wasmer_byte_array *arr) { + for (int i = 0; i < arr->bytes_len; ++i) { + putchar(arr->bytes[i]); + } +} + +int main() +{ + // Create a new func to hold the parameter and signature + // of our `host_print` host function + wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; + wasmer_value_tag returns_sig[] = {}; + wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) host_print, params_sig, 2, returns_sig, 0); + + // Create module name for our imports + // represented in bytes for UTF-8 compatability + const char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = (const uint8_t *) module_name; + module_name_bytes.bytes_len = strlen(module_name); + + // Define a function import + const char *import_name = "host_print"; + wasmer_byte_array import_name_bytes; + import_name_bytes.bytes = (const uint8_t *) import_name; + import_name_bytes.bytes_len = strlen(import_name); + wasmer_import_t func_import; + func_import.module_name = module_name_bytes; + func_import.import_name = import_name_bytes; + func_import.tag = WASM_FUNCTION; + func_import.value.func = func; + + // Define a memory import + const char *import_memory_name = "memory"; + wasmer_byte_array import_memory_name_bytes; + import_memory_name_bytes.bytes = (const uint8_t *) import_memory_name; + import_memory_name_bytes.bytes_len = strlen(import_memory_name); + wasmer_import_t memory_import; + memory_import.module_name = module_name_bytes; + memory_import.import_name = import_memory_name_bytes; + memory_import.tag = WASM_MEMORY; + wasmer_memory_t *memory = NULL; + wasmer_limits_t descriptor; + descriptor.min = 256; + wasmer_limit_option_t max; + max.has_some = true; + max.some = 256; + descriptor.max = max; + wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); + if (memory_result != WASMER_OK) + { + print_wasmer_error(); + } + memory_import.value.memory = memory; + + // Define a global import + const char *import_global_name = "__memory_base"; + wasmer_byte_array import_global_name_bytes; + import_global_name_bytes.bytes = (const uint8_t *) import_global_name; + import_global_name_bytes.bytes_len = strlen(import_global_name); + wasmer_import_t global_import; + global_import.module_name = module_name_bytes; + global_import.import_name = import_global_name_bytes; + global_import.tag = WASM_GLOBAL; + wasmer_value_t val; + val.tag = WASM_I32; + val.value.I32 = 1024; + wasmer_global_t *global = wasmer_global_new(val, false); + global_import.value.global = global; + + // Define a table import + const char *import_table_name = "table"; + wasmer_byte_array import_table_name_bytes; + import_table_name_bytes.bytes = (const uint8_t *) import_table_name; + import_table_name_bytes.bytes_len = strlen(import_table_name); + wasmer_import_t table_import; + table_import.module_name = module_name_bytes; + table_import.import_name = import_table_name_bytes; + table_import.tag = WASM_TABLE; + wasmer_table_t *table = NULL; + wasmer_limits_t table_descriptor; + table_descriptor.min = 256; + wasmer_limit_option_t table_max; + table_max.has_some = true; + table_max.some = 256; + table_descriptor.max = table_max; + wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor); + if (table_result != WASMER_OK) + { + print_wasmer_error(); + } + table_import.value.table = table; + + + // Create arbitrary arguments for our program + + + // Read the Wasm file bytes. + FILE *file = fopen("assets/emscripten_hello_world.wasm", "r"); + assert(file); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_module_t *module = NULL; + // Compile the WebAssembly module + wasmer_result_t compile_result = wasmer_compile(&module, bytes, len); + printf("Compile result: %d\n", compile_result); + + if (compile_result != WASMER_OK) + { + print_wasmer_error(); + } + + assert(compile_result == WASMER_OK); + + // Set up data for Emscripten + wasmer_emscripten_globals_t *emscripten_globals = wasmer_emscripten_get_emscripten_globals(module); + + if (!emscripten_globals) + { + print_wasmer_error(); + } + assert(emscripten_globals); + + // Create the Emscripten import object + wasmer_import_object_t *import_object = + wasmer_emscripten_generate_import_object(emscripten_globals); + + // Create our imports + wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import}; + int imports_len = sizeof(imports) / sizeof(imports[0]); + // Add our imports to the import object + wasmer_import_object_extend(import_object, imports, imports_len); + + // Instantiatoe the module with our import_object + wasmer_instance_t *instance = NULL; + wasmer_result_t instantiate_result = wasmer_module_import_instantiate(&instance, module, import_object); + printf("Instantiate result: %d\n", instantiate_result); + + if (instantiate_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(instantiate_result == WASMER_OK); + + // Set up emscripten to be called + wasmer_result_t setup_result = wasmer_emscripten_set_up_emscripten(instance, emscripten_globals); + + if (setup_result != WASMER_OK) + { + print_wasmer_error(); + } + + + const char *emscripten_prog_name = "emscripten_test_program"; + const char *emscripten_first_arg = "--help"; + wasmer_byte_array args[] = { + { .bytes = (const uint8_t *) emscripten_prog_name, + .bytes_len = strlen(emscripten_prog_name) }, + { .bytes = (const uint8_t *) emscripten_first_arg, + .bytes_len = strlen(emscripten_first_arg) } + }; + int emscripten_argc = sizeof(args) / sizeof(args[0]); + + wasmer_result_t main_result = wasmer_emscripten_call_main(instance, args, emscripten_argc); + + printf("Main result: %d\n", main_result); + assert(main_result == WASMER_OK); + + + wasmer_import_object_iter_t *func_iter = wasmer_import_object_iterate_functions(import_object); + + puts("Functions in import object:"); + while ( !wasmer_import_object_iter_at_end(func_iter) ) { + wasmer_import_t import; + wasmer_result_t result = wasmer_import_object_iter_next(func_iter, &import); + assert(result == WASMER_OK); + + print_byte_array(&import.module_name); + putchar(' '); + print_byte_array(&import.import_name); + putchar('\n'); + + assert(import.tag == WASM_FUNCTION); + assert(import.value.func); + wasmer_import_object_imports_destroy(&import, 1); + } + wasmer_import_object_iter_destroy(func_iter); + + // Use *_destroy methods to cleanup as specified in the header documentation + wasmer_emscripten_destroy_emscripten_globals(emscripten_globals); + wasmer_import_func_destroy(func); + wasmer_global_destroy(global); + wasmer_memory_destroy(memory); + wasmer_table_destroy(table); + wasmer_instance_destroy(instance); + wasmer_import_object_destroy(import_object); + wasmer_module_destroy(module); + + return 0; +} + diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index d313f61a9..5eacbbd76 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -14,6 +14,7 @@ #endif #endif +#define WASMER_EMSCRIPTEN_ENABLED #endif // WASMER_H_MACROS @@ -74,6 +75,15 @@ typedef struct { } wasmer_module_t; +typedef struct { + +} wasmer_instance_t; + +typedef struct { + const uint8_t *bytes; + uint32_t bytes_len; +} wasmer_byte_array; + #if defined(WASMER_EMSCRIPTEN_ENABLED) /** * Type used to construct an import_object_t with Emscripten imports. @@ -94,11 +104,6 @@ typedef struct { } wasmer_export_descriptor_t; -typedef struct { - const uint8_t *bytes; - uint32_t bytes_len; -} wasmer_byte_array; - /** * Opaque pointer to `NamedExportDescriptors`. */ @@ -191,10 +196,6 @@ typedef struct { typedef struct { -} wasmer_instance_t; - -typedef struct { - } wasmer_instance_context_t; typedef struct { @@ -256,6 +257,23 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module, uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/** + * Convenience function for setting up arguments and calling the Emscripten + * main function. + * + * WARNING: + * + * Do not call this function on untrusted code when operating without + * additional sandboxing in place. + * Emscripten has access to many host system calls and therefore may do very + * bad things. + */ +wasmer_result_t wasmer_emscripten_call_main(wasmer_instance_t *instance, + const wasmer_byte_array *args, + unsigned int args_len); +#endif + #if defined(WASMER_EMSCRIPTEN_ENABLED) /** * Destroy `wasmer_emscrpten_globals_t` created by @@ -269,6 +287,11 @@ void wasmer_emscripten_destroy_emscripten_globals(wasmer_emscripten_globals_t *g * Create a `wasmer_import_object_t` with Emscripten imports, use * `wasmer_emscripten_get_emscripten_globals` to get a * `wasmer_emscripten_globals_t` from a `wasmer_module_t`. + * + * WARNING: + *1 + * This `import_object_t` contains thin-wrappers around host system calls. + * Do not use this to execute untrusted code without additional sandboxing. */ wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals); #endif @@ -280,6 +303,18 @@ wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscript wasmer_emscripten_globals_t *wasmer_emscripten_get_emscripten_globals(const wasmer_module_t *module); #endif +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/** + * Execute global constructors (required if the module is compiled from C++) + * and sets up the internal environment. + * + * This function sets the data pointer in the same way that + * [`wasmer_instance_context_data_set`] does. + */ +wasmer_result_t wasmer_emscripten_set_up_emscripten(wasmer_instance_t *instance, + wasmer_emscripten_globals_t *globals); +#endif + /** * Gets export descriptor kind */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index a81b8c77a..7a0e6dae2 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -14,6 +14,7 @@ #endif #endif +#define WASMER_EMSCRIPTEN_ENABLED #endif // WASMER_H_MACROS @@ -61,6 +62,15 @@ struct wasmer_module_t { }; +struct wasmer_instance_t { + +}; + +struct wasmer_byte_array { + const uint8_t *bytes; + uint32_t bytes_len; +}; + #if defined(WASMER_EMSCRIPTEN_ENABLED) /// Type used to construct an import_object_t with Emscripten imports. struct wasmer_emscripten_globals_t { @@ -77,11 +87,6 @@ struct wasmer_export_descriptor_t { }; -struct wasmer_byte_array { - const uint8_t *bytes; - uint32_t bytes_len; -}; - /// Opaque pointer to `NamedExportDescriptors`. struct wasmer_export_descriptors_t { @@ -162,10 +167,6 @@ struct wasmer_import_object_iter_t { }; -struct wasmer_instance_t { - -}; - struct wasmer_instance_context_t { }; @@ -223,6 +224,21 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module, uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Convenience function for setting up arguments and calling the Emscripten +/// main function. +/// +/// WARNING: +/// +/// Do not call this function on untrusted code when operating without +/// additional sandboxing in place. +/// Emscripten has access to many host system calls and therefore may do very +/// bad things. +wasmer_result_t wasmer_emscripten_call_main(wasmer_instance_t *instance, + const wasmer_byte_array *args, + unsigned int args_len); +#endif + #if defined(WASMER_EMSCRIPTEN_ENABLED) /// Destroy `wasmer_emscrpten_globals_t` created by /// `wasmer_emscripten_get_emscripten_globals`. @@ -233,6 +249,11 @@ void wasmer_emscripten_destroy_emscripten_globals(wasmer_emscripten_globals_t *g /// Create a `wasmer_import_object_t` with Emscripten imports, use /// `wasmer_emscripten_get_emscripten_globals` to get a /// `wasmer_emscripten_globals_t` from a `wasmer_module_t`. +/// +/// WARNING: +///1 +/// This `import_object_t` contains thin-wrappers around host system calls. +/// Do not use this to execute untrusted code without additional sandboxing. wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals); #endif @@ -241,6 +262,16 @@ wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscript wasmer_emscripten_globals_t *wasmer_emscripten_get_emscripten_globals(const wasmer_module_t *module); #endif +#if defined(WASMER_EMSCRIPTEN_ENABLED) +/// Execute global constructors (required if the module is compiled from C++) +/// and sets up the internal environment. +/// +/// This function sets the data pointer in the same way that +/// [`wasmer_instance_context_data_set`] does. +wasmer_result_t wasmer_emscripten_set_up_emscripten(wasmer_instance_t *instance, + wasmer_emscripten_globals_t *globals); +#endif + /// Gets export descriptor kind wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_);