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) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 0a5f82106..5af944e46 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -409,6 +409,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 a7925b008..c49b63ca2 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_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 4b6d25b83..63a3c83c9 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, @@ -1388,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) @@ -1414,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); } @@ -2057,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) { @@ -4999,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) @@ -5012,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; } @@ -5020,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 4c3676f88..2728e57ef 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -496,6 +496,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. * @@ -536,6 +548,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 fe6b7a074..e70cc2a5b 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -1102,11 +1102,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 @@ -1185,20 +1183,13 @@ 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 - #if WASM_ENABLE_SHARED_HEAP != 0 WASMSharedHeap *shared_heap; #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; @@ -1231,8 +1222,23 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count, total_page_count = inc_page_count + cur_page_count; total_size_new = num_bytes_per_page * (uint64)total_page_count; + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < cur_page_count) { /* integer overflow */ + ret = false; + goto return_func; + } + + if (total_page_count > max_page_count) { + failure_reason = MAX_SIZE_REACHED; + ret = false; + goto return_func; + } + #if WASM_ENABLE_SHARED_HEAP != 0 - shared_heap = get_shared_heap((WASMModuleInstanceCommon *)module); + shared_heap = get_shared_heap(module); if (shared_heap) { if (memory->is_memory64 && total_size_new > shared_heap->start_off_mem64) { @@ -1248,20 +1254,6 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count, } } #endif - if (inc_page_count <= 0) - /* No need to enlarge memory */ - return true; - - if (total_page_count < cur_page_count) { /* integer overflow */ - ret = false; - goto return_func; - } - - if (total_page_count > max_page_count) { - failure_reason = MAX_SIZE_REACHED; - ret = false; - goto return_func; - } bh_assert(total_size_new <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); @@ -1364,7 +1356,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 @@ -1377,8 +1369,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); } @@ -1422,15 +1413,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; } @@ -1441,15 +1433,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/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index c827b28fe..dc20edba2 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) @@ -4505,7 +4521,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, #endif typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *); NativeRawFuncPtr invoke_native_raw = (NativeRawFuncPtr)func_ptr; - uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size, arg_i64; + uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size; uint32 *argv_src = argv, i, argc1, ptr_len; uint32 arg_i32; bool ret = false; @@ -4568,6 +4584,8 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I64: #if WASM_ENABLE_MEMORY64 != 0 { + uint64 arg_i64; + PUT_I64_TO_ADDR((uint32 *)argv_dst, GET_I64_FROM_ADDR(argv_src)); argv_src += 2; 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; 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 ffdafcef0..016cc2cb1 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; @@ -251,6 +255,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 */ @@ -572,6 +581,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. * @@ -946,6 +961,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_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 f70f9cb73..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) { @@ -1323,42 +1441,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 +1478,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 +2506,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 +2552,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 +3360,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 +3412,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 +3423,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 d4905a10d..48c333f4c 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -528,6 +528,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, @@ -554,13 +561,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); 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