diff --git a/.gitignore b/.gitignore index 57d60419..fbd9b8e3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,10 @@ /.idea **/cmake-build-*/ **/*build/ +*.obj +*.a +*.so + core/deps/** core/shared/mem-alloc/tlsf core/app-framework/wgl @@ -12,6 +16,9 @@ wamr-sdk/out/ wamr-sdk/runtime/build_runtime_sdk/ test-tools/host-tool/bin/ product-mini/app-samples/hello-world/test.wasm +product-mini/platforms/linux-sgx/enclave-sample/App/ +product-mini/platforms/linux-sgx/enclave-sample/Enclave/ +product-mini/platforms/linux-sgx/enclave-sample/iwasm build_out tests/wamr-test-suites/workspace diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index ec94ffff..f8766dde 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1284,7 +1284,7 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, #if WASM_ENABLE_LIBC_WASI != 0 if (!strcmp(import_funcs[i].module_name, "wasi_unstable") || !strcmp(import_funcs[i].module_name, "wasi_snapshot_preview1")) - module->is_wasi_module = true; + module->import_wasi_api = true; #endif } @@ -2925,7 +2925,7 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, module->comp_data = comp_data; #if WASM_ENABLE_LIBC_WASI != 0 - module->is_wasi_module = comp_data->wasm_module->is_wasi_module; + module->import_wasi_api = comp_data->wasm_module->import_wasi_api; #endif return module; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index e2eb9496..7cad5d3b 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1059,7 +1059,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, #if WASM_ENABLE_BULK_MEMORY != 0 #if WASM_ENABLE_LIBC_WASI != 0 - if (!module->is_wasi_module) { + if (!module->import_wasi_api) { #endif /* Only execute the memory init function for main instance because the data segments will be dropped once initialized. diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 08a7a908..8046880a 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -256,7 +256,7 @@ typedef struct AOTModule { #if WASM_ENABLE_LIBC_WASI != 0 WASIArguments wasi_args; - bool is_wasi_module; + bool import_wasi_api; #endif #if WASM_ENABLE_DEBUG_AOT != 0 void *elf_hdr; diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 326f008d..4cc8543b 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -48,10 +48,6 @@ static union { /** * Implementation of wasm_application_execute_main() */ - -static WASMFunctionInstanceCommon * -resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name); - static bool check_main_func_type(const WASMType *type) { @@ -96,23 +92,29 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, bool ret, is_import_func = true; #if WASM_ENABLE_LIBC_WASI != 0 - if (wasm_runtime_is_wasi_mode(module_inst)) { - /* In wasi mode, we should call function named "_start" - which initializes the wasi envrionment and then calls - the actual main function. Directly call main function - may cause exception thrown. */ - if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) - return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, - 0, NULL); - /* If no start function was found, we execute - the main function as normal */ + /* In wasi mode, we should call function named "_start" + which initializes the wasi envrionment and then calls + the actual main function. Directly call main function + may cause exception thrown. */ + if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) { + return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, 0, + NULL); } #endif /* end of WASM_ENABLE_LIBC_WASI */ - if (!(func = resolve_function(module_inst, "main")) - && !(func = resolve_function(module_inst, "__main_argc_argv")) - && !(func = resolve_function(module_inst, "_main"))) { - wasm_runtime_set_exception(module_inst, "lookup main function failed"); + if (!(func = wasm_runtime_lookup_function(module_inst, "main", NULL)) + && !(func = wasm_runtime_lookup_function(module_inst, + "__main_argc_argv", NULL)) + && !(func = wasm_runtime_lookup_function(module_inst, "_main", NULL))) { +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_runtime_set_exception( + module_inst, "lookup the entry point symbol (like _start, main, " + "_main, __main_argc_argv) failed"); +#else + wasm_runtime_set_exception(module_inst, + "lookup the entry point symbol (like main, " + "_main, __main_argc_argv) failed"); +#endif return false; } @@ -238,21 +240,23 @@ parse_function_name(char *orig_function_name, char **p_module_name, * Implementation of wasm_application_execute_func() */ -static WASMFunctionInstanceCommon * -resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name) +static bool +resolve_function(WASMModuleInstanceCommon *module_inst, const char *name, + WASMFunctionInstanceCommon **out_func, + WASMModuleInstanceCommon **out_module_inst) { - uint32 i = 0; - WASMFunctionInstanceCommon *ret = NULL; + WASMFunctionInstanceCommon *target_func = NULL; + WASMModuleInstanceCommon *target_inst = NULL; + #if WASM_ENABLE_MULTI_MODULE != 0 - WASMModuleInstance *sub_module_inst = NULL; + char *function_name = NULL; char *orig_name = NULL; char *sub_module_name = NULL; - char *function_name = NULL; uint32 length = (uint32)(strlen(name) + 1); orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0); if (!orig_name) { - return NULL; + goto LEAVE; } strncpy(orig_name, name, length); @@ -264,53 +268,33 @@ resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name) LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name); if (sub_module_name) { - sub_module_inst = get_sub_module_inst((WASMModuleInstance *)module_inst, - sub_module_name); - if (!sub_module_inst) { + target_inst = (WASMModuleInstanceCommon *)get_sub_module_inst( + (WASMModuleInstance *)module_inst, sub_module_name); + if (!target_inst) { LOG_DEBUG("can not find a sub module named %s", sub_module_name); goto LEAVE; } } + else { + target_inst = module_inst; + } #else const char *function_name = name; + target_inst = module_inst; #endif -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst; - -#if WASM_ENABLE_MULTI_MODULE != 0 - wasm_inst = sub_module_inst ? sub_module_inst : wasm_inst; -#endif /* WASM_ENABLE_MULTI_MODULE */ - - for (i = 0; i < wasm_inst->export_func_count; i++) { - if (!strcmp(wasm_inst->export_functions[i].name, function_name)) { - ret = wasm_inst->export_functions[i].function; - break; - } - } - } -#endif /* WASM_ENABLE_INTERP */ - -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst; - AOTFunctionInstance *export_funcs = - (AOTFunctionInstance *)aot_inst->export_funcs.ptr; - for (i = 0; i < aot_inst->export_func_count; i++) { - if (!strcmp(export_funcs[i].func_name, function_name)) { - ret = &export_funcs[i]; - break; - } - } - } -#endif + target_func = + wasm_runtime_lookup_function(target_inst, function_name, NULL); #if WASM_ENABLE_MULTI_MODULE != 0 LEAVE: - wasm_runtime_free(orig_name); + if (orig_name) + wasm_runtime_free(orig_name); #endif - return ret; + + *out_func = target_func; + *out_module_inst = target_inst; + return target_func; } union ieee754_float { @@ -358,7 +342,8 @@ bool wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, const char *name, int32 argc, char *argv[]) { - WASMFunctionInstanceCommon *func; + WASMFunctionInstanceCommon *target_func; + WASMModuleInstanceCommon *target_inst; WASMType *type = NULL; uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; int32 i, p, module_type; @@ -368,31 +353,15 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, bh_assert(argc >= 0); LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc); - func = resolve_function(module_inst, name); - if (!func) { + if (!resolve_function(module_inst, name, &target_func, &target_inst)) { snprintf(buf, sizeof(buf), "lookup function %s failed", name); wasm_runtime_set_exception(module_inst, buf); goto fail; } -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - WASMFunctionInstance *wasm_func = (WASMFunctionInstance *)func; - if (wasm_func->is_import_func -#if WASM_ENABLE_MULTI_MODULE != 0 - && !wasm_func->import_func_inst -#endif - ) { - snprintf(buf, sizeof(buf), "lookup function %s failed", name); - wasm_runtime_set_exception(module_inst, buf); - goto fail; - } - } -#endif - - module_type = module_inst->module_type; - type = wasm_runtime_get_function_type(func, module_type); + module_type = target_inst->module_type; + type = wasm_runtime_get_function_type(target_func, module_type); if (!type) { LOG_ERROR("invalid module instance type"); @@ -408,7 +377,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); - if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, NULL, 0)))) { + if ((!(argv1 = runtime_malloc((uint32)total_size, target_inst, NULL, 0)))) { goto fail; } @@ -538,7 +507,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, void *extern_obj = (void *)(uintptr_t)val; uint32 externref_idx; - if (!wasm_externref_obj2ref(module_inst, extern_obj, + if (!wasm_externref_obj2ref(target_inst, extern_obj, &externref_idx)) { wasm_runtime_set_exception( module_inst, "map extern object to ref failed"); @@ -563,8 +532,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, bh_assert(p == (int32)argc1); wasm_runtime_set_exception(module_inst, NULL); - if (!wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, argc1, - argv1)) { + if (!wasm_runtime_create_exec_env_and_call_wasm(target_inst, target_func, + argc1, argv1)) { goto fail; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index e97b81a8..af2f5930 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2294,13 +2294,13 @@ wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode - && ((WASMModuleInstance *)module_inst)->module->is_wasi_module) + && ((WASMModuleInstance *)module_inst)->module->import_wasi_api) return true; #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT && ((AOTModule *)((AOTModuleInstance *)module_inst)->aot_module.ptr) - ->is_wasi_module) + ->import_wasi_api) return true; #endif return false; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 653e9065..6db1a705 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -403,7 +403,7 @@ struct WASMModule { #if WASM_ENABLE_LIBC_WASI != 0 WASIArguments wasi_args; - bool is_wasi_module; + bool import_wasi_api; #endif #if WASM_ENABLE_MULTI_MODULE != 0 diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 21f828da..d0d3707b 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -647,11 +647,11 @@ adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) static WASMExport * wasm_loader_find_export(const WASMModule *module, const char *module_name, const char *field_name, uint8 export_kind, - uint32 export_index_boundary, char *error_buf, - uint32 error_buf_size) + char *error_buf, uint32 error_buf_size) { WASMExport *export; uint32 i; + uint32 export_index_boundary = 0; for (i = 0, export = module->exports; i < module->export_count; ++i, ++export) { @@ -674,6 +674,27 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name, return NULL; } + switch (export_kind) { + case EXPORT_KIND_FUNC: + export_index_boundary = + module->import_function_count + module->function_count; + break; + case EXPORT_KIND_GLOBAL: + export_index_boundary = + module->import_global_count + module->global_count; + break; + case EXPORT_KIND_MEMORY: + export_index_boundary = + module->import_memory_count + module->memory_count; + break; + case EXPORT_KIND_TABLE: + export_index_boundary = + module->import_table_count + module->table_count; + break; + default: + bh_assert(0); + } + if (export->index >= export_index_boundary) { LOG_DEBUG("%s in the module %s is out of index (%d >= %d )", field_name, module_name, export->index, export_index_boundary); @@ -704,10 +725,9 @@ wasm_loader_resolve_function(const char *module_name, const char *function_name, } module = (WASMModule *)module_reg; - export = wasm_loader_find_export( - module, module_name, function_name, EXPORT_KIND_FUNC, - module->import_function_count + module->function_count, error_buf, - error_buf_size); + export = + wasm_loader_find_export(module, module_name, function_name, + EXPORT_KIND_FUNC, error_buf, error_buf_size); if (!export) { return NULL; } @@ -755,10 +775,9 @@ wasm_loader_resolve_table(const char *module_name, const char *table_name, } module = (WASMModule *)module_reg; - export = wasm_loader_find_export( - module, module_name, table_name, EXPORT_KIND_TABLE, - module->table_count + module->import_table_count, error_buf, - error_buf_size); + export = + wasm_loader_find_export(module, module_name, table_name, + EXPORT_KIND_TABLE, error_buf, error_buf_size); if (!export) { return NULL; } @@ -800,10 +819,9 @@ wasm_loader_resolve_memory(const char *module_name, const char *memory_name, } module = (WASMModule *)module_reg; - export = wasm_loader_find_export( - module, module_name, memory_name, EXPORT_KIND_MEMORY, - module->import_memory_count + module->memory_count, error_buf, - error_buf_size); + export = + wasm_loader_find_export(module, module_name, memory_name, + EXPORT_KIND_MEMORY, error_buf, error_buf_size); if (!export) { return NULL; } @@ -846,10 +864,9 @@ wasm_loader_resolve_global(const char *module_name, const char *global_name, } module = (WASMModule *)module_reg; - export = wasm_loader_find_export( - module, module_name, global_name, EXPORT_KIND_GLOBAL, - module->import_global_count + module->global_count, error_buf, - error_buf_size); + export = + wasm_loader_find_export(module, module_name, global_name, + EXPORT_KIND_GLOBAL, error_buf, error_buf_size); if (!export) { return NULL; } @@ -969,7 +986,7 @@ load_depended_module(const WASMModule *parent_module, } sub_module = - wasm_loader_load(buffer, buffer_size, error_buf, error_buf_size); + wasm_loader_load(buffer, buffer_size, false, error_buf, error_buf_size); if (!sub_module) { LOG_DEBUG("error: can not load the sub_module %s", sub_module_name); /* others will be destroyed in runtime_destroy() */ @@ -1736,7 +1753,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (!strcmp(import->u.names.module_name, "wasi_unstable") || !strcmp(import->u.names.module_name, "wasi_snapshot_preview1")) { - module->is_wasi_module = true; + module->import_wasi_api = true; break; } } @@ -3440,9 +3457,129 @@ fail: return false; } +#if (WASM_ENABLE_MULTI_MODULE != 0) && (WASM_ENABLE_LIBC_WASI != 0) +/* + * refer to + * https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md + */ +static bool +check_wasi_abi_compatibility(const WASMModule *module, bool main_module, + char *error_buf, uint32 error_buf_size) +{ + /* + * need to handle: + * - non-wasi compatiable modules + * - a fake wasi compatiable module + * - a command acts as a main_module + * - a command acts as a sub_module + * - a reactor acts as a main_module + * - a reactor acts as a sub_module + * + * be careful with: + * wasi compatiable modules(command/reactor) which don't import any wasi + * APIs. usually, a command has to import a "prox_exit" at least. but a + * reactor can depend on nothing. At the same time, each has its own entry + * point. + * + * observations: + * - clang always injects `_start` into a command + * - clang always injects `_initialize` into a reactor + * - `iwasm -f` allows to run a function in the reactor + * + * strong assumptions: + * - no one will define either `_start` or `_initialize` on purpose + * - `_start` should always be `void _start(void)` + * - `_initialize` should always be `void _initialize(void)` + */ + + WASMExport *initialize = NULL, *memory = NULL, *start = NULL; + + /* (func (export "_start") (...) */ + start = wasm_loader_find_export(module, "", "_start", EXPORT_KIND_FUNC, + error_buf, error_buf_size); + if (start) { + WASMType *func_type = + module->functions[start->index - module->import_function_count] + ->func_type; + if (func_type->param_count || func_type->result_count) { + set_error_buf(error_buf, error_buf_size, + "The builtin _start() is with a wrong signature"); + return false; + } + } + + /* (func (export "_initialize") (...) */ + initialize = wasm_loader_find_export( + module, "", "_initialize", EXPORT_KIND_FUNC, error_buf, error_buf_size); + if (initialize) { + WASMType *func_type = + module->functions[initialize->index - module->import_function_count] + ->func_type; + if (func_type->param_count || func_type->result_count) { + set_error_buf( + error_buf, error_buf_size, + "The builtin _initiazlie() is with a wrong signature"); + return false; + } + } + + /* filter out non-wasi compatiable modules */ + if (!module->import_wasi_api && !start && !initialize) { + return true; + } + + /* should have one at least */ + if (module->import_wasi_api && !start && !initialize) { + set_error_buf( + error_buf, error_buf_size, + "A module with WASI apis should be either a command or a reactor"); + return false; + } + + /* + * there is at least one of `_start` and `_initialize` in below cases. + * according to the assumption, they should be all wasi compatiable + */ + + /* always can not have both at the same time */ + if (start && initialize) { + set_error_buf( + error_buf, error_buf_size, + "Neither a command nor a reactor can have both at the same time"); + return false; + } + + /* filter out commands (with `_start`) cases */ + if (start && !main_module) { + set_error_buf(error_buf, error_buf_size, + "A command(with _start) can not be a sud-module"); + return false; + } + + /* + * it is ok a reactor acts as a main module, + * so skip the check about (with `_initialize`) + */ + + memory = wasm_loader_find_export(module, "", "memory", EXPORT_KIND_MEMORY, + error_buf, error_buf_size); + if (!memory) { + set_error_buf( + error_buf, error_buf_size, + "A module with WASI apis should export memory by default"); + return false; + } + + return true; +} +#endif + WASMModule * -wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, - uint32 error_buf_size) +wasm_loader_load(const uint8 *buf, uint32 size, +#if WASM_ENABLE_MULTI_MODULE != 0 + bool main_module, +#endif + char *error_buf, uint32 error_buf_size) { WASMModule *module = create_module(error_buf, error_buf_size); if (!module) { @@ -3458,6 +3595,14 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, goto fail; } +#if (WASM_ENABLE_MULTI_MODULE != 0) && (WASM_ENABLE_LIBC_WASI != 0) + /* do a check about WASI Application ABI */ + if (!check_wasi_abi_compatibility(module, main_module, error_buf, + error_buf_size)) { + goto fail; + } +#endif + LOG_VERBOSE("Load module success.\n"); return module; diff --git a/core/iwasm/interpreter/wasm_loader.h b/core/iwasm/interpreter/wasm_loader.h index 5f245f60..d799a4ab 100644 --- a/core/iwasm/interpreter/wasm_loader.h +++ b/core/iwasm/interpreter/wasm_loader.h @@ -24,8 +24,11 @@ extern "C" { * @return return module loaded, NULL if failed */ WASMModule * -wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, - uint32 error_buf_size); +wasm_loader_load(const uint8 *buf, uint32 size, +#if WASM_ENABLE_MULTI_MODULE != 0 + bool main_module, +#endif + char *error_buf, uint32 error_buf_size); /** * Load a WASM module from a specified WASM section list. diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 9bf19713..c3ccd55a 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -851,7 +851,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (!strcmp(import->u.names.module_name, "wasi_unstable") || !strcmp(import->u.names.module_name, "wasi_snapshot_preview1")) { - module->is_wasi_module = true; + module->import_wasi_api = true; break; } } @@ -2120,7 +2120,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } -#if WASM_ENABLE_MULTI_MODULE == 0 if (module->import_memory_count) { memory_import = &module->import_memories[0].u.memory; /* Memory init page count cannot be larger than 65536, we don't @@ -2128,6 +2127,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, memory_import->num_bytes_per_page *= memory_import->init_page_count; memory_import->init_page_count = memory_import->max_page_count = 1; } + if (module->memory_count) { /* Memory init page count cannot be larger than 65536, we don't check integer overflow again. */ @@ -2135,7 +2135,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, memory->num_bytes_per_page *= memory->init_page_count; memory->init_page_count = memory->max_page_count = 1; } -#endif } #if WASM_ENABLE_MEMORY_TRACING != 0 @@ -2159,9 +2158,6 @@ create_module(char *error_buf, uint32 error_buf_size) /* Set start_function to -1, means no start function */ module->start_function = (uint32)-1; -#if WASM_ENABLE_MULTI_MODULE != 0 - module->import_module_list = &module->import_module_list_head; -#endif return module; } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f12c9ebf..2de827c8 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -47,7 +47,11 @@ set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, ...) WASMModule * wasm_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) { - return wasm_loader_load(buf, size, error_buf, error_buf_size); + return wasm_loader_load(buf, size, +#if WASM_ENABLE_MULTI_MODULE != 0 + true, +#endif + error_buf, error_buf_size); } WASMModule * @@ -105,7 +109,7 @@ memories_deinstantiate(WASMModuleInstance *module_inst, for (i = 0; i < count; i++) { if (memories[i]) { #if WASM_ENABLE_MULTI_MODULE != 0 - if (memories[i]->owner != module_inst) + if (i < module_inst->module->import_memory_count) continue; #endif #if WASM_ENABLE_SHARED_MEMORY != 0 @@ -384,13 +388,6 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, memories_deinstantiate(module_inst, memories, memory_count); return NULL; } -#if WASM_ENABLE_MULTI_MODULE != 0 - /* The module of the import memory is a builtin module, and - the memory is created by current module, set its owner - to current module, so the memory can be destroyed in - memories_deinstantiate. */ - memory->owner = module_inst; -#endif } } @@ -404,9 +401,6 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, memories_deinstantiate(module_inst, memories, memory_count); return NULL; } -#if WASM_ENABLE_MULTI_MODULE != 0 - memory->owner = module_inst; -#endif } if (mem_index == 0) { @@ -1007,15 +1001,17 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, bh_list_first_elem(module->import_module_list); while (sub_module_list_node) { - WASMSubModInstNode *sub_module_inst_list_node; + WASMSubModInstNode *sub_module_inst_list_node = NULL; WASMModule *sub_module = (WASMModule *)sub_module_list_node->module; - WASMModuleInstance *sub_module_inst = + WASMModuleInstance *sub_module_inst = NULL; + + sub_module_inst = wasm_instantiate(sub_module, false, stack_size, heap_size, error_buf, error_buf_size); if (!sub_module_inst) { LOG_DEBUG("instantiate %s failed", sub_module_list_node->module_name); - return false; + goto failed; } sub_module_inst_list_node = runtime_malloc(sizeof(WASMSubModInstNode), @@ -1023,8 +1019,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, if (!sub_module_inst_list_node) { LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d", sizeof(WASMSubModInstNode)); - wasm_deinstantiate(sub_module_inst, false); - return false; + goto failed; } sub_module_inst_list_node->module_inst = sub_module_inst; @@ -1036,6 +1031,39 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, (void)ret; sub_module_list_node = bh_list_elem_next(sub_module_list_node); + +#if WASM_ENABLE_LIBC_WASI != 0 + { + /* + * reactor instances may assume that _initialize will be called by + * the environment at most once, and that none of their other + * exports are accessed before that call. + * + * let the loader decide how to act if there is no _initialize + * in a reactor + */ + WASMFunctionInstance *initialize = + wasm_lookup_function(sub_module_inst, "_initialize", NULL); + if (initialize + && !wasm_create_exec_env_and_call_function( + sub_module_inst, initialize, 0, NULL, false)) { + set_error_buf(error_buf, error_buf_size, + "Call _initialize failed "); + goto failed; + } + } +#endif + + continue; + failed: + if (sub_module_inst_list_node) { + bh_list_remove(sub_module_inst_list, sub_module_inst_list_node); + wasm_runtime_free(sub_module_inst_list_node); + } + + if (sub_module_inst) + wasm_deinstantiate(sub_module_inst, false); + return false; } return true; @@ -1518,7 +1546,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, #if WASM_ENABLE_BULK_MEMORY != 0 #if WASM_ENABLE_LIBC_WASI != 0 - if (!module->is_wasi_module) { + if (!module->import_wasi_api) { #endif /* Only execute the memory init function for main instance because the data segments will be dropped once initialized. diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 27d63068..40e9af14 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -40,11 +40,6 @@ struct WASMMemoryInstance { /* The heap created */ void *heap_handle; -#if WASM_ENABLE_MULTI_MODULE != 0 - /* to indicate which module instance create it */ - WASMModuleInstance *owner; -#endif - #if WASM_ENABLE_SHARED_MEMORY != 0 /* mutex lock for the memory, used in atomic operation */ korp_mutex mem_lock; diff --git a/samples/multi-module/CMakeLists.txt b/samples/multi-module/CMakeLists.txt index 76e326ed..48f67e1b 100644 --- a/samples/multi-module/CMakeLists.txt +++ b/samples/multi-module/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required (VERSION 2.8...3.16) project(multi_module) ################ runtime settings ################ @@ -41,7 +41,7 @@ set(WAMR_BUILD_INTERP 1) set(WAMR_BUILD_AOT 0) set(WAMR_BUILD_JIT 0) set(WAMR_BUILD_LIBC_BUILTIN 1) -set(WAMR_BUILD_LIBC_WASI 0) +set(WAMR_BUILD_LIBC_WASI 1) set(WAMR_BUILD_MULTI_MODULE 1) # compiling and linking flags @@ -66,8 +66,79 @@ add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) ################ application related ################ ################ WASM MODULES +include(ExternalProject) + +message(CHECK_START "Detecting WASI-SDK") +if(NOT (DEFINED WASI_SDK_DIR OR DEFINED CACHE{WASI_SDK_DIR})) + find_path(WASI_SDK_PARENT + wasi-sdk + PATHS /opt + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + if(WASI_SDK_PARENT) + set(WASI_SDK_DIR ${WASI_SDK_PARENT}/wasi-sdk) + endif() +endif() +if(WASI_SDK_DIR) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() + +message(CHECK_START "Detecting WASI_TOOLCHAIN_FILE at ${WASI_SDK_DIR}") +find_file(WASI_TOOLCHAIN_FILE + wasi-sdk.cmake + PATHS "${WASI_SDK_DIR}/share/cmake" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH +) +if(WASI_TOOLCHAIN_FILE) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() + +message(CHECK_START "Detecting WASI_SYS_ROOT at ${WASI_SDK_DIR}") +find_path(WASI_SYS_ROOT + wasi-sysroot + PATHS "${WASI_SDK_DIR}/share" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH +) +if(WASI_SYS_ROOT) + message(CHECK_PASS "found") + set(WASI_SYS_ROOT ${WASI_SYS_ROOT}/wasi-sysroot) +else() + message(CHECK_FAIL "not found") +endif() + +if(NOT EXISTS ${WASI_SDK_DIR} OR NOT EXISTS ${WASI_TOOLCHAIN_FILE} OR NOT EXISTS ${WASI_SYS_ROOT}) + message(FATAL_ERROR "Please set the absolute path of wasi-sdk with \'cmake -DWASI_SDK_HOME=XXX\'") +else() + message(STATUS "WASI_SDK_DIR is ${WASI_SDK_DIR}") + message(STATUS "WASI_TOOLCHAIN_FILE is ${WASI_TOOLCHAIN_FILE}") + message(STATUS "WASI_SYS_ROOT is ${WASI_SYS_ROOT}") +endif() + # .c -> .wasm -add_subdirectory(wasm-apps) +ExternalProject_Add(WASM_MODULE + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps + UPDATE_COMMAND "" + PATCH_COMMAND "" + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASI_SDK_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} + -DCMAKE_SYSROOT=${WASI_SYS_ROOT} + -S ${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps + BUILD_COMMAND ${CMAKE_COMMAND} --build . + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy + ./mA.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/ + ./mB.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/ + ./mC.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/ + ./mD.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/ + ./mE.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/ +) ################ NATIVE include_directories(${CMAKE_CURRENT_LIST_DIR}/src) @@ -75,7 +146,7 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) add_executable(multi_module src/main.c ${UNCOMMON_SHARED_SOURCE}) -add_dependencies(multi_module vmlib wasm-modules) +add_dependencies(multi_module vmlib WASM_MODULE) # libraries target_link_libraries(multi_module PRIVATE vmlib -lpthread -lm) diff --git a/samples/multi-module/src/main.c b/samples/multi-module/src/main.c index 4aa092c3..557ffec3 100644 --- a/samples/multi-module/src/main.c +++ b/samples/multi-module/src/main.c @@ -9,7 +9,7 @@ static char * build_module_path(const char *module_name) { - const char *module_search_path = "./wasm-apps"; + const char *module_search_path = "."; const char *format = "%s/%s.wasm"; int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + strlen(".wasm") + 1; @@ -107,24 +107,36 @@ main() goto UNLOAD_MODULE; } - /* call some functions of mC */ + /* call functions of mC */ printf("\n----------------------------------------\n"); - printf("call \"C\", it will return 0xc:i32, ===> "); - wasm_application_execute_func(module_inst, "C", 0, &args[0]); - printf("call \"call_B\", it will return 0xb:i32, ===> "); - wasm_application_execute_func(module_inst, "call_B", 0, &args[0]); - printf("call \"call_A\", it will return 0xa:i32, ===>"); - wasm_application_execute_func(module_inst, "call_A", 0, &args[0]); + printf("call \"C1\", it will return 0x1f:i32, ===> "); + wasm_application_execute_func(module_inst, "C1", 0, args); + printf("call \"C2\", it will call B1() of mB and return 0x15:i32, ===> "); + wasm_application_execute_func(module_inst, "C2", 0, args); + printf("call \"C3\", it will call A1() of mA and return 0xb:i32, ===> "); + wasm_application_execute_func(module_inst, "C3", 0, args); + printf("call \"C4\", it will call B2() of mB and call A1() of mA and " + "return 0xb:i32, ===> "); + wasm_application_execute_func(module_inst, "C4", 0, args); + printf( + "call \"C5\", it will be failed since it is a export function, ===> "); + wasm_application_execute_func(module_inst, "C5", 0, args); - /* call some functions of mB */ - printf("call \"mB.B\", it will return 0xb:i32, ===>"); - wasm_application_execute_func(module_inst, "$mB$B", 0, &args[0]); - printf("call \"mB.call_A\", it will return 0xa:i32, ===>"); - wasm_application_execute_func(module_inst, "$mB$call_A", 0, &args[0]); + /* call functions of mB */ + printf("call \"mB.B1\", it will return 0x15:i32, ===> "); + wasm_application_execute_func(module_inst, "$mB$B1", 0, args); + printf("call \"mB.B2\", it will call A1() of mA and return 0xb:i32, ===> "); + wasm_application_execute_func(module_inst, "$mB$B2", 0, args); + printf("call \"mB.B3\", it will be failed since it is a export function, " + "===> "); + wasm_application_execute_func(module_inst, "$mB$B3", 0, args); - /* call some functions of mA */ - printf("call \"mA.A\", it will return 0xa:i32, ===>"); - wasm_application_execute_func(module_inst, "$mA$A", 0, &args[0]); + /* call functions of mA */ + printf("call \"mA.A1\", it will return 0xb:i32, ===>"); + wasm_application_execute_func(module_inst, "$mA$A1", 0, args); + printf("call \"mA.A2\", it will be failed since it is a export function, " + "===> "); + wasm_application_execute_func(module_inst, "$mA$A2", 0, args); printf("----------------------------------------\n\n"); ret = true; diff --git a/samples/multi-module/wasm-apps/CMakeLists.txt b/samples/multi-module/wasm-apps/CMakeLists.txt index 2691c50b..0dbfcc2e 100644 --- a/samples/multi-module/wasm-apps/CMakeLists.txt +++ b/samples/multi-module/wasm-apps/CMakeLists.txt @@ -1,41 +1,89 @@ -cmake_minimum_required(VERSION 2.8) +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8...3.16) project(wasm-apps) -set(CMAKE_VERBOSE_MAKEFILE on) +message(CHECK_START "Detecting WABT") +if(NOT (DEFINED WABT_DIR OR DEFINED CACHE{WABT_DIR})) + find_path(WABT_DIR + wabt + PATHS /opt + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + if(DEFINED WABT_DIR) + set(WABT_DIR ${WABT_DIR}/wabt) + endif() +endif() +if(WABT_DIR) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() -set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) -set(CLANG_COMMAND "/opt/wasi-sdk/bin/clang") - -set(CLANG_FLAGS --target=wasm32 -nostdlib) -set(CLANG_FLAGS ${CLANG_FLAGS} -Wl,--no-entry,--allow-undefined,--export-all) - -set(SOURCE_A ${CMAKE_CURRENT_SOURCE_DIR}/mA.c) -add_custom_command( - OUTPUT mA.wasm - COMMENT "Transform mA.C to mA.WASM" - COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mA.wasm ${SOURCE_A} - DEPENDS ${SOURCE_A} - VERBATIM +message(CHECK_START "Detecting WASM_OBJDUMP at ${WABT_DIR}") +find_program(WASM_OBJDUMP + wasm-objdump + PATHS "${WABT_DIR}/bin" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH ) +if(WASM_OBJDUMP) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() -set(SOURCE_B ${CMAKE_CURRENT_SOURCE_DIR}/mB.c) -add_custom_command( - OUTPUT mB.wasm - COMMENT "Transform mB.C to mB.WASM" - COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mB.wasm ${SOURCE_B} - DEPENDS ${SOURCE_B} - VERBATIM +message(CHECK_START "Detecting WASM2WAT at ${WABT_DIR}") +find_program(WASM2WAT + wasm2wat + PATHS "${WABT_DIR}/bin" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH ) +if(WASM2WAT) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() -set(SOURCE_C ${CMAKE_CURRENT_SOURCE_DIR}/mC.c) -add_custom_command( - OUTPUT mC.wasm - COMMENT "Transform mC.C to mC.WASM" - COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mC.wasm ${SOURCE_C} - DEPENDS ${SOURCE_C} - VERBATIM -) +function(COMPILE_WITH_CLANG SOURCE_FILE COMMAND) + get_filename_component(FILE_NAME ${SOURCE_FILE} NAME_WLE) + + set(WASM_MODULE ${FILE_NAME}.wasm) + + set(MAIN_TARGET_NAME MODULE_${FILE_NAME}) + + add_executable(${MAIN_TARGET_NAME} ${SOURCE_FILE}) + set_target_properties(${MAIN_TARGET_NAME} PROPERTIES OUTPUT_NAME ${WASM_MODULE}) + + if(${COMMAND}) + message(STATUS "Generating ${WASM_MODULE} as COMMAND...") + else() + message(STATUS "Generating ${WASM_MODULE} as REACTOR...") + target_link_options(${MAIN_TARGET_NAME} PRIVATE -mexec-model=reactor) + endif() + + if(EXISTS ${WASM2WAT}) + message(STATUS "Dumping ${WASM_MODULE}...") + set(WASM_WAT ${FILE_NAME}.wat) + set(DUMP_TARGET_NAME DUMP_${FILE_NAME}) + add_custom_command(OUTPUT ${WASM_WAT} + COMMAND ${WASM2WAT} --enable-all -o ${WASM_WAT} ${WASM_MODULE} + COMMENT "Dumping ${WASM_MODULE}..." + DEPENDS ${MAIN_TARGET_NAME} + ) + + add_custom_target(${DUMP_TARGET_NAME} ALL + DEPENDS ${WASM_WAT} + ) + endif() +endfunction() + +compile_with_clang(mA.c OFF) +compile_with_clang(mB.c OFF) +compile_with_clang(mC.c ON) +compile_with_clang(mD.cpp ON) +compile_with_clang(mE.cpp OFF) -add_custom_target(wasm-modules ALL - DEPENDS mA.wasm mB.wasm mC.wasm -) \ No newline at end of file diff --git a/samples/multi-module/wasm-apps/mA.c b/samples/multi-module/wasm-apps/mA.c index d5e8d833..663ec816 100644 --- a/samples/multi-module/wasm-apps/mA.c +++ b/samples/multi-module/wasm-apps/mA.c @@ -1,5 +1,13 @@ -int -A() +__attribute__((export_name("A1"))) int +A1() { - return 10; -} \ No newline at end of file + return 11; +} + +int +A2() +{ + return 12; +} + +/* mA is a reactor. it doesn't need a main() */ \ No newline at end of file diff --git a/samples/multi-module/wasm-apps/mB.c b/samples/multi-module/wasm-apps/mB.c index 7e9f3bfd..a912d1d7 100644 --- a/samples/multi-module/wasm-apps/mB.c +++ b/samples/multi-module/wasm-apps/mB.c @@ -1,15 +1,23 @@ __attribute__((import_module("mA"))) -__attribute__((import_name("A"))) extern int -A(); +__attribute__((import_name("A1"))) extern int +A1(); -int -B() +__attribute__((export_name("B1"))) int +B1() { - return 11; + return 21; +} + +__attribute__((export_name("B2"))) int +B2() +{ + return A1(); } int -call_A() +B3() { - return A(); + return 23; } + +/* mA is a reactor. it doesn't need a main() */ \ No newline at end of file diff --git a/samples/multi-module/wasm-apps/mC.c b/samples/multi-module/wasm-apps/mC.c index 5a378dd1..8b19a5b6 100644 --- a/samples/multi-module/wasm-apps/mC.c +++ b/samples/multi-module/wasm-apps/mC.c @@ -1,25 +1,51 @@ +#include +#include + __attribute__((import_module("mA"))) -__attribute__((import_name("A"))) extern int -A(); +__attribute__((import_name("A1"))) extern int +A1(); __attribute__((import_module("mB"))) -__attribute__((import_name("B"))) extern int -B(); +__attribute__((import_name("B1"))) extern int +B1(); -int -C() +__attribute__((import_module("mB"))) +__attribute__((import_name("B2"))) extern int +B2(); + +__attribute__((export_name("C1"))) int +C1() { - return 12; + return 31; +} + +__attribute__((export_name("C2"))) int +C2() +{ + return B1(); +} + +__attribute__((export_name("C3"))) int +C3() +{ + return A1(); +} + +__attribute__((export_name("C4"))) int +C4() +{ + return B2(); } int -call_A() +C5() { - return A(); + return C1() + C2() + C3() + 35; } int -call_B() +main() { - return B(); + printf("%u\n", C5()); + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/samples/multi-module/wasm-apps/mD.cpp b/samples/multi-module/wasm-apps/mD.cpp new file mode 100644 index 00000000..d70998c0 --- /dev/null +++ b/samples/multi-module/wasm-apps/mD.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +static void +bye_main() +{ + std::cout << "mD " << __FUNCTION__ << std::endl; +} + +static void +bye_setup() +{ + std::cout << "mD " << __FUNCTION__ << std::endl; +} + +static void +bye_func() +{ + std::cout << "mD " << __FUNCTION__ << std::endl; +} + +void +func3() __attribute__((__import_module__("mE"), __import_name__("func1"))); + +void +func4() __attribute__((__import_module__("mE"), __import_name__("func2"))); + +void +func1() +{ + std::printf("mD %s\n", __FUNCTION__); + if (std::atexit(bye_func) != 0) { + std::perror("register an atexit handler failed"); + } + func3(); +} + +void +func2() +{ + std::printf("mD %s\n", __FUNCTION__); + func4(); +} + +__attribute__((constructor)) void +setup() +{ + std::cout << "mD " << __FUNCTION__ << std::endl; + if (std::atexit(bye_setup) != 0) { + std::perror("register an atexit handler failed"); + } +} + +__attribute__((destructor)) void +teardown() +{ + std::cout << "mD " << __FUNCTION__ << std::endl; +} + +int +main() +{ + std::printf("mD %s\n", __FUNCTION__); + + if (std::atexit(bye_main) != 0) { + std::perror("register an atexit handler failed"); + return EXIT_FAILURE; + } + + func1(); + func2(); + return EXIT_SUCCESS; +} diff --git a/samples/multi-module/wasm-apps/mE.cpp b/samples/multi-module/wasm-apps/mE.cpp new file mode 100644 index 00000000..11e70af1 --- /dev/null +++ b/samples/multi-module/wasm-apps/mE.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +static void +bye_setup() +{ + std::cout << "mE " << __FUNCTION__ << std::endl; +} + +static void +bye_func() +{ + std::cout << "mE " << __FUNCTION__ << std::endl; +} + +__attribute__((constructor)) void +setup() +{ + std::cout << "mE " << __FUNCTION__ << std::endl; + if (std::atexit(bye_setup) != 0) { + std::perror("register an atexit handler failed"); + } +} + +__attribute__((destructor)) void +teardown() +{ + std::cout << "mE " << __FUNCTION__ << std::endl; +} + +__attribute__((export_name("func1"))) void +func1() +{ + std::cout << "mE " << __FUNCTION__ << std::endl; + if (std::atexit(bye_func) != 0) { + std::perror("register an atexit handler failed"); + } +} + +__attribute__((export_name("func2"))) void +func2() +{ + std::cout << "mE " << __FUNCTION__ << std::endl; +}