From 926f6622312b52ce24bf55690cfba771299f36fa Mon Sep 17 00:00:00 2001 From: Benbuck Nason Date: Fri, 13 Sep 2024 19:31:13 -0700 Subject: [PATCH 1/6] Add memory instance support apis (#3786) Now that WAMR supports multiple memory instances, this PR adds some APIs to access them in a standard way. This involves moving some existing utility functions out from the `WASM_ENABLE_MULTI_MODULE` blocks they were nested in, but multi-memory and multi-module seem independent as far as I can tell so I assume that's okay. APIs added: ```C wasm_runtime_lookup_memory wasm_runtime_get_default_memory wasm_runtime_get_memory wasm_memory_get_cur_page_count wasm_memory_get_max_page_count wasm_memory_get_bytes_per_page wasm_memory_get_shared wasm_memory_get_base_address wasm_memory_enlarge ``` --- core/iwasm/aot/aot_runtime.c | 27 ++++- core/iwasm/aot/aot_runtime.h | 9 ++ core/iwasm/common/wasm_memory.c | 137 ++++++++++++++++++++++---- core/iwasm/include/wasm_export.h | 98 ++++++++++++++++++ core/iwasm/interpreter/wasm_runtime.c | 106 ++++++++++---------- core/iwasm/interpreter/wasm_runtime.h | 6 +- 6 files changed, 307 insertions(+), 76 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 4b6d25b83..dc6cba3f6 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1058,7 +1058,24 @@ fail1: return NULL; } -static AOTMemoryInstance * +AOTMemoryInstance * +aot_lookup_memory(AOTModuleInstance *module_inst, char const *name) +{ +#if WASM_ENABLE_MULTI_MEMORY != 0 + uint32 i; + for (i = 0; i < module_inst->export_memory_count; i++) + if (!strcmp(module_inst->export_memories[i].name, name)) + return module_inst->export_memories[i].memory; + return NULL; +#else + (void)module_inst->export_memories; + if (!module_inst->memories) + return NULL; + return module_inst->memories[0]; +#endif +} + +AOTMemoryInstance * aot_get_default_memory(AOTModuleInstance *module_inst) { if (module_inst->memories) @@ -1067,6 +1084,14 @@ aot_get_default_memory(AOTModuleInstance *module_inst) return NULL; } +AOTMemoryInstance * +aot_get_memory_with_index(AOTModuleInstance *module_inst, uint32 index) +{ + if ((index >= module_inst->memory_count) || !module_inst->memories) + return NULL; + return module_inst->memories[index]; +} + static bool memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, AOTModule *module, uint32 heap_size, diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 56d11a22d..f13d7eefc 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -532,6 +532,15 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst); AOTFunctionInstance * aot_lookup_function(const AOTModuleInstance *module_inst, const char *name); +AOTMemoryInstance * +aot_lookup_memory(AOTModuleInstance *module_inst, char const *name); + +AOTMemoryInstance * +aot_get_default_memory(AOTModuleInstance *module_inst); + +AOTMemoryInstance * +aot_get_memory_with_index(AOTModuleInstance *module_inst, uint32 index); + /** * Get a function in the AOT module instance. * diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 82eebbf30..03260589d 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -673,11 +673,9 @@ wasm_get_default_memory(WASMModuleInstance *module_inst) WASMMemoryInstance * wasm_get_memory_with_idx(WASMModuleInstance *module_inst, uint32 index) { - bh_assert(index < module_inst->memory_count); - if (module_inst->memories) - return module_inst->memories[index]; - else + if ((index >= module_inst->memory_count) || !module_inst->memories) return NULL; + return module_inst->memories[index]; } void @@ -756,15 +754,10 @@ wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size) return wasm_mremap_linear_memory(NULL, 0, map_size, commit_size); } -bool -wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count, - uint32 memidx) +static bool +wasm_enlarge_memory_internal(WASMModuleInstanceCommon *module, + WASMMemoryInstance *memory, uint32 inc_page_count) { -#if WASM_ENABLE_MULTI_MEMORY != 0 - WASMMemoryInstance *memory = wasm_get_memory_with_idx(module, memidx); -#else - WASMMemoryInstance *memory = wasm_get_default_memory(module); -#endif uint8 *memory_data_old, *memory_data_new, *heap_data_old; uint32 num_bytes_per_page, heap_size; uint32 cur_page_count, max_page_count, total_page_count; @@ -913,7 +906,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count, wasm_runtime_set_mem_bound_check_bytes(memory, total_size_new); return_func: - if (!ret && enlarge_memory_error_cb) { + if (!ret && module && enlarge_memory_error_cb) { WASMExecEnv *exec_env = NULL; #if WASM_ENABLE_INTERP != 0 @@ -926,8 +919,7 @@ return_func: #endif enlarge_memory_error_cb(inc_page_count, total_size_old, 0, - failure_reason, - (WASMModuleInstanceCommon *)module, exec_env, + failure_reason, module, exec_env, enlarge_memory_error_user_data); } @@ -971,15 +963,16 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) { bool ret = false; + if (module->memory_count > 0) { #if WASM_ENABLE_SHARED_MEMORY != 0 - if (module->memory_count > 0) shared_memory_lock(module->memories[0]); #endif - ret = wasm_enlarge_memory_internal(module, inc_page_count, 0); + ret = wasm_enlarge_memory_internal((WASMModuleInstanceCommon *)module, + module->memories[0], inc_page_count); #if WASM_ENABLE_SHARED_MEMORY != 0 - if (module->memory_count > 0) shared_memory_unlock(module->memories[0]); #endif + } return ret; } @@ -990,15 +983,117 @@ wasm_enlarge_memory_with_idx(WASMModuleInstance *module, uint32 inc_page_count, { bool ret = false; + if (memidx < module->memory_count) { #if WASM_ENABLE_SHARED_MEMORY != 0 - if (memidx < module->memory_count) shared_memory_lock(module->memories[memidx]); #endif - ret = wasm_enlarge_memory_internal(module, inc_page_count, memidx); + ret = wasm_enlarge_memory_internal((WASMModuleInstanceCommon *)module, + module->memories[memidx], + inc_page_count); #if WASM_ENABLE_SHARED_MEMORY != 0 - if (memidx < module->memory_count) shared_memory_unlock(module->memories[memidx]); #endif + } + + return ret; +} + +WASMMemoryInstance * +wasm_runtime_lookup_memory(WASMModuleInstanceCommon *module_inst, + const char *name) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_lookup_memory((WASMModuleInstance *)module_inst, name); +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_lookup_memory((WASMModuleInstance *)module_inst, name); +#endif + + return NULL; +} + +WASMMemoryInstance * +wasm_runtime_get_default_memory(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_get_default_memory((WASMModuleInstance *)module_inst); +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_get_default_memory((AOTModuleInstance *)module_inst); +#endif + + return NULL; +} + +WASMMemoryInstance * +wasm_runtime_get_memory(WASMModuleInstanceCommon *module_inst, uint32 index) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_get_memory_with_idx((WASMModuleInstance *)module_inst, + index); +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_get_memory_with_index((AOTModuleInstance *)module_inst, + index); +#endif + + return NULL; +} + +uint64 +wasm_memory_get_cur_page_count(WASMMemoryInstance *memory) +{ + return memory->cur_page_count; +} + +uint64 +wasm_memory_get_max_page_count(WASMMemoryInstance *memory) +{ + return memory->max_page_count; +} + +uint64 +wasm_memory_get_bytes_per_page(WASMMemoryInstance *memory) +{ + return memory->num_bytes_per_page; +} + +bool +wasm_memory_get_shared(WASMMemoryInstance *memory) +{ + return memory->is_shared_memory; +} + +void * +wasm_memory_get_base_address(WASMMemoryInstance *memory) +{ + return memory->memory_data; +} + +bool +wasm_memory_enlarge(WASMMemoryInstance *memory, uint64 inc_page_count) +{ + bool ret = false; + + if (memory) { +#if WASM_ENABLE_SHARED_MEMORY != 0 + shared_memory_lock(memory); +#endif + ret = + wasm_enlarge_memory_internal(NULL, memory, (uint32)inc_page_count); +#if WASM_ENABLE_SHARED_MEMORY != 0 + shared_memory_unlock(memory); +#endif + } return ret; } diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 569c4deaa..1a03f7280 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -120,6 +120,10 @@ typedef struct WASMModuleInstanceCommon *wasm_module_inst_t; typedef void WASMFunctionInstanceCommon; typedef WASMFunctionInstanceCommon *wasm_function_inst_t; +/* Memory instance */ +struct WASMMemoryInstance; +typedef struct WASMMemoryInstance *wasm_memory_inst_t; + /* WASM section */ typedef struct wasm_section_t { struct wasm_section_t *next; @@ -939,6 +943,100 @@ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_module_inst(wasm_exec_env_t exec_env, const wasm_module_inst_t module_inst); +/** + * @brief Lookup a memory instance by name + * + * @param module_inst The module instance + * @param name The name of the memory instance + * + * @return The memory instance if found, NULL otherwise + */ +WASM_RUNTIME_API_EXTERN wasm_memory_inst_t +wasm_runtime_lookup_memory(const wasm_module_inst_t module_inst, + const char *name); + +/** + * @brief Get the default memory instance + * + * @param module_inst The module instance + * + * @return The memory instance if found, NULL otherwise + */ +WASM_RUNTIME_API_EXTERN wasm_memory_inst_t +wasm_runtime_get_default_memory(const wasm_module_inst_t module_inst); + +/** + * @brief Get a memory instance by index + * + * @param module_inst The module instance + * @param index The index of the memory instance + * + * @return The memory instance if found, NULL otherwise + */ +WASM_RUNTIME_API_EXTERN wasm_memory_inst_t +wasm_runtime_get_memory(const wasm_module_inst_t module_inst, uint32_t index); + +/** + * @brief Get the current number of pages for a memory instance + * + * @param memory_inst The memory instance + * + * @return The current number of pages + */ +WASM_RUNTIME_API_EXTERN uint64_t +wasm_memory_get_cur_page_count(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the maximum number of pages for a memory instance + * + * @param memory_inst The memory instance + * + * @return The maximum number of pages + */ +WASM_RUNTIME_API_EXTERN uint64_t +wasm_memory_get_max_page_count(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the number of bytes per page for a memory instance + * + * @param memory_inst The memory instance + * + * @return The number of bytes per page + */ +WASM_RUNTIME_API_EXTERN uint64_t +wasm_memory_get_bytes_per_page(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the shared status for a memory instance + * + * @param memory_inst The memory instance + * + * @return True if shared, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_memory_get_shared(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the base address for a memory instance + * + * @param memory_inst The memory instance + * + * @return The base address on success, false otherwise + */ +WASM_RUNTIME_API_EXTERN void * +wasm_memory_get_base_address(const wasm_memory_inst_t memory_inst); + +/** + * @brief Enlarge a memory instance by a number of pages + * + * @param memory_inst The memory instance + * @param inc_page_count The number of pages to add + * + * @return True if successful, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_memory_enlarge(wasm_memory_inst_t memory_inst, uint64_t inc_page_count); + /** * Call the given WASM function of a WASM module instance with * arguments (bytecode and AoT). diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f70f9cb73..e8f4c749e 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1323,42 +1323,6 @@ export_tags_instantiate(const WASMModule *module, } #endif /* end of WASM_ENABLE_TAGS != 0 */ -#if WASM_ENABLE_MULTI_MODULE != 0 -static void -export_globals_deinstantiate(WASMExportGlobInstance *globals) -{ - if (globals) - wasm_runtime_free(globals); -} - -static WASMExportGlobInstance * -export_globals_instantiate(const WASMModule *module, - WASMModuleInstance *module_inst, - uint32 export_glob_count, char *error_buf, - uint32 error_buf_size) -{ - WASMExportGlobInstance *export_globals, *export_global; - WASMExport *export = module->exports; - uint32 i; - uint64 total_size = - sizeof(WASMExportGlobInstance) * (uint64)export_glob_count; - - if (!(export_global = export_globals = - runtime_malloc(total_size, error_buf, error_buf_size))) { - return NULL; - } - - for (i = 0; i < module->export_count; i++, export ++) - if (export->kind == EXPORT_KIND_GLOBAL) { - export_global->name = export->name; - export_global->global = &module_inst->e->globals[export->index]; - export_global++; - } - - bh_assert((uint32)(export_global - export_globals) == export_glob_count); - return export_globals; -} - #if WASM_ENABLE_MULTI_MEMORY != 0 static void export_memories_deinstantiate(WASMExportMemInstance *memories) @@ -1396,6 +1360,42 @@ export_memories_instantiate(const WASMModule *module, } #endif /* end of if WASM_ENABLE_MULTI_MEMORY != 0 */ +#if WASM_ENABLE_MULTI_MODULE != 0 +static void +export_globals_deinstantiate(WASMExportGlobInstance *globals) +{ + if (globals) + wasm_runtime_free(globals); +} + +static WASMExportGlobInstance * +export_globals_instantiate(const WASMModule *module, + WASMModuleInstance *module_inst, + uint32 export_glob_count, char *error_buf, + uint32 error_buf_size) +{ + WASMExportGlobInstance *export_globals, *export_global; + WASMExport *export = module->exports; + uint32 i; + uint64 total_size = + sizeof(WASMExportGlobInstance) * (uint64)export_glob_count; + + if (!(export_global = export_globals = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return NULL; + } + + for (i = 0; i < module->export_count; i++, export ++) + if (export->kind == EXPORT_KIND_GLOBAL) { + export_global->name = export->name; + export_global->global = &module_inst->e->globals[export->index]; + export_global++; + } + + bh_assert((uint32)(export_global - export_globals) == export_glob_count); + return export_globals; +} + #endif /* end of if WASM_ENABLE_MULTI_MODULE != 0 */ static WASMFunctionInstance * @@ -2388,11 +2388,13 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, /* export */ module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC); +#if WASM_ENABLE_MULTI_MEMORY != 0 + module_inst->export_memory_count = + get_export_count(module, EXPORT_KIND_MEMORY); +#endif #if WASM_ENABLE_MULTI_MODULE != 0 module_inst->export_table_count = get_export_count(module, EXPORT_KIND_TABLE); - module_inst->export_memory_count = - get_export_count(module, EXPORT_KIND_MEMORY); #if WASM_ENABLE_TAGS != 0 module_inst->e->export_tag_count = get_export_count(module, EXPORT_KIND_TAG); @@ -2432,7 +2434,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, module, module_inst, module_inst->export_global_count, error_buf, error_buf_size))) #endif -#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_MULTI_MEMORY != 0 +#if WASM_ENABLE_MULTI_MEMORY != 0 || (module_inst->export_memory_count > 0 && !(module_inst->export_memories = export_memories_instantiate( module, module_inst, module_inst->export_memory_count, @@ -3240,7 +3242,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) export_globals_deinstantiate(module_inst->export_globals); #endif -#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_MULTI_MEMORY != 0 +#if WASM_ENABLE_MULTI_MEMORY != 0 export_memories_deinstantiate(module_inst->export_memories); #endif @@ -3292,17 +3294,6 @@ wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name) return NULL; } -#if WASM_ENABLE_MULTI_MODULE != 0 -WASMGlobalInstance * -wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name) -{ - uint32 i; - for (i = 0; i < module_inst->export_global_count; i++) - if (!strcmp(module_inst->export_globals[i].name, name)) - return module_inst->export_globals[i].global; - return NULL; -} - WASMMemoryInstance * wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name) { @@ -3314,10 +3305,23 @@ wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name) return NULL; #else (void)module_inst->export_memories; + if (!module_inst->memories) + return NULL; return module_inst->memories[0]; #endif } +#if WASM_ENABLE_MULTI_MODULE != 0 +WASMGlobalInstance * +wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name) +{ + uint32 i; + for (i = 0; i < module_inst->export_global_count; i++) + if (!strcmp(module_inst->export_globals[i].name, name)) + return module_inst->export_globals[i].global; + return NULL; +} + WASMTableInstance * wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name) { diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 8666541f2..c43018695 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -539,13 +539,13 @@ wasm_set_running_mode(WASMModuleInstance *module_inst, WASMFunctionInstance * wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name); +WASMMemoryInstance * +wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); + #if WASM_ENABLE_MULTI_MODULE != 0 WASMGlobalInstance * wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name); -WASMMemoryInstance * -wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); - WASMTableInstance * wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name); From d64a3ab6ecfbf83e69a2d31cf0b3fb4f6a6e3368 Mon Sep 17 00:00:00 2001 From: Benbuck Nason Date: Fri, 13 Sep 2024 19:53:01 -0700 Subject: [PATCH 2/6] Fix aot multi export memory support (#3791) --- core/iwasm/aot/aot_runtime.c | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index dc6cba3f6..13664ca0e 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1413,6 +1413,36 @@ create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module, return true; } +#if WASM_ENABLE_MULTI_MEMORY != 0 +static WASMExportMemInstance * +export_memories_instantiate(const AOTModule *module, + AOTModuleInstance *module_inst, + uint32 export_mem_count, char *error_buf, + uint32 error_buf_size) +{ + WASMExportMemInstance *export_memories, *export_memory; + AOTExport *export = module->exports; + uint32 i; + uint64 total_size = + sizeof(WASMExportMemInstance) * (uint64)export_mem_count; + + if (!(export_memory = export_memories = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return NULL; + } + + for (i = 0; i < module->export_count; i++, export ++) + if (export->kind == EXPORT_KIND_MEMORY) { + export_memory->name = export->name; + export_memory->memory = module_inst->memories[export->index]; + export_memory++; + } + + bh_assert((uint32)(export_memory - export_memories) == export_mem_count); + return export_memories; +} +#endif /* end of if WASM_ENABLE_MULTI_MEMORY != 0 */ + static bool create_exports(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -1439,6 +1469,19 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module, } } +#if WASM_ENABLE_MULTI_MEMORY == 0 + bh_assert(module_inst->export_memory_count <= 1); +#else + if (module_inst->export_memory_count) { + module_inst->export_memories = export_memories_instantiate( + module, module_inst, module_inst->export_memory_count, error_buf, + error_buf_size); + if (!module_inst->export_memories) { + return false; + } + } +#endif + return create_export_funcs(module_inst, module, error_buf, error_buf_size); } @@ -2082,6 +2125,11 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) if (module_inst->export_functions) wasm_runtime_free(module_inst->export_functions); +#if WASM_ENABLE_MULTI_MEMORY != 0 + if (module_inst->export_memories) + wasm_runtime_free(module_inst->export_memories); +#endif + if (extra->functions) { uint32 func_idx; for (func_idx = 0; func_idx < extra->function_count; ++func_idx) { From 79e695e1a3566caa38fe25e86bd242b8c6691455 Mon Sep 17 00:00:00 2001 From: Anders Bakken Date: Tue, 17 Sep 2024 18:37:57 -0700 Subject: [PATCH 3/6] Fix a compile warning in aot_emit_function.c (#3793) This just fixes an unused variable warning when WASM_ENABLE_AOT_STACK_FRAME is != 0. --- core/iwasm/compilation/aot_emit_function.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 11129ac9c..85a9239aa 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -1407,7 +1407,9 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef *param_values = NULL, value_ret = NULL, func; LLVMValueRef import_func_idx, res; LLVMValueRef ext_ret, ext_ret_ptr, ext_ret_idx; +#if WASM_ENABLE_AOT_STACK_FRAME != 0 LLVMValueRef func_idx_ref; +#endif int32 i, j = 0, param_count, result_count, ext_ret_count; uint64 total_size; uint8 wasm_ret_type; From e9cc8731da157e03a2e07fc7aa9489e226210543 Mon Sep 17 00:00:00 2001 From: Benbuck Nason Date: Tue, 17 Sep 2024 19:24:30 -0700 Subject: [PATCH 4/6] Restore cmake hidden compile symbol visibility (#3796) This was originally fixed in #3655, but regressed in #3762 which removed the `-fvisibility=hidden` flag from the CMakeLists.txt file. This also removes extraneous ending whitespace from the file. --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0531ec411..40658e9ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,8 @@ include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) if (NOT WIN32) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security \ -ffunction-sections -fdata-sections \ - -Wno-unused-parameter -Wno-pedantic") + -Wno-unused-parameter -Wno-pedantic \ + -fvisibility=hidden") # Remove the extra spaces for better make log string (REGEX REPLACE " *" " " CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused") @@ -168,7 +169,7 @@ if (WAMR_BUILD_STATIC) endif () if (WIN32) - target_link_libraries(iwasm_static PRIVATE ntdll) + target_link_libraries(iwasm_static PRIVATE ntdll) endif() install (TARGETS iwasm_static ARCHIVE DESTINATION lib) @@ -190,7 +191,7 @@ if (WAMR_BUILD_SHARED) endif () if (WIN32) - target_link_libraries(iwasm_shared PRIVATE ntdll) + target_link_libraries(iwasm_shared PRIVATE ntdll) endif() install (TARGETS iwasm_shared LIBRARY DESTINATION lib) From 51a71092bf97116685986ebfcdf858e59a3834d0 Mon Sep 17 00:00:00 2001 From: Liangyu Zhang Date: Wed, 18 Sep 2024 11:02:10 +0800 Subject: [PATCH 5/6] Support dynamic aot debug (#3788) Enable dynamic aot debug feature which debugs the aot file and is able to set the break point and do single step. Refer to the README for the detailed steps. Signed-off-by: zhangliangyu3 --- build-scripts/config_common.cmake | 4 + core/config.h | 4 + core/iwasm/aot/aot_runtime.c | 18 +++ product-mini/platforms/nuttx/CMakeLists.txt | 6 + product-mini/platforms/nuttx/wamr.mk | 6 + product-mini/platforms/posix/main.c | 9 ++ test-tools/dynamic-aot-debug/README.md | 139 ++++++++++++++++++ .../dynamic-aot-debug/dynamic_aot_debug.py | 104 +++++++++++++ .../dynamic_aot_debug_workflow.svg | 17 +++ 9 files changed, 307 insertions(+) create mode 100644 test-tools/dynamic-aot-debug/README.md create mode 100644 test-tools/dynamic-aot-debug/dynamic_aot_debug.py create mode 100644 test-tools/dynamic-aot-debug/dynamic_aot_debug_workflow.svg diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 12fc06bd7..3d0d6bef7 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -404,6 +404,10 @@ endif () if (WAMR_BUILD_DEBUG_AOT EQUAL 1) message (" Debug AOT enabled") endif () +if (WAMR_BUILD_DYNAMIC_AOT_DEBUG EQUAL 1) + add_definitions (-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1) + message (" Dynamic AOT debug enabled") +endif () if (WAMR_BUILD_LOAD_CUSTOM_SECTION EQUAL 1) add_definitions (-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1) message (" Load custom section enabled") diff --git a/core/config.h b/core/config.h index a25eb543e..50f798922 100644 --- a/core/config.h +++ b/core/config.h @@ -75,6 +75,10 @@ #define WASM_ENABLE_AOT 0 #endif +#ifndef WASM_ENABLE_DYNAMIC_AOT_DEBUG +#define WASM_ENABLE_DYNAMIC_AOT_DEBUG 0 +#endif + #ifndef WASM_ENABLE_WORD_ALIGN_READ #define WASM_ENABLE_WORD_ALIGN_READ 0 #endif diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 13664ca0e..f1e63802a 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -5072,6 +5072,18 @@ aot_const_str_set_insert(const uint8 *str, int32 len, AOTModule *module, return c_str; } +#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0 +AOTModule *g_dynamic_aot_module = NULL; + +void __attribute__((noinline)) __enable_dynamic_aot_debug(void) +{ + /* empty implementation. */ +} + +void (*__enable_dynamic_aot_debug_ptr)(void) + __attribute__((visibility("default"))) = __enable_dynamic_aot_debug; +#endif + bool aot_set_module_name(AOTModule *module, const char *name, char *error_buf, uint32_t error_buf_size) @@ -5085,6 +5097,12 @@ aot_set_module_name(AOTModule *module, const char *name, char *error_buf, false, #endif error_buf, error_buf_size); +#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0 + /* export g_dynamic_aot_module for dynamic aot debug */ + g_dynamic_aot_module = module; + /* trigger breakpoint __enable_dynamic_aot_debug */ + (*__enable_dynamic_aot_debug_ptr)(); +#endif return module->name != NULL; } diff --git a/product-mini/platforms/nuttx/CMakeLists.txt b/product-mini/platforms/nuttx/CMakeLists.txt index ca07a5d55..27ddd9fa9 100644 --- a/product-mini/platforms/nuttx/CMakeLists.txt +++ b/product-mini/platforms/nuttx/CMakeLists.txt @@ -49,6 +49,12 @@ else() add_definitions(-DWASM_ENABLE_WORD_ALIGN_READ=0) endif() +if(CONFIG_INTERPRETERS_WAMR_DYNAMIC_AOT_DEBUG) + add_definitions(-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1) +else() + add_definitions(-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=0) +endif() + if(CONFIG_INTERPRETERS_WAMR_STACK_GUARD_SIZE) add_definitions(-DWASM_STACK_GUARD_SIZE=0) else() diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 0ee76c7dd..44d8694e5 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -148,6 +148,12 @@ else CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_DYNAMIC_AOT_DEBUG),y) +CFLAGS += -DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1 +else +CFLAGS += -DWASM_ENABLE_DYNAMIC_AOT_DEBUG=0 +endif + ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_DUAL_BUS_MIRROR),y) CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=1 else diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 14dc01f6b..af50223a4 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -928,6 +928,15 @@ main(int argc, char *argv[]) goto fail2; } +#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0 + if (!wasm_runtime_set_module_name(wasm_module, wasm_file, error_buf, + sizeof(error_buf))) { + printf("set aot module name failed in dynamic aot debug mode, %s\n", + error_buf); + goto fail3; + } +#endif + #if WASM_ENABLE_LIBC_WASI != 0 libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx); #endif diff --git a/test-tools/dynamic-aot-debug/README.md b/test-tools/dynamic-aot-debug/README.md new file mode 100644 index 000000000..6325a803a --- /dev/null +++ b/test-tools/dynamic-aot-debug/README.md @@ -0,0 +1,139 @@ +# Dynamic AOT Module Debugging + +> Note: Dynamic AOT debugging is experimental and only a few debugging capabilities are supported. + +This guide explains how to debug WAMR AOT modules with dynamic AOT features. Follow these steps to set up and run your debugging environment. + +## 1. Test source code + +The following c program file is used as a debugging test file. + +```bash +#include + +int main() { + printf("hello, world!\n"); + int a = 1024; + printf("a is %d\n",a); + int b = 42; + printf("b is %d\n",b); + return 0; +} +``` + +## 2. Build iwasm with dynamic aot debugging feature + +To enable dynamic AOT debugging, ensure the following +compile options are enabled when you [build iwasm](../../product-mini/README.md): + +```bash +cmake -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_DYNAMIC_AOT_DEBUG=1 -DCMAKE_BUILD_TYPE=Debug +``` + +## 3. Build wamrc + +Developer may need to build out two versions of wamrc, one is to compile the wasm binary into the AOT file, the other is to compile the wasm binary into an object file. To build out the former, just build wamrc as normal, see [wamrc-compiler/README.md](../../wamr-compiler/README.md). To build out the latter, the `WAMR_BUILD_DEBUG_AOT` flag must be added to cmake, please refer to the first two steps in [doc/source_debugging_aot.md](../../doc/source_debugging_aot.md), and if you encounter the error “‘eLanguageTypeC17’ not declared in this scope”, you can bypass it by commenting out the case judgments. This will not affect the debugging results. + +## 4. Dynamic aot debugging and verification across various platforms + +You can adjust the compiler options for different architectures and instruction sets. + +### 4.1 Linux + +#### Compile test.c to test.wasm + +```bash +/opt/wasi-sdk/bin/clang -O0 -g -gdwarf-2 -o test.wasm test.c +``` + +#### Compile test.wasm to test.aot + +```bash +./wamrc --opt-level=0 -o test.aot test.wasm +``` + +#### Compile test.wasm to test object file + +> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag. + +```bash +./wamrc --opt-level=0 --format=object -o test.obj test.wasm +``` + +#### Launch the program using gdbserver on the remote linux host + +```bash +cd ~/aot_debug # This directory contains iwasm and test.aot +gdbserver hostip:port ./iwasm test.aot +``` + +#### Local remote debugging + +```bash +expport OBJ_PATH=~/aot_debug +cd ~/aot_debug # This directory contains iwasm, test.c, test obj file and dynamic_aot_debug.py +gdb ./iwasm +(gdb) target remote hostip:port +(gdb) source dynamic_aot_debug.py +(gdb) c +(gdb) b test.c:main +(gdb) n +``` + +### 4.2 ARMv7 + +#### Compile test.c to test.wasm + +```bash +/opt/wasi-sdk/bin/clang -O0 -nostdlib -z stack-size=8192 -Wl,--initial-memory=65536 +-g -gdwarf-2 -o test.wasm test.c -Wl,--export=main -Wl,--export=__main_argc_argv +-Wl,--export=__heap_base -Wl,--export=__data_end -Wl,--no-entry -Wl,--allow-undefined +``` + +#### Compile test.wasm to test.aot + +```bash +./wamrc --opt-level=0 --target=thumbv7 --target-abi=gnueabihf --cpu=cortex-a7 +--cpu-features=-neon -o test.aot test.wasm +``` + +#### Compile test.wasm to test object file + +> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag. + +```bash +./wamrc --opt-level=0 --format=object --target=thumbv7 --target-abi=gnueabihf +--cpu=cortex-a7 --cpu-features=-neon -o test.obj test.wasm +``` + +#### Start Emulator + +In Terminal 1, start the emulator in debug mode and launch the GDB server: + +```bash +# start emulator on debug mode, and will start gdb server, set port as 1234 +./emulator.sh vela -qemu -S -s +ap> iwasm test.aot +``` + +#### Start NuttX Using GDB + +In Terminal 2, set the path to your object file and start NuttX with GDB: + +```bash +# You can save test.obj file in this path +export OBJ_PATH=~/work/data/aot_debug +gdb-multiarch nuttx -ex "tar remote:1234" -ex "source dynamic_aot_debug.py" +``` + +In the GDB prompt: + +```bash +(gdb) c +(gdb) b test.c:main +(gdb) n +``` + +## 5. Workflow + +Refer to the workflow diagram (wasm-micro-runtime/test-tools/dynamic-aot-debug) for an overview of the debugging process. In addition, the implementation of this dynamic aot debugging solution is not complete yet. It only supports breakpoints and single-step execution, and it is not yet known to view detailed information such as variables. diff --git a/test-tools/dynamic-aot-debug/dynamic_aot_debug.py b/test-tools/dynamic-aot-debug/dynamic_aot_debug.py new file mode 100644 index 000000000..1548954f4 --- /dev/null +++ b/test-tools/dynamic-aot-debug/dynamic_aot_debug.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 XiaoMi Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import os +import gdb + +# Get object file path from environment variable or use default value +path_objs = os.getenv("OBJ_PATH", "~/objects/") + +# Expand user directory symbol (~) +path_objs = os.path.expanduser(path_objs) +print(f"Object files will be loaded from: {path_objs} on localhost") + + +def add_symbol_with_aot_info(aot_module_info): + """Add symbol file with AOT information to GDB and list current breakpoints.""" + try: + text_addr = aot_module_info.get("code") + file_name = aot_module_info.get("name") + + if not text_addr or not file_name: + print("Error: 'code' or 'name' missing in AOT module info.") + return + + # Extract base file name without extension + file_name_without_extension, _ = os.path.splitext(file_name) + + # Remove directory part if present + file_name = os.path.basename(file_name_without_extension) + + # Add .obj extension to the file name + file_name = file_name + ".obj" + + # Construct the path for the symbol file + path_symfile = os.path.join(path_objs, file_name) + + # Construct the command to add the symbol file + cmd = f"add-symbol-file {path_symfile} {text_addr}" + gdb.execute(cmd) + + # Print current breakpoints + breakpoints = gdb.execute("info breakpoints", to_string=True) + print("Current breakpoints:", breakpoints) + + except gdb.error as e: + print(f"GDB error: {e}") + except Exception as e: + print(f"Unexpected error: {e}") + + +class ReadGDynamicAotModule(gdb.Command): + """Command to read the g_dynamic_aot_module structure and extract information.""" + + def __init__(self): + super(self.__class__, self).__init__("read_gda", gdb.COMMAND_USER) + + def invoke(self, args, from_tty): + """Retrieve and process the g_dynamic_aot_module structure.""" + try: + aot_module = gdb.parse_and_eval("g_dynamic_aot_module") + aot_module_info = {} + + # Ensure aot_module is a pointer and dereference it + if aot_module.type.code == gdb.TYPE_CODE_PTR: + aot_module = aot_module.dereference() + + # Check if it's a structure type + if aot_module.type.strip_typedefs().code == gdb.TYPE_CODE_STRUCT: + for field in aot_module.type.fields(): + field_name = field.name + var = aot_module[field_name] + + if field_name == "name": + aot_module_info["name"] = var.string() + elif field_name == "code": + aot_module_info["code"] = str(var) + + if "name" in aot_module_info and "code" in aot_module_info: + add_symbol_with_aot_info(aot_module_info) + else: + print("Could not find 'name' or 'code' in Aot_module.") + else: + print("Aot_module is not of struct type.") + else: + print("Aot_module is not a pointer type.") + except gdb.error as e: + print(f"An error occurred: {e}") + + +def init(): + """Initialize environment and set up debugger.""" + # Register the command to gdb + ReadGDynamicAotModule() + + # Set a breakpoint at function __enable_dynamic_aot_debug + breakpoint = gdb.Breakpoint("__enable_dynamic_aot_debug") + # Attach the self-defined command to the created breakpoint, read_gda means read global dynamic aot info. + breakpoint.commands = "read_gda" + + +init() diff --git a/test-tools/dynamic-aot-debug/dynamic_aot_debug_workflow.svg b/test-tools/dynamic-aot-debug/dynamic_aot_debug_workflow.svg new file mode 100644 index 000000000..fc81cb87a --- /dev/null +++ b/test-tools/dynamic-aot-debug/dynamic_aot_debug_workflow.svg @@ -0,0 +1,17 @@ + + + + + + + + load python scriptPCrun python initset breakpoint $1 on __enable_dynamic_aot_debugRegister "read_gda" command into gdbBind readl_gda to breakpoint $1trigger breakpointexcute "read_gda" commandnoyesRead and parse code_addr and module name from g_dynamic_aot_moduleGet the file name, text segment address of the dynamically aot loaded moduleExecute add-symbol-file test -s text 0x408f10f8 to load the debugging information fileiwasm test.aotset breakpoint $2, b test.aot main contiuewasm_runtime_set_module_name__enable_dynamic_aot_debug_ptrtrigger breakpoint $1gdb continue ?run nuttxGDB run nuttx andconnect to gdb servertrigger breakpoint $2debug test.aot programnowaityes12nuttxexitcall load_aot_module_destroytest/obj filetest.wasmwamrccall aot_unloadWASM_ENABLE_DYNAMIC_AOT_DEBUG=1test.cwasi-SDKWAMR_BUILD_DEBUG_AOT=1aot_set_module_name \ No newline at end of file From 21330990a8f5963dd09d81e491ca4a34f7196ab1 Mon Sep 17 00:00:00 2001 From: Anders Bakken Date: Thu, 19 Sep 2024 17:54:09 -0700 Subject: [PATCH 6/6] Add no_resolve to LoadArgs and wasm_runtime_resolve_symbols (#3790) Add no_resolve to LoadArgs and wasm_runtime_resolve_symbols so one can delay resolving of symbols. This is useful for inspecting the module between loading and instantiating. --- core/iwasm/aot/aot_loader.c | 150 ++++-------------------- core/iwasm/aot/aot_runtime.c | 122 +++++++++++++++++++ core/iwasm/aot/aot_runtime.h | 12 ++ core/iwasm/common/wasm_runtime_common.c | 16 +++ core/iwasm/include/wasm_c_api.h | 4 + core/iwasm/include/wasm_export.h | 11 ++ core/iwasm/interpreter/wasm_loader.c | 138 ++++------------------ core/iwasm/interpreter/wasm_runtime.c | 118 +++++++++++++++++++ core/iwasm/interpreter/wasm_runtime.h | 7 ++ 9 files changed, 337 insertions(+), 241 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 0abafd9dd..5c8131833 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -634,73 +634,6 @@ str2uint32(const char *buf, uint32 *p_res); static bool str2uint64(const char *buf, uint64 *p_res); -#if WASM_ENABLE_MULTI_MODULE != 0 -static void * -aot_loader_resolve_function(const AOTModule *module, const char *function_name, - const AOTFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size); - -static void * -aot_loader_resolve_function_ex(const char *module_name, - const char *function_name, - const AOTFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size) -{ - WASMModuleCommon *module_reg; - - module_reg = wasm_runtime_find_module_registered(module_name); - if (!module_reg || module_reg->module_type != Wasm_Module_AoT) { - LOG_DEBUG("can not find a module named %s for function %s", module_name, - function_name); - set_error_buf(error_buf, error_buf_size, "unknown import"); - return NULL; - } - return aot_loader_resolve_function((AOTModule *)module_reg, function_name, - expected_function_type, error_buf, - error_buf_size); -} - -static void * -aot_loader_resolve_function(const AOTModule *module, const char *function_name, - const AOTFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size) -{ - void *function = NULL; - AOTExport *export = NULL; - AOTFuncType *target_function_type = NULL; - - export = loader_find_export((WASMModuleCommon *)module, module->name, - function_name, EXPORT_KIND_FUNC, error_buf, - error_buf_size); - if (!export) { - return NULL; - } - - /* resolve function type and function */ - if (export->index < module->import_func_count) { - target_function_type = module->import_funcs[export->index].func_type; - function = module->import_funcs[export->index].func_ptr_linked; - } - else { - target_function_type = - (AOTFuncType *)module - ->types[module->func_type_indexes[export->index - - module->import_func_count]]; - function = - (module->func_ptrs[export->index - module->import_func_count]); - } - /* check function type */ - if (!wasm_type_equal((WASMType *)expected_function_type, - (WASMType *)target_function_type, module->types, - module->type_count)) { - LOG_DEBUG("%s.%s failed the type check", module->name, function_name); - set_error_buf(error_buf, error_buf_size, "incompatible import type"); - return NULL; - } - return function; -} -#endif /* end of WASM_ENABLE_MULTI_MODULE */ - static bool load_native_symbol_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, bool is_load_from_file_buf, @@ -2285,19 +2218,13 @@ destroy_import_funcs(AOTImportFunc *import_funcs) static bool load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, - bool is_load_from_file_buf, char *error_buf, + bool is_load_from_file_buf, bool no_resolve, char *error_buf, uint32 error_buf_size) { - char *module_name, *field_name; const uint8 *buf = *p_buf; AOTImportFunc *import_funcs; uint64 size; uint32 i; -#if WASM_ENABLE_MULTI_MODULE != 0 - AOTModule *sub_module = NULL; - AOTFunc *linked_func = NULL; - AOTFuncType *declare_func_type = NULL; -#endif /* Allocate memory */ size = sizeof(AOTImportFunc) * (uint64)module->import_func_count; @@ -2314,53 +2241,17 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, return false; } -#if WASM_ENABLE_MULTI_MODULE != 0 - declare_func_type = - (AOTFuncType *)module->types[import_funcs[i].func_type_index]; - read_string(buf, buf_end, module_name); - read_string(buf, buf_end, field_name); - - import_funcs[i].module_name = module_name; - import_funcs[i].func_name = field_name; - linked_func = wasm_native_resolve_symbol( - module_name, field_name, declare_func_type, - &import_funcs[i].signature, &import_funcs[i].attachment, - &import_funcs[i].call_conv_raw); - if (!linked_func) { - sub_module = NULL; - if (!wasm_runtime_is_built_in_module(module_name)) { - sub_module = (AOTModule *)wasm_runtime_load_depended_module( - (WASMModuleCommon *)module, module_name, error_buf, - error_buf_size); - if (!sub_module) { - LOG_ERROR("failed to load sub module: %s", error_buf); - return false; - } - } - if (!sub_module) - linked_func = aot_loader_resolve_function_ex( - module_name, field_name, declare_func_type, error_buf, - error_buf_size); - else - linked_func = aot_loader_resolve_function( - sub_module, field_name, declare_func_type, error_buf, - error_buf_size); - } - import_funcs[i].func_ptr_linked = linked_func; - import_funcs[i].func_type = declare_func_type; - -#else import_funcs[i].func_type = (AOTFuncType *)module->types[import_funcs[i].func_type_index]; read_string(buf, buf_end, import_funcs[i].module_name); read_string(buf, buf_end, import_funcs[i].func_name); - module_name = import_funcs[i].module_name; - field_name = import_funcs[i].func_name; - import_funcs[i].func_ptr_linked = wasm_native_resolve_symbol( - module_name, field_name, import_funcs[i].func_type, - &import_funcs[i].signature, &import_funcs[i].attachment, - &import_funcs[i].call_conv_raw); -#endif + import_funcs[i].attachment = NULL; + import_funcs[i].signature = NULL; + import_funcs[i].call_conv_raw = false; + + if (!no_resolve) { + aot_resolve_import_func(module, &import_funcs[i]); + } #if WASM_ENABLE_LIBC_WASI != 0 if (!strcmp(import_funcs[i].module_name, "wasi_unstable") @@ -2378,7 +2269,7 @@ fail: static bool load_import_func_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, bool is_load_from_file_buf, - char *error_buf, uint32 error_buf_size) + bool no_resolve, char *error_buf, uint32 error_buf_size) { const uint8 *buf = *p_buf; @@ -2387,7 +2278,7 @@ load_import_func_info(const uint8 **p_buf, const uint8 *buf_end, /* load import funcs */ if (module->import_func_count > 0 && !load_import_funcs(&buf, buf_end, module, is_load_from_file_buf, - error_buf, error_buf_size)) + no_resolve, error_buf, error_buf_size)) return false; *p_buf = buf; @@ -2514,7 +2405,7 @@ fail: static bool load_init_data_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, bool is_load_from_file_buf, - char *error_buf, uint32 error_buf_size) + bool no_resolve, char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; @@ -2525,7 +2416,7 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end, error_buf, error_buf_size) || !load_global_info(&p, p_end, module, error_buf, error_buf_size) || !load_import_func_info(&p, p_end, module, is_load_from_file_buf, - error_buf, error_buf_size)) + no_resolve, error_buf, error_buf_size)) return false; /* load function count and start function index */ @@ -3819,7 +3710,7 @@ has_module_memory64(AOTModule *module) static bool load_from_sections(AOTModule *module, AOTSection *sections, - bool is_load_from_file_buf, char *error_buf, + bool is_load_from_file_buf, bool no_resolve, char *error_buf, uint32 error_buf_size) { AOTSection *section = sections; @@ -3852,8 +3743,8 @@ load_from_sections(AOTModule *module, AOTSection *sections, break; case AOT_SECTION_TYPE_INIT_DATA: if (!load_init_data_section(buf, buf_end, module, - is_load_from_file_buf, error_buf, - error_buf_size)) + is_load_from_file_buf, no_resolve, + error_buf, error_buf_size)) return false; break; case AOT_SECTION_TYPE_TEXT: @@ -4076,7 +3967,7 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf, if (!module) return NULL; - if (!load_from_sections(module, section_list, false, error_buf, + if (!load_from_sections(module, section_list, false, false, error_buf, error_buf_size)) { aot_unload(module); return NULL; @@ -4246,7 +4137,8 @@ fail: static bool load(const uint8 *buf, uint32 size, AOTModule *module, - bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size) + bool wasm_binary_freeable, bool no_resolve, char *error_buf, + uint32 error_buf_size) { const uint8 *buf_end = buf + size; const uint8 *p = buf, *p_end = buf_end; @@ -4273,7 +4165,7 @@ load(const uint8 *buf, uint32 size, AOTModule *module, return false; ret = load_from_sections(module, section_list, !wasm_binary_freeable, - error_buf, error_buf_size); + no_resolve, error_buf, error_buf_size); if (!ret) { /* If load_from_sections() fails, then aot text is destroyed in destroy_sections() */ @@ -4321,8 +4213,8 @@ aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args, return NULL; os_thread_jit_write_protect_np(false); /* Make memory writable */ - if (!load(buf, size, module, args->wasm_binary_freeable, error_buf, - error_buf_size)) { + if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve, + error_buf, error_buf_size)) { aot_unload(module); return NULL; } diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index f1e63802a..63a3c83c9 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -5111,3 +5111,125 @@ aot_get_module_name(AOTModule *module) { return module->name; } + +bool +aot_resolve_symbols(AOTModule *module) +{ + bool ret = true; + uint32 idx; + for (idx = 0; idx < module->import_func_count; ++idx) { + AOTImportFunc *aot_import_func = &module->import_funcs[idx]; + if (!aot_import_func->func_ptr_linked) { + if (!aot_resolve_import_func(module, aot_import_func)) { + LOG_WARNING("Failed to link function (%s, %s)", + aot_import_func->module_name, + aot_import_func->func_name); + ret = false; + } + } + } + return ret; +} + +#if WASM_ENABLE_MULTI_MODULE != 0 +static void * +aot_resolve_function(const AOTModule *module, const char *function_name, + const AOTFuncType *expected_function_type, char *error_buf, + uint32 error_buf_size); + +static void * +aot_resolve_function_ex(const char *module_name, const char *function_name, + const AOTFuncType *expected_function_type, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg || module_reg->module_type != Wasm_Module_AoT) { + LOG_DEBUG("can not find a module named %s for function %s", module_name, + function_name); + set_error_buf(error_buf, error_buf_size, "unknown import"); + return NULL; + } + return aot_resolve_function((AOTModule *)module_reg, function_name, + expected_function_type, error_buf, + error_buf_size); +} + +static void * +aot_resolve_function(const AOTModule *module, const char *function_name, + const AOTFuncType *expected_function_type, char *error_buf, + uint32 error_buf_size) +{ + void *function = NULL; + AOTExport *export = NULL; + AOTFuncType *target_function_type = NULL; + + export = loader_find_export((WASMModuleCommon *)module, module->name, + function_name, EXPORT_KIND_FUNC, error_buf, + error_buf_size); + if (!export) { + return NULL; + } + + /* resolve function type and function */ + if (export->index < module->import_func_count) { + target_function_type = module->import_funcs[export->index].func_type; + function = module->import_funcs[export->index].func_ptr_linked; + } + else { + target_function_type = + (AOTFuncType *)module + ->types[module->func_type_indexes[export->index + - module->import_func_count]]; + function = + (module->func_ptrs[export->index - module->import_func_count]); + } + /* check function type */ + if (!wasm_type_equal((WASMType *)expected_function_type, + (WASMType *)target_function_type, module->types, + module->type_count)) { + LOG_DEBUG("%s.%s failed the type check", module->name, function_name); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + return function; +} +#endif /* end of WASM_ENABLE_MULTI_MODULE */ + +bool +aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func) +{ +#if WASM_ENABLE_MULTI_MODULE != 0 + char error_buf[128]; + AOTModule *sub_module = NULL; +#endif + import_func->func_ptr_linked = wasm_native_resolve_symbol( + import_func->module_name, import_func->func_name, + import_func->func_type, &import_func->signature, + &import_func->attachment, &import_func->call_conv_raw); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!import_func->func_ptr_linked) { + if (!wasm_runtime_is_built_in_module(import_func->module_name)) { + sub_module = (AOTModule *)wasm_runtime_load_depended_module( + (WASMModuleCommon *)module, import_func->module_name, error_buf, + sizeof(error_buf)); + if (!sub_module) { + LOG_WARNING("Failed to load sub module: %s", error_buf); + } + if (!sub_module) + import_func->func_ptr_linked = aot_resolve_function_ex( + import_func->module_name, import_func->func_name, + import_func->func_type, error_buf, sizeof(error_buf)); + else + import_func->func_ptr_linked = aot_resolve_function( + sub_module, import_func->func_name, import_func->func_type, + error_buf, sizeof(error_buf)); + if (!import_func->func_ptr_linked) { + LOG_WARNING("Failed to link function: %s", error_buf); + } + } + } +#endif + return import_func->func_ptr_linked != NULL; +} diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index f13d7eefc..9c73dd401 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -492,6 +492,18 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf, void aot_unload(AOTModule *module); +/** + * Resolve symbols for an AOT module + */ +bool +aot_resolve_symbols(AOTModule *module); + +/** + * Helper function to resolve a single function + */ +bool +aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func); + /** * Instantiate a AOT module. * diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 314dc7ddb..667cbba03 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1484,6 +1484,22 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args, error_buf_size); } +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_resolve_symbols(WASMModuleCommon *module) +{ +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + return wasm_resolve_symbols((WASMModule *)module); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) { + return aot_resolve_symbols((AOTModule *)module); + } +#endif + return false; +} + WASMModuleCommon * wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 4994454bd..9fc460148 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -534,6 +534,10 @@ typedef struct LoadArgs { bool clone_wasm_binary; /* This option is only used by the AOT/wasm loader (see wasm_export.h) */ bool wasm_binary_freeable; + /* false by default, if true, don't resolve the symbols yet. The + wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols + call */ + bool no_resolve; /* TODO: more fields? */ } LoadArgs; #endif /* LOAD_ARGS_OPTION_DEFINED */ diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 1a03f7280..c9037b3cc 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -252,6 +252,11 @@ typedef struct LoadArgs { const strings), making it possible to free the wasm binary buffer after loading. */ bool wasm_binary_freeable; + + /* false by default, if true, don't resolve the symbols yet. The + wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols + call */ + bool no_resolve; /* TODO: more fields? */ } LoadArgs; #endif /* LOAD_ARGS_OPTION_DEFINED */ @@ -569,6 +574,12 @@ WASM_RUNTIME_API_EXTERN wasm_module_t wasm_runtime_load_ex(uint8_t *buf, uint32_t size, const LoadArgs *args, char *error_buf, uint32_t error_buf_size); +/** + * Resolve symbols for a previously loaded WASM module. Only useful when the + * module was loaded with LoadArgs::no_resolve set to true + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_resolve_symbols(wasm_module_t module); /** * Load a WASM module from a specified WASM or AOT section list. * diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 3a21b1fc6..ff3501e3d 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2246,60 +2246,6 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name, #endif #if WASM_ENABLE_MULTI_MODULE != 0 -static WASMFunction * -wasm_loader_resolve_function(const char *module_name, const char *function_name, - const WASMFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size) -{ - WASMModuleCommon *module_reg; - WASMFunction *function = NULL; - WASMExport *export = NULL; - WASMModule *module = NULL; - WASMFuncType *target_function_type = NULL; - - module_reg = wasm_runtime_find_module_registered(module_name); - if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { - LOG_DEBUG("can not find a module named %s for function %s", module_name, - function_name); - set_error_buf(error_buf, error_buf_size, "unknown import"); - return NULL; - } - - module = (WASMModule *)module_reg; - export = - wasm_loader_find_export(module, module_name, function_name, - EXPORT_KIND_FUNC, error_buf, error_buf_size); - if (!export) { - return NULL; - } - - /* resolve function type and function */ - if (export->index < module->import_function_count) { - target_function_type = - module->import_functions[export->index].u.function.func_type; - function = module->import_functions[export->index] - .u.function.import_func_linked; - } - else { - target_function_type = - module->functions[export->index - module->import_function_count] - ->func_type; - function = - module->functions[export->index - module->import_function_count]; - } - - /* check function type */ - if (!wasm_type_equal((WASMType *)expected_function_type, - (WASMType *)target_function_type, module->types, - module->type_count)) { - LOG_DEBUG("%s.%s failed the type check", module_name, function_name); - set_error_buf(error_buf, error_buf_size, "incompatible import type"); - return NULL; - } - - return function; -} - static WASMTable * wasm_loader_resolve_table(const char *module_name, const char *table_name, uint32 init_size, uint32 max_size, char *error_buf, @@ -2494,21 +2440,11 @@ static bool load_function_import(const uint8 **p_buf, const uint8 *buf_end, const WASMModule *parent_module, const char *sub_module_name, const char *function_name, - WASMFunctionImport *function, char *error_buf, - uint32 error_buf_size) + WASMFunctionImport *function, bool no_resolve, + char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; uint32 declare_type_index = 0; - WASMFuncType *declare_func_type = NULL; - WASMFunction *linked_func = NULL; -#if WASM_ENABLE_MULTI_MODULE != 0 - WASMModule *sub_module = NULL; - bool is_built_in_module = false; -#endif - const char *linked_signature = NULL; - void *linked_attachment = NULL; - bool linked_call_conv_raw = false; - bool is_native_symbol = false; read_leb_uint32(p, p_end, declare_type_index); *p_buf = p; @@ -2527,43 +2463,19 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end, parent_module->types, parent_module->type_count, declare_type_index); #endif - declare_func_type = + function->func_type = (WASMFuncType *)parent_module->types[declare_type_index]; - /* lookup registered native symbols first */ - linked_func = wasm_native_resolve_symbol( - sub_module_name, function_name, declare_func_type, &linked_signature, - &linked_attachment, &linked_call_conv_raw); - if (linked_func) { - is_native_symbol = true; - } -#if WASM_ENABLE_MULTI_MODULE != 0 - else { - if (!(is_built_in_module = - wasm_runtime_is_built_in_module(sub_module_name))) { - sub_module = (WASMModule *)wasm_runtime_load_depended_module( - (WASMModuleCommon *)parent_module, sub_module_name, error_buf, - error_buf_size); - } - if (is_built_in_module || sub_module) - linked_func = wasm_loader_resolve_function( - sub_module_name, function_name, declare_func_type, error_buf, - error_buf_size); - } -#endif - function->module_name = (char *)sub_module_name; function->field_name = (char *)function_name; - function->func_type = declare_func_type; - /* func_ptr_linked is for native registered symbol */ - function->func_ptr_linked = is_native_symbol ? linked_func : NULL; - function->signature = linked_signature; - function->attachment = linked_attachment; - function->call_conv_raw = linked_call_conv_raw; -#if WASM_ENABLE_MULTI_MODULE != 0 - function->import_module = is_native_symbol ? NULL : sub_module; - function->import_func_linked = is_native_symbol ? NULL : linked_func; -#endif + function->attachment = NULL; + function->signature = NULL; + function->call_conv_raw = false; + + /* lookup registered native symbols first */ + if (!no_resolve) { + wasm_resolve_import_func(parent_module, function); + } return true; fail: return false; @@ -3258,8 +3170,8 @@ fail: static bool load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, - bool is_load_from_file_buf, char *error_buf, - uint32 error_buf_size) + bool is_load_from_file_buf, bool no_resolve, + char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end, *p_old; uint32 import_count, name_len, type_index, i, u32, flags; @@ -3442,9 +3354,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_FUNC: /* import function */ bh_assert(import_functions); import = import_functions++; - if (!load_function_import( - &p, p_end, module, sub_module_name, field_name, - &import->u.function, error_buf, error_buf_size)) { + if (!load_function_import(&p, p_end, module, + sub_module_name, field_name, + &import->u.function, no_resolve, + error_buf, error_buf_size)) { return false; } break; @@ -5760,7 +5673,7 @@ static void **handle_table; static bool load_from_sections(WASMModule *module, WASMSection *sections, bool is_load_from_file_buf, bool wasm_binary_freeable, - char *error_buf, uint32 error_buf_size) + bool no_resolve, char *error_buf, uint32 error_buf_size) { WASMExport *export; WASMSection *section = sections; @@ -5817,8 +5730,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, break; case SECTION_TYPE_IMPORT: if (!load_import_section(buf, buf_end, module, - reuse_const_strings, error_buf, - error_buf_size)) + reuse_const_strings, no_resolve, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_FUNC: @@ -6343,7 +6256,7 @@ wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf, if (!module) return NULL; - if (!load_from_sections(module, section_list, false, true, error_buf, + if (!load_from_sections(module, section_list, false, true, false, error_buf, error_buf_size)) { wasm_loader_unload(module); return NULL; @@ -6488,7 +6401,8 @@ static union { static bool load(const uint8 *buf, uint32 size, WASMModule *module, - bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size) + bool wasm_binary_freeable, bool no_resolve, char *error_buf, + uint32 error_buf_size) { const uint8 *buf_end = buf + size; const uint8 *p = buf, *p_end = buf_end; @@ -6519,7 +6433,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module, if (!create_sections(buf, size, §ion_list, error_buf, error_buf_size) || !load_from_sections(module, section_list, true, wasm_binary_freeable, - error_buf, error_buf_size)) { + no_resolve, error_buf, error_buf_size)) { destroy_sections(section_list); return false; } @@ -6695,8 +6609,8 @@ wasm_loader_load(uint8 *buf, uint32 size, module->load_size = size; #endif - if (!load(buf, size, module, args->wasm_binary_freeable, error_buf, - error_buf_size)) { + if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve, + error_buf, error_buf_size)) { goto fail; } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index e8f4c749e..e4142ab88 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -83,6 +83,124 @@ wasm_unload(WASMModule *module) wasm_loader_unload(module); } +bool +wasm_resolve_symbols(WASMModule *module) +{ + bool ret = true; + uint32 idx; + for (idx = 0; idx < module->import_function_count; ++idx) { + WASMFunctionImport *import = &module->import_functions[idx].u.function; + bool linked = import->func_ptr_linked; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (import->import_func_linked) { + linked = true; + } +#endif + if (!linked && !wasm_resolve_import_func(module, import)) { + ret = false; + } + } + return ret; +} + +#if WASM_ENABLE_MULTI_MODULE != 0 +static WASMFunction * +wasm_resolve_function(const char *module_name, const char *function_name, + const WASMFuncType *expected_function_type, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + WASMFunction *function = NULL; + WASMExport *export = NULL; + WASMModule *module = NULL; + WASMFuncType *target_function_type = NULL; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { + LOG_DEBUG("can not find a module named %s for function %s", module_name, + function_name); + set_error_buf(error_buf, error_buf_size, "unknown import"); + return NULL; + } + + module = (WASMModule *)module_reg; + export = loader_find_export((WASMModuleCommon *)module, module_name, + function_name, EXPORT_KIND_FUNC, error_buf, + error_buf_size); + if (!export) { + return NULL; + } + + /* resolve function type and function */ + if (export->index < module->import_function_count) { + target_function_type = + module->import_functions[export->index].u.function.func_type; + function = module->import_functions[export->index] + .u.function.import_func_linked; + } + else { + target_function_type = + module->functions[export->index - module->import_function_count] + ->func_type; + function = + module->functions[export->index - module->import_function_count]; + } + + /* check function type */ + if (!wasm_type_equal((WASMType *)expected_function_type, + (WASMType *)target_function_type, module->types, + module->type_count)) { + LOG_DEBUG("%s.%s failed the type check", module_name, function_name); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + + return function; +} +#endif + +bool +wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function) +{ +#if WASM_ENABLE_MULTI_MODULE != 0 + char error_buf[128]; + WASMModule *sub_module = NULL; +#endif + function->func_ptr_linked = wasm_native_resolve_symbol( + function->module_name, function->field_name, function->func_type, + &function->signature, &function->attachment, &function->call_conv_raw); + + if (function->func_ptr_linked) { + return true; + } + +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!wasm_runtime_is_built_in_module(function->module_name)) { + sub_module = (WASMModule *)wasm_runtime_load_depended_module( + (WASMModuleCommon *)module, function->module_name, error_buf, + sizeof(error_buf)); + if (!sub_module) { + LOG_WARNING("failed to load sub module: %s", error_buf); + return false; + } + } + function->import_func_linked = wasm_resolve_function( + function->module_name, function->field_name, function->func_type, + error_buf, sizeof(error_buf)); + + if (function->import_func_linked) { + function->import_module = sub_module; + return true; + } + else { + LOG_WARNING("failed to link function (%s, %s): %s", + function->module_name, function->field_name, error_buf); + } +#endif + + return false; +} + static void * runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index c43018695..e46b63cda 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -513,6 +513,13 @@ wasm_load_from_sections(WASMSection *section_list, char *error_buf, void wasm_unload(WASMModule *module); +bool +wasm_resolve_symbols(WASMModule *module); + +bool +wasm_resolve_import_func(const WASMModule *module, + WASMFunctionImport *function); + WASMModuleInstance * wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, WASMExecEnv *exec_env_main, uint32 stack_size,