diff --git a/README.md b/README.md index 8cbd41d0..df10d717 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,13 @@ Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr - [Linux](./doc/build_wamr.md#linux), [Zephyr](./doc/build_wamr.md#zephyr), [MacOS](./doc/build_wamr.md#macos), [VxWorks](./doc/build_wamr.md#vxworks), [AliOS-Things](./doc/build_wamr.md#alios-things), [Intel Software Guard Extention (Linux)](./doc/build_wamr.md#linux-sgx-intel-software-guard-extention), [Android](./doc/build_wamr.md#android) +### Build iwasm VM core (mini product) +WAMR supports building the iwasm VM core only (no app framework) to the mini product. The WAMR mini product takes the WASM application file name or AoT file name as input and then executes it. For the detailed procedure, please see **[build WAMR VM core](./doc/build_wamr.md)** and **[build and run WASM application](./doc/build_wasm_app.md)**. Also we can click the link of each platform above to see how to build iwasm on it. ### Build wamrc AoT compiler -Execute following commands to build **wamrc** compiler: +Both wasm binary file and AoT file are supported by iwasm. The wamrc AoT compiler is to compile wasm binary file to AoT file which can also be run by iwasm. Execute following commands to build **wamrc** compiler: ```shell cd wamr-compiler @@ -69,12 +71,6 @@ ln -s {current path}/wamrc /usr/bin/wamrc ``` For MacOS, you should replace `cmake ..` with `cmake -DWAMR_BUILD_PLATFORM=darwin ..`. -### Build the mini product - -WAMR supports building the iwasm VM core only (no app framework) to the mini product. The WAMR mini product takes the WASM application file name as input and then executes it. For the detailed procedure, see **[build WAMR VM core](./doc/build_wamr.md)** and **[build and run WASM application](./doc/build_wasm_app.md)**. - - - Application framework =================================== diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 3908ea1e..3b7728f5 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -158,3 +158,8 @@ if (WAMR_BUILD_MINI_LOADER EQUAL 1) else () add_definitions (-DWASM_ENABLE_MINI_LOADER=0) endif () +if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1) + add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1) + message (" Hardware boundary check disabled") +endif () + diff --git a/core/config.h b/core/config.h index 870d02c7..104dfdf3 100644 --- a/core/config.h +++ b/core/config.h @@ -149,6 +149,12 @@ enum { #define WASM_ENABLE_MINI_LOADER 0 #endif +/* Disable boundary check with hardware trap or not, + * enable it by default if it is supported */ +#ifndef WASM_DISABLE_HW_BOUND_CHECK +#define WASM_DISABLE_HW_BOUND_CHECK 0 +#endif + /* Heap and stack profiling */ #define BH_ENABLE_MEMORY_PROFILING 0 @@ -199,8 +205,8 @@ enum { /* Default/min/max stack size of each app thread */ #if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) -#define APP_THREAD_STACK_SIZE_DEFAULT (20 * 1024) -#define APP_THREAD_STACK_SIZE_MIN (16 * 1024) +#define APP_THREAD_STACK_SIZE_DEFAULT (32 * 1024) +#define APP_THREAD_STACK_SIZE_MIN (24 * 1024) #define APP_THREAD_STACK_SIZE_MAX (256 * 1024) #else #define APP_THREAD_STACK_SIZE_DEFAULT (6 * 1024) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index c2e491af..29e11db1 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -158,10 +158,38 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint64 total_size = heap_size + memory_data_size; uint8 *p; +#ifndef OS_ENABLE_HW_BOUND_CHECK /* Allocate memory */ if (!(p = runtime_malloc(total_size, error_buf, error_buf_size))) { return false; } +#else + uint8 *mapped_mem; + uint64 map_size = 8 * (uint64)BH_GB; + + /* Totally 8G is mapped, the opcode load/store address range is -2G to 6G: + * ea = i + memarg.offset + * i is i32, the range is -2G to 2G + * memarg.offset is u32, the range is 0 to 4G + * so the range of ea is -2G to 6G + */ + if (total_size >= UINT32_MAX + || !(mapped_mem = os_mmap(NULL, map_size, + MMAP_PROT_NONE, MMAP_MAP_NONE))) { + set_error_buf(error_buf, error_buf_size, + "AOT module instantiate failed: mmap memory failed."); + return false; + } + + p = mapped_mem + 2 * (uint64)BH_GB - heap_size; + if (os_mprotect(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { + set_error_buf(error_buf, error_buf_size, + "AOT module instantiate failed: mprotec memory failed."); + os_munmap(mapped_mem, map_size); + return false; + } + memset(p, 0, (uint32)total_size); +#endif /* Initialize heap info */ module_inst->heap_data.ptr = p; @@ -184,15 +212,15 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, p += (uint32)memory_data_size; module_inst->memory_data_end.ptr = p; module_inst->memory_data_size = (uint32)memory_data_size; - module_inst->total_mem_size = (uint32)(heap_size + memory_data_size); module_inst->mem_cur_page_count = module->mem_init_page_count; module_inst->mem_max_page_count = module->mem_max_page_count; - if (module_inst->total_mem_size > 0) { - module_inst->mem_bound_check_1byte = module_inst->total_mem_size - 1; - module_inst->mem_bound_check_2bytes = module_inst->total_mem_size - 2; - module_inst->mem_bound_check_4bytes = module_inst->total_mem_size - 4; - module_inst->mem_bound_check_8bytes = module_inst->total_mem_size - 8; + module_inst->mem_bound_check_heap_base = module_inst->heap_base_offset; + if (module_inst->memory_data_size > 0) { + module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; + module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; + module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; + module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; } for (i = 0; i < module->mem_init_data_count; i++) { @@ -263,7 +291,11 @@ fail2: module_inst->heap_handle.ptr = NULL; } fail1: +#ifndef OS_ENABLE_HW_BOUND_CHECK wasm_runtime_free(module_inst->heap_data.ptr); +#else + os_munmap(mapped_mem, map_size); +#endif module_inst->heap_data.ptr = NULL; return false; } @@ -374,6 +406,9 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, heap_size = align_uint(heap_size, 8); if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; +#ifdef OS_ENABLE_HW_BOUND_CHECK + heap_size = align_uint(heap_size, os_getpagesize()); +#endif /* Allocate module instance, global data, table data and heap data */ if (!(module_inst = runtime_malloc(total_size, @@ -468,8 +503,14 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) if (module_inst->heap_handle.ptr) mem_allocator_destroy(module_inst->heap_handle.ptr); - if (module_inst->heap_data.ptr) + if (module_inst->heap_data.ptr) { +#ifndef OS_ENABLE_HW_BOUND_CHECK wasm_runtime_free(module_inst->heap_data.ptr); +#else + os_munmap((uint8*)module_inst->memory_data.ptr - 2 * (uint64)BH_GB, + 8 * (uint64)BH_GB); +#endif + } if (module_inst->func_ptrs.ptr) wasm_runtime_free(module_inst->func_ptrs.ptr); @@ -508,6 +549,157 @@ aot_lookup_function(const AOTModuleInstance *module_inst, (addr)[1] = u.parts[1]; \ } while (0) + +#ifdef OS_ENABLE_HW_BOUND_CHECK + +static os_thread_local_attribute WASMExecEnv *aot_exec_env = NULL; + +static inline uint8 * +get_stack_min_addr(WASMExecEnv *exec_env, uint32 page_size) +{ + uintptr_t stack_bound = (uintptr_t)exec_env->native_stack_boundary; + return (uint8*)(stack_bound & ~(uintptr_t)(page_size -1 )); +} + +static void +aot_signal_handler(void *sig_addr) +{ + AOTModuleInstance *module_inst; + WASMJmpBuf *jmpbuf_node; + uint8 *mapped_mem_start_addr, *mapped_mem_end_addr; + uint8 *stack_min_addr; + uint32 page_size; + + /* Check whether current thread is running aot function */ + if (aot_exec_env + && aot_exec_env->handle == os_self_thread() + && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) { + /* Get mapped mem info of current instance */ + module_inst = (AOTModuleInstance *)aot_exec_env->module_inst; + mapped_mem_start_addr = (uint8*)module_inst->memory_data.ptr + - 2 * (uint64)BH_GB; + mapped_mem_end_addr = (uint8*)module_inst->memory_data.ptr + + 6 * (uint64)BH_GB; + + /* Get stack info of current thread */ + page_size = os_getpagesize(); + stack_min_addr = get_stack_min_addr(aot_exec_env, page_size); + + if (mapped_mem_start_addr <= (uint8*)sig_addr + && (uint8*)sig_addr < mapped_mem_end_addr) { + /* The address which causes segmentation fault is inside + aot instance's guard regions */ + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } + else if (stack_min_addr - page_size <= (uint8*)sig_addr + && (uint8*)sig_addr < stack_min_addr + page_size * 3) { + /* The address which causes segmentation fault is inside + native thread's guard page */ + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } + } +} + +bool +aot_signal_init() +{ + return os_signal_init(aot_signal_handler) == 0 ? true : false; +} + +void +aot_signal_destroy() +{ + os_signal_destroy(); +} + +#if defined(__GNUC__) +__attribute__((no_sanitize_address)) static uint32 +#else +static uint32 +#endif +touch_pages(uint8 *stack_min_addr, uint32 page_size) +{ + uint8 sum = 0; + while (1) { + uint8 *touch_addr = os_alloca(page_size / 2); + sum += *touch_addr; + if (touch_addr < stack_min_addr + page_size) { + break; + } + } + return sum; +} + +static bool +invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, + uint32 *argv, uint32 argc, uint32 *argv_ret) +{ + AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst; + WASMExecEnv **p_aot_exec_env = &aot_exec_env; + WASMJmpBuf *jmpbuf_node, *jmpbuf_node_pop; + uint32 page_size = os_getpagesize(); + uint8 *stack_min_addr = get_stack_min_addr(exec_env, page_size); + bool ret; + + if (aot_exec_env + && (aot_exec_env != exec_env)) { + aot_set_exception(module_inst, "Invalid exec env."); + return false; + } + + if (!exec_env->jmpbuf_stack_top) { + /* Touch each stack page to ensure that it has been mapped: the OS may + lazily grow the stack mapping as a guard page is hit. */ + touch_pages(stack_min_addr, page_size); + /* First time to call aot function, protect one page */ + if (os_mprotect(stack_min_addr, page_size * 3, MMAP_PROT_NONE) != 0) { + aot_set_exception(module_inst, "Set protected page failed."); + return false; + } + } + + if (!(jmpbuf_node = wasm_runtime_malloc(sizeof(WASMJmpBuf)))) { + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); + return false; + } + + wasm_exec_env_push_jmpbuf(exec_env, jmpbuf_node); + + aot_exec_env = exec_env; + if (os_setjmp(jmpbuf_node->jmpbuf) == 0) { + ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, + signature, attachment, + argv, argc, argv); + } + else { + /* Exception has been set in signal handler before calling longjmp */ + ret = false; + } + + jmpbuf_node_pop = wasm_exec_env_pop_jmpbuf(exec_env); + bh_assert(jmpbuf_node == jmpbuf_node_pop); + wasm_runtime_free(jmpbuf_node); + if (!exec_env->jmpbuf_stack_top) { + /* Unprotect the guard page when the nested call depth is zero */ + os_mprotect(stack_min_addr, page_size * 3, + MMAP_PROT_READ | MMAP_PROT_WRITE); + *p_aot_exec_env = NULL; + } + os_sigreturn(); + os_signal_unmask(); + (void)jmpbuf_node_pop; + return ret; +} + +#define invoke_native_internal invoke_native_with_hw_bound_check +#else /* else of OS_ENABLE_HW_BOUND_CHECK */ +#define invoke_native_internal wasm_runtime_invoke_native +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ + bool aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, @@ -515,8 +707,8 @@ aot_call_function(WASMExecEnv *exec_env, { AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst; AOTFuncType *func_type = function->func_type; - bool ret = wasm_runtime_invoke_native(exec_env, function->func_ptr, - func_type, NULL, NULL, argv, argc, argv); + bool ret = invoke_native_internal(exec_env, function->func_ptr, + func_type, NULL, NULL, argv, argc, argv); return ret && !aot_get_exception(module_inst) ? true : false; } @@ -762,6 +954,7 @@ aot_get_native_addr_range(AOTModuleInstance *module_inst, return false; } +#ifndef OS_ENABLE_HW_BOUND_CHECK bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { @@ -830,17 +1023,58 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) module_inst->mem_cur_page_count = total_page_count; module_inst->memory_data_size = (uint32)memory_data_size; - module_inst->total_mem_size = (uint32)(heap_size + memory_data_size); module_inst->memory_data.ptr = (uint8*)heap_data + heap_size; module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr + (uint32)memory_data_size; - module_inst->mem_bound_check_1byte = module_inst->total_mem_size - 1; - module_inst->mem_bound_check_2bytes = module_inst->total_mem_size - 2; - module_inst->mem_bound_check_4bytes = module_inst->total_mem_size - 4; - module_inst->mem_bound_check_8bytes = module_inst->total_mem_size - 8; + module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; + module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; + module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; + module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; return true; } +#else +bool +aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) +{ + uint32 num_bytes_per_page = + ((AOTModule*)module_inst->aot_module.ptr)->num_bytes_per_page; + uint32 cur_page_count = module_inst->mem_cur_page_count; + uint32 max_page_count = module_inst->mem_max_page_count; + uint32 total_page_count = cur_page_count + inc_page_count; + uint64 memory_data_size = (uint64)num_bytes_per_page * total_page_count; + + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < cur_page_count /* integer overflow */ + || total_page_count > max_page_count) { + aot_set_exception(module_inst, "fail to enlarge memory."); + return false; + } + + if (os_mprotect(module_inst->memory_data.ptr, memory_data_size, + MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { + aot_set_exception(module_inst, "fail to enlarge memory."); + return false; + } + + memset(module_inst->memory_data_end.ptr, 0, + num_bytes_per_page * inc_page_count); + + module_inst->mem_cur_page_count = total_page_count; + module_inst->memory_data_size = (uint32)memory_data_size; + module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr + + (uint32)memory_data_size; + + module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; + module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; + module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; + module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; + return true; +} +#endif bool aot_is_wasm_type_equal(AOTModuleInstance *module_inst, @@ -979,9 +1213,9 @@ aot_call_indirect(WASMExecEnv *exec_env, } } - return wasm_runtime_invoke_native(exec_env, func_ptr, - func_type, signature, attachment, - argv, argc, argv); + return invoke_native_internal(exec_env, func_ptr, + func_type, signature, attachment, + argv, argc, argv); } #if WASM_ENABLE_BULK_MEMORY != 0 diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index d06bc0b8..b42f12a2 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -198,14 +198,12 @@ typedef struct AOTModuleInstance { /* WASI context */ AOTPointer wasi_ctx; - /* total memory size: heap and linear memory */ - uint32 total_mem_size; - /* boundary check constants for aot code */ - uint32 mem_bound_check_1byte; - uint32 mem_bound_check_2bytes; - uint32 mem_bound_check_4bytes; - uint32 mem_bound_check_8bytes; + int64 mem_bound_check_heap_base; + int64 mem_bound_check_1byte; + int64 mem_bound_check_2bytes; + int64 mem_bound_check_4bytes; + int64 mem_bound_check_8bytes; /* others */ int32 temp_ret; @@ -469,6 +467,14 @@ bool aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index); #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK +bool +aot_signal_init(); + +void +aot_signal_destroy(); +#endif + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 14a173c1..4975b4d2 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -61,6 +61,15 @@ fail1: void wasm_exec_env_destroy_internal(WASMExecEnv *exec_env) { +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMJmpBuf *jmpbuf = exec_env->jmpbuf_stack_top; + WASMJmpBuf *jmpbuf_prev; + while (jmpbuf) { + jmpbuf_prev = jmpbuf->prev; + wasm_runtime_free(jmpbuf); + jmpbuf = jmpbuf_prev; + } +#endif #if WASM_ENABLE_THREAD_MGR != 0 os_mutex_destroy(&exec_env->wait_lock); os_cond_destroy(&exec_env->wait_cond); @@ -121,7 +130,6 @@ wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) exec_env->handle = os_self_thread(); exec_env->native_stack_boundary = os_thread_get_stack_boundary() + RESERVED_BYTES_TO_NATIVE_STACK_BOUNDARY; - } #if WASM_ENABLE_THREAD_MGR != 0 @@ -136,4 +144,27 @@ wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg) { exec_env->thread_arg = thread_arg; } -#endif \ No newline at end of file +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf) +{ + jmpbuf->prev = exec_env->jmpbuf_stack_top; + exec_env->jmpbuf_stack_top = jmpbuf; +} + +WASMJmpBuf * +wasm_exec_env_pop_jmpbuf(WASMExecEnv *exec_env) +{ + WASMJmpBuf *stack_top = exec_env->jmpbuf_stack_top; + + if (stack_top) { + exec_env->jmpbuf_stack_top = stack_top->prev; + return stack_top; + } + + return NULL; +} +#endif + diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index d29f33cb..fa5310e5 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -22,6 +22,13 @@ struct WASMInterpFrame; typedef struct WASMCluster WASMCluster; #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK +typedef struct WASMJmpBuf { + struct WASMJmpBuf *prev; + korp_jmpbuf jmpbuf; +} WASMJmpBuf; +#endif + /* Execution environment */ typedef struct WASMExecEnv { /* Next thread's exec env of a WASM module instance. */ @@ -82,6 +89,10 @@ typedef struct WASMExecEnv { BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE]; #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMJmpBuf *jmpbuf_stack_top; +#endif + /* The WASM stack size */ uint32 wasm_stack_size; @@ -207,6 +218,14 @@ void wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg); #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf); + +WASMJmpBuf * +wasm_exec_env_pop_jmpbuf(WASMExecEnv *exec_env); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 986348aa..ef3b5c46 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -120,9 +120,24 @@ wasm_runtime_env_init() goto fail5; } #endif + +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!aot_signal_init()) { + goto fail6; + } +#endif +#endif + return true; +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK +fail6: +#endif +#endif #if WASM_ENABLE_THREAD_MGR != 0 + thread_manager_destroy(); fail5: #endif #if WASM_ENABLE_SHARED_MEMORY @@ -170,6 +185,12 @@ wasm_runtime_init() void wasm_runtime_destroy() { +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK + aot_signal_destroy(); +#endif +#endif + /* runtime env destroy */ #if WASM_ENABLE_MULTI_MODULE wasm_runtime_destroy_loading_module_list(); diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 3c170892..ed45edda 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -398,7 +398,8 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_func = func_ctxes[func_idx - import_func_count]->aot_func; callee_cell_num = aot_func->param_cell_num + aot_func->local_cell_num + 1; - if (!check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) + if (comp_ctx->enable_bound_check + && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) goto fail; /* Call the function */ diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 70e6a0fa..46292660 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -75,18 +75,13 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 offset, uint32 bytes) { LLVMValueRef offset_const = I32_CONST(offset); - LLVMValueRef bytes_const = I32_CONST(bytes); - LLVMValueRef bytes64_const = I64_CONST(bytes); - LLVMValueRef heap_base_offset = func_ctx->heap_base_offset; - LLVMValueRef addr, maddr, offset1, offset2, cmp; - LLVMValueRef mem_base_addr, mem_check_bound, total_mem_size; + LLVMValueRef addr, maddr, offset1, cmp, cmp1, cmp2; + LLVMValueRef mem_base_addr, mem_check_bound; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMBasicBlockRef check_succ, check_mem_space; + LLVMBasicBlockRef check_succ; AOTValue *aot_value; CHECK_LLVM_CONST(offset_const); - CHECK_LLVM_CONST(bytes_const); - CHECK_LLVM_CONST(bytes64_const); /* Get memory base address and memory data size */ if (func_ctx->mem_space_unchanged) { @@ -104,21 +99,20 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_value = func_ctx->block_stack.block_list_end->value_stack.value_list_end; POP_I32(addr); - /* offset1 = offset + addr; */ - BUILD_OP(Add, offset_const, addr, offset1, "offset1"); /* return addres directly if constant offset and inside memory space */ - if (LLVMIsConstant(offset1)) { - uint32 mem_offset = (uint32)LLVMConstIntGetZExtValue(offset1); + if (LLVMIsConstant(addr)) { + int64 mem_offset = (int64)LLVMConstIntGetSExtValue(addr) + (int64)offset; uint32 num_bytes_per_page = comp_ctx->comp_data->num_bytes_per_page; uint32 init_page_count = comp_ctx->comp_data->mem_init_page_count; - uint32 mem_data_size = num_bytes_per_page * init_page_count; + int64 mem_data_size = num_bytes_per_page * init_page_count; if (mem_data_size > 0 + && mem_offset >= 0 && mem_offset <= mem_data_size - bytes) { /* inside memory space */ - /* maddr = mem_base_addr + moffset */ - if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, - mem_base_addr, + offset1 = I32_CONST((uint32)mem_offset); + CHECK_LLVM_CONST(offset_const); + if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr, &offset1, 1, "maddr"))) { aot_set_last_error("llvm build add failed."); goto fail; @@ -127,51 +121,35 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - if (comp_ctx->comp_data->mem_init_page_count == 0) { - /* Get total memory size */ - if (func_ctx->mem_space_unchanged) { - total_mem_size = func_ctx->total_mem_size; - } - else { - if (!(total_mem_size = LLVMBuildLoad(comp_ctx->builder, - func_ctx->total_mem_size, - "total_mem_size"))) { - aot_set_last_error("llvm build load failed."); + if (!(offset_const = LLVMBuildZExt(comp_ctx->builder, offset_const, + I64_TYPE, "offset_i64")) + || !(addr = LLVMBuildSExt(comp_ctx->builder, addr, + I64_TYPE, "addr_i64"))) { + aot_set_last_error("llvm build extend i32 to i64 failed."); goto fail; - } - } - - ADD_BASIC_BLOCK(check_mem_space, "check_mem_space"); - LLVMMoveBasicBlockAfter(check_mem_space, block_curr); - - /* if total_mem_size is zero, boundary check fail */ - BUILD_ICMP(LLVMIntEQ, total_mem_size, I32_ZERO, cmp, - "cmp_total_mem_size"); - if (!aot_emit_exception(comp_ctx, func_ctx, - EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - true, cmp, check_mem_space)) { - goto fail; - } - SET_BUILD_POS(check_mem_space); } - if (!(aot_value->is_local - && aot_checked_addr_list_find(func_ctx, aot_value->local_idx, - offset, bytes))) { - /* offset2 = offset1 - heap_base_offset; */ - BUILD_OP(Sub, offset1, heap_base_offset, offset2, "offset2"); + /* offset1 = offset + addr; */ + BUILD_OP(Add, offset_const, addr, offset1, "offset1"); + if (comp_ctx->enable_bound_check + && !(aot_value->is_local + && aot_checked_addr_list_find(func_ctx, aot_value->local_idx, + offset, bytes))) { if (!(mem_check_bound = get_memory_check_bound(comp_ctx, func_ctx, bytes))) { goto fail; } + BUILD_ICMP(LLVMIntSGT, func_ctx->mem_bound_check_heap_base, offset1, + cmp1, "cmp1"); + BUILD_ICMP(LLVMIntSGT, offset1, mem_check_bound, cmp2, "cmp2"); + BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); + /* Add basic blocks */ ADD_BASIC_BLOCK(check_succ, "check_succ"); LLVMMoveBasicBlockAfter(check_succ, block_curr); - /* offset2 > bound ? */ - BUILD_ICMP(LLVMIntUGT, offset2, mem_check_bound, cmp, "cmp"); if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, check_succ)) { diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 09155918..7ae2e025 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -182,29 +182,6 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - /* Load total memory size */ - offset = I32_CONST(offsetof(AOTModuleInstance, total_mem_size)); - if (!(func_ctx->total_mem_size = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, - &offset, 1, "bound_check_1byte_offset"))) { - aot_set_last_error("llvm build in bounds gep failed"); - return false; - } - if (!(func_ctx->total_mem_size = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->total_mem_size, - INT32_PTR_TYPE, "bound_check_1byte_ptr"))) { - aot_set_last_error("llvm build bit cast failed"); - return false; - } - if (mem_space_unchanged) { - if (!(func_ctx->total_mem_size = - LLVMBuildLoad(comp_ctx->builder, func_ctx->total_mem_size, - "bound_check_1byte"))) { - aot_set_last_error("llvm build load failed"); - return false; - } - } - /* Load memory bound check constants */ offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_1byte)); if (!(func_ctx->mem_bound_check_1byte = @@ -215,7 +192,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_1byte = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_1byte, - INT32_PTR_TYPE, "bound_check_1byte_ptr"))) { + INT64_PTR_TYPE, "bound_check_1byte_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -237,7 +214,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_2bytes = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_2bytes, - INT32_PTR_TYPE, "bound_check_2bytes_ptr"))) { + INT64_PTR_TYPE, "bound_check_2bytes_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -259,7 +236,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_4bytes = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_4bytes, - INT32_PTR_TYPE, "bound_check_4bytes_ptr"))) { + INT64_PTR_TYPE, "bound_check_4bytes_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -281,7 +258,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_8bytes = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_8bytes, - INT32_PTR_TYPE, "bound_check_8bytes_ptr"))) { + INT64_PTR_TYPE, "bound_check_8bytes_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -294,23 +271,23 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - /* Load heap base offset */ - offset = I32_CONST(offsetof(AOTModuleInstance, heap_base_offset)); - if (!(func_ctx->heap_base_offset = + /* Load bound_check_heap_base */ + offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_heap_base)); + if (!(func_ctx->mem_bound_check_heap_base = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, - &offset, 1, "heap_base_offset_offset"))) { + &offset, 1, "bound_check_heap_base_offset"))) { aot_set_last_error("llvm build in bounds gep failed"); return false; } - if (!(func_ctx->heap_base_offset = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->heap_base_offset, - INT32_PTR_TYPE, "heap_base_offset_tmp"))) { + if (!(func_ctx->mem_bound_check_heap_base = + LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_heap_base, + INT64_PTR_TYPE, "bound_check_heap_base_tmp"))) { aot_set_last_error("llvm build bit cast failed"); return false; } - if (!(func_ctx->heap_base_offset = - LLVMBuildLoad(comp_ctx->builder, func_ctx->heap_base_offset, - "heap_base_offset"))) { + if (!(func_ctx->mem_bound_check_heap_base = + LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_bound_check_heap_base, + "bound_check_heap_base"))) { aot_set_last_error("llvm build load failed"); return false; } @@ -936,6 +913,11 @@ aot_create_comp_context(AOTCompData *comp_data, comp_ctx->is_jit_mode = true; comp_ctx->target_machine = LLVMGetExecutionEngineTargetMachine(comp_ctx->exec_engine); +#ifndef OS_ENABLE_HW_BOUND_CHECK + comp_ctx->enable_bound_check = true; +#else + comp_ctx->enable_bound_check = false; +#endif } else { /* Create LLVM target machine */ @@ -1049,6 +1031,21 @@ aot_create_comp_context(AOTCompData *comp_data, get_target_arch_from_triple(triple_norm, comp_ctx->target_arch, sizeof(comp_ctx->target_arch)); + if (option->bounds_checks == 1 || option->bounds_checks == 0) { + /* Set by user */ + comp_ctx->enable_bound_check = + (option->bounds_checks == 1) ? true : false; + } + else { + /* Unset by user, use default value */ + if (strstr(comp_ctx->target_arch, "64") && !option->is_sgx_platform) { + comp_ctx->enable_bound_check = false; + } + else { + comp_ctx->enable_bound_check = true; + } + } + os_printf("Create AoT compiler with:\n"); os_printf(" target: %s\n", comp_ctx->target_arch); os_printf(" target cpu: %s\n", cpu); @@ -1114,14 +1111,11 @@ aot_create_comp_context(AOTCompData *comp_data, goto fail; } - LLVMAddBasicAliasAnalysisPass(comp_ctx->pass_mgr); LLVMAddPromoteMemoryToRegisterPass(comp_ctx->pass_mgr); LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); + LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); LLVMAddJumpThreadingPass(comp_ctx->pass_mgr); LLVMAddConstantPropagationPass(comp_ctx->pass_mgr); - LLVMAddReassociatePass(comp_ctx->pass_mgr); - LLVMAddGVNPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); /* Create metadata for llvm float experimental constrained intrinsics */ if (!(comp_ctx->fp_rounding_mode = diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index fc4821e2..f94f7c75 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -105,9 +105,8 @@ typedef struct AOTFuncContext { LLVMValueRef native_stack_bound; LLVMValueRef last_alloca; - LLVMValueRef heap_base_offset; LLVMValueRef mem_base_addr; - LLVMValueRef total_mem_size; + LLVMValueRef mem_bound_check_heap_base; LLVMValueRef mem_bound_check_1byte; LLVMValueRef mem_bound_check_2bytes; LLVMValueRef mem_bound_check_4bytes; @@ -188,6 +187,9 @@ typedef struct AOTCompContext { /* Bulk memory feature */ bool enable_bulk_memory; + /* Bounday Check */ + bool enable_bound_check; + /* Whether optimize the JITed code */ bool optimize; @@ -227,9 +229,11 @@ typedef struct AOTCompOption{ char *target_cpu; char *cpu_features; bool enable_bulk_memory; + bool is_sgx_platform; uint32 opt_level; uint32 size_level; uint32 output_format; + uint32 bounds_checks; } AOTCompOption, *aot_comp_option_t; AOTCompContext * diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 531d2df7..981c9edc 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -40,9 +40,11 @@ typedef struct AOTCompOption{ char *target_cpu; char *cpu_features; bool enable_bulk_memory; + bool is_sgx_platform; uint32_t opt_level; uint32_t size_level; uint32_t output_format; + uint32_t bounds_checks; } AOTCompOption, *aot_comp_option_t; aot_comp_context_t diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 02914f7f..2b164e71 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -224,11 +224,9 @@ LOAD_I16(void *addr) #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ #define CHECK_MEMORY_OVERFLOW(bytes) do { \ - int32 offset1 = (int32)(offset + addr); \ - uint64 offset2 = (uint64)(uint32)(offset1 - heap_base_offset); \ - /* if (flags != 2) \ - LOG_VERBOSE("unaligned load/store, flag: %d.\n", flags); */ \ - if (offset2 + LOAD_SIZE[opcode - WASM_OP_I32_LOAD] <= total_mem_size) \ + int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \ + if (heap_base_offset <= offset1 \ + && offset1 <= (int64)linear_mem_size - bytes) \ /* If offset1 is in valid range, maddr must also be in valid range, \ no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -973,12 +971,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMMemoryInstance *memory = module->default_memory; int32 heap_base_offset = memory ? memory->heap_base_offset : 0; uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; - uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - - heap_base_offset : 0; uint8 *global_data = module->global_data; -#if WASM_ENABLE_BULK_MEMORY != 0 uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; -#endif WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1015,12 +1009,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #undef HANDLE_OPCODE #endif - /* Size of memory load. - This starts with the first memory load operator at opcode 0x28 */ - uint32 LOAD_SIZE[] = { - 4, 8, 4, 8, 1, 1, 2, 2, 1, 1, 2, 2, 4, 4, /* loads */ - 4, 8, 4, 8, 1, 2, 1, 2, 4 }; /* stores */ - #if WASM_ENABLE_LABELS_AS_VALUES == 0 while (frame_ip < frame_ip_end) { opcode = *frame_ip++; @@ -1445,6 +1433,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if ((global_idx == (uint32)aux_stack_top_global_idx) && (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary)) goto out_of_bounds; + *(int32*)global_addr = POP_I32(); + break; case VALUE_TYPE_F32: *(int32*)global_addr = POP_I32(); break; @@ -1462,180 +1452,261 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* memory load instructions */ HANDLE_OP (WASM_OP_I32_LOAD): - HANDLE_OP (WASM_OP_I64_LOAD): HANDLE_OP (WASM_OP_F32_LOAD): - HANDLE_OP (WASM_OP_F64_LOAD): - HANDLE_OP (WASM_OP_I32_LOAD8_S): - HANDLE_OP (WASM_OP_I32_LOAD8_U): - HANDLE_OP (WASM_OP_I32_LOAD16_S): - HANDLE_OP (WASM_OP_I32_LOAD16_U): - HANDLE_OP (WASM_OP_I64_LOAD8_S): - HANDLE_OP (WASM_OP_I64_LOAD8_U): - HANDLE_OP (WASM_OP_I64_LOAD16_S): - HANDLE_OP (WASM_OP_I64_LOAD16_U): - HANDLE_OP (WASM_OP_I64_LOAD32_S): - HANDLE_OP (WASM_OP_I64_LOAD32_U): { - uint32 offset, flags, addr; - GET_OPCODE(); + uint32 offset, flags; + int32 addr; + read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); -#if WASM_ENABLE_LABELS_AS_VALUES != 0 - static const void *handle_load_table[] = { - &&HANDLE_LOAD_WASM_OP_I32_LOAD, - &&HANDLE_LOAD_WASM_OP_I64_LOAD, - &&HANDLE_LOAD_WASM_OP_F32_LOAD, - &&HANDLE_LOAD_WASM_OP_F64_LOAD, - &&HANDLE_LOAD_WASM_OP_I32_LOAD8_S, - &&HANDLE_LOAD_WASM_OP_I32_LOAD8_U, - &&HANDLE_LOAD_WASM_OP_I32_LOAD16_S, - &&HANDLE_LOAD_WASM_OP_I32_LOAD16_U, - &&HANDLE_LOAD_WASM_OP_I64_LOAD8_S, - &&HANDLE_LOAD_WASM_OP_I64_LOAD8_U, - &&HANDLE_LOAD_WASM_OP_I64_LOAD16_S, - &&HANDLE_LOAD_WASM_OP_I64_LOAD16_U, - &&HANDLE_LOAD_WASM_OP_I64_LOAD32_S, - &&HANDLE_LOAD_WASM_OP_I64_LOAD32_U - }; - #define HANDLE_OP_LOAD(opcode) HANDLE_LOAD_##opcode - goto *handle_load_table[opcode - WASM_OP_I32_LOAD]; -#else - #define HANDLE_OP_LOAD(opcode) case opcode - switch (opcode) -#endif - { - HANDLE_OP_LOAD(WASM_OP_I32_LOAD): - PUSH_I32(LOAD_I32(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD): - PUSH_I64(LOAD_I64(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_F32_LOAD): - PUSH_I32(LOAD_I32(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_F64_LOAD): - PUSH_F64(LOAD_F64(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD8_S): - PUSH_I32(sign_ext_8_32(*(int8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD8_U): - PUSH_I32((uint32)(*(uint8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD16_S): - PUSH_I32(sign_ext_16_32(LOAD_I16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD16_U): - PUSH_I32((uint32)(LOAD_U16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD8_S): - PUSH_I64(sign_ext_8_64(*(int8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD8_U): - PUSH_I64((uint64)(*(uint8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD16_S): - PUSH_I64(sign_ext_16_64(LOAD_I16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD16_U): - PUSH_I64((uint64)(LOAD_U16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD32_S): - PUSH_I64(sign_ext_32_64(LOAD_I32(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD32_U): - PUSH_I64((uint64)(LOAD_U32(maddr))); - HANDLE_OP_END(); - } + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); + PUSH_I32(LOAD_I32(maddr)); (void)flags; - HANDLE_OP_END (); + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD): + HANDLE_OP (WASM_OP_F64_LOAD): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(8); + PUSH_I64(LOAD_I64(maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD8_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I32(sign_ext_8_32(*(int8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD8_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I32((uint32)(*(uint8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD16_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I32(sign_ext_16_32(LOAD_I16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD16_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I32((uint32)(LOAD_U16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD8_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I64(sign_ext_8_64(*(int8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD8_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I64((uint64)(*(uint8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD16_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I64(sign_ext_16_64(LOAD_I16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD16_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I64((uint64)(LOAD_U16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD32_S): + { + uint32 offset, flags; + int32 addr; + + opcode = *(frame_ip - 1); + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); + PUSH_I64(sign_ext_32_64(LOAD_I32(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD32_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); + PUSH_I64((uint64)(LOAD_U32(maddr))); + (void)flags; + HANDLE_OP_END(); } /* memory store instructions */ + HANDLE_OP (WASM_OP_I32_STORE): HANDLE_OP (WASM_OP_F32_STORE): { - uint32 offset, flags, addr; - GET_OPCODE(); + uint32 offset, flags; + int32 addr; + read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); frame_sp--; - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, frame_sp[1]); (void)flags; HANDLE_OP_END (); } + HANDLE_OP (WASM_OP_I64_STORE): HANDLE_OP (WASM_OP_F64_STORE): { - uint32 offset, flags, addr; - GET_OPCODE(); + uint32 offset, flags; + int32 addr; + read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); frame_sp -= 2; - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(8); STORE_U32(maddr, frame_sp[1]); STORE_U32(maddr + 4, frame_sp[2]); (void)flags; HANDLE_OP_END (); } - HANDLE_OP (WASM_OP_I32_STORE): HANDLE_OP (WASM_OP_I32_STORE8): HANDLE_OP (WASM_OP_I32_STORE16): { - uint32 offset, flags, addr; + uint32 offset, flags; + int32 addr; uint32 sval; - GET_OPCODE(); + + opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); sval = (uint32)POP_I32(); - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); - switch (opcode) { - case WASM_OP_I32_STORE: - STORE_U32(maddr, sval); - break; - case WASM_OP_I32_STORE8: + addr = POP_I32(); + + if (opcode == WASM_OP_I32_STORE8) { + CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; - break; - case WASM_OP_I32_STORE16: - STORE_U16(maddr, (uint16)sval); - break; } + else { + CHECK_MEMORY_OVERFLOW(2); + STORE_U16(maddr, (uint16)sval); + } + (void)flags; HANDLE_OP_END (); } - HANDLE_OP (WASM_OP_I64_STORE): HANDLE_OP (WASM_OP_I64_STORE8): HANDLE_OP (WASM_OP_I64_STORE16): HANDLE_OP (WASM_OP_I64_STORE32): { - uint32 offset, flags, addr; + uint32 offset, flags; + int32 addr; uint64 sval; - GET_OPCODE(); + + opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); sval = (uint64)POP_I64(); - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); - switch (opcode) { - case WASM_OP_I64_STORE: - STORE_I64(maddr, sval); - break; - case WASM_OP_I64_STORE8: + addr = POP_I32(); + + if (opcode == WASM_OP_I64_STORE8) { + CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; - break; - case WASM_OP_I64_STORE16: + } + else if(opcode == WASM_OP_I64_STORE16) { + CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); - break; - case WASM_OP_I64_STORE32: + } + else { + CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, (uint32)sval); - break; } (void)flags; HANDLE_OP_END (); @@ -1671,11 +1742,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, PUSH_I32(prev_page_count); /* update the memory instance ptr */ memory = module->default_memory; - total_mem_size = num_bytes_per_page * memory->cur_page_count - - heap_base_offset; -#if WASM_ENABLE_BULK_MEMORY != 0 linear_mem_size = num_bytes_per_page * memory->cur_page_count; -#endif } (void)reserved; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 7f8ee845..afb9ac3e 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -226,11 +226,9 @@ LOAD_I16(void *addr) #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ #define CHECK_MEMORY_OVERFLOW(bytes) do { \ - int32 offset1 = (int32)(offset + addr); \ - uint64 offset2 = (uint64)(uint32)(offset1 - heap_base_offset); \ - /* if (flags != 2) \ - LOG_VERBOSE("unaligned load/store, flag: %d.\n", flags); */ \ - if (offset2 + bytes <= total_mem_size) \ + int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \ + if (heap_base_offset <= offset1 \ + && offset1 <= (int64)linear_mem_size - bytes) \ /* If offset1 is in valid range, maddr must also be in valid range,\ no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -412,6 +410,8 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) p += _off; \ } while (0) +#define read_uint32(p) (p += sizeof(uint32), *(uint32 *)(p - sizeof(uint32))) + #define GET_LOCAL_INDEX_TYPE_AND_OFFSET() do { \ uint32 param_count = cur_func->param_count; \ read_leb_uint32(frame_ip, frame_ip_end, local_idx); \ @@ -965,12 +965,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMMemoryInstance *memory = module->default_memory; int32 heap_base_offset = memory ? memory->heap_base_offset : 0; uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; - uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - - heap_base_offset : 0; uint8 *global_data = module->global_data; -#if WASM_ENABLE_BULK_MEMORY != 0 uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; -#endif WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1067,9 +1063,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_THREAD_MGR != 0 CHECK_SUSPEND_FLAGS(); #endif - count = GET_OPERAND(uint32, 0); - didx = GET_OPERAND(uint32, 2); - frame_ip += 4; + count = read_uint32(frame_ip); + didx = GET_OPERAND(uint32, 0); + frame_ip += 2; if (!(didx >= 0 && (uint32)didx < count)) didx = count; @@ -1096,9 +1092,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_SUSPEND_FLAGS(); #endif - tidx = GET_OPERAND(int32, 0); - val = GET_OPERAND(int32, 2); - frame_ip += 4; + tidx = read_uint32(frame_ip); + val = GET_OPERAND(int32, 0); + frame_ip += 2; if (tidx >= module->module->type_count) { wasm_set_exception(module, "type index is overflow"); @@ -1228,7 +1224,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_GET_GLOBAL): { - global_idx = frame_lp[GET_OFFSET()]; + global_idx = read_uint32(frame_ip); addr_ret = GET_OFFSET(); bh_assert(global_idx < module->global_count); @@ -1261,7 +1257,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_SET_GLOBAL): { - global_idx = frame_lp[GET_OFFSET()]; + global_idx = read_uint32(frame_ip); addr1 = GET_OFFSET(); bh_assert(global_idx < module->global_count); @@ -1281,6 +1277,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if ((global_idx == (uint32)aux_stack_top_global_idx) && (frame_lp[addr1] < exec_env->aux_stack_boundary)) goto out_of_bounds; + *(int32*)global_addr = frame_lp[addr1]; + break; case VALUE_TYPE_F32: *(int32*)global_addr = frame_lp[addr1]; break; @@ -1300,9 +1298,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); frame_lp[addr_ret] = LOAD_I32(maddr); @@ -1312,9 +1310,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(8); PUT_I64_TO_ADDR(frame_lp + addr_ret, LOAD_I64(maddr)); @@ -1324,9 +1322,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD8_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); frame_lp[addr_ret] = sign_ext_8_32(*(int8*)maddr); @@ -1336,9 +1334,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD8_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); frame_lp[addr_ret] = (uint32)(*(uint8*)maddr); @@ -1348,9 +1346,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD16_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); frame_lp[addr_ret] = sign_ext_16_32(LOAD_I16(maddr)); @@ -1360,9 +1358,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD16_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); frame_lp[addr_ret] = (uint32)(LOAD_U16(maddr)); @@ -1372,9 +1370,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD8_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); *(int64 *)(frame_lp + addr_ret) = sign_ext_8_64(*(int8*)maddr); @@ -1384,9 +1382,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD8_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); *(int64 *)(frame_lp + addr_ret) = (uint64)(*(uint8*)maddr); @@ -1396,9 +1394,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD16_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); *(int64 *)(frame_lp + addr_ret) = sign_ext_16_64(LOAD_I16(maddr)); @@ -1408,9 +1406,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD16_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); *(int64 *)(frame_lp + addr_ret) = (uint64)(LOAD_U16(maddr)); @@ -1420,9 +1418,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD32_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); *(int64 *)(frame_lp + addr_ret) = sign_ext_32_64(LOAD_I32(maddr)); @@ -1432,9 +1430,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD32_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); *(int64 *)(frame_lp + addr_ret) = (uint64)(LOAD_U32(maddr)); @@ -1445,10 +1443,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint32 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint32, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, sval); HANDLE_OP_END (); @@ -1458,10 +1456,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint32 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint32, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; HANDLE_OP_END (); @@ -1471,10 +1469,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint32 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint32, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); HANDLE_OP_END (); @@ -1484,10 +1482,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(8); STORE_I64(maddr, sval); HANDLE_OP_END (); @@ -1497,10 +1495,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; HANDLE_OP_END (); @@ -1510,10 +1508,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); HANDLE_OP_END (); @@ -1523,10 +1521,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, (uint32)sval); HANDLE_OP_END (); @@ -1563,11 +1561,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, frame_lp[addr_ret] = prev_page_count; /* update the memory instance ptr */ memory = module->default_memory; - total_mem_size = num_bytes_per_page * memory->cur_page_count - - heap_base_offset; -#if WASM_ENABLE_BULK_MEMORY != 0 linear_mem_size = num_bytes_per_page * memory->cur_page_count; -#endif } (void)reserved; @@ -2335,23 +2329,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (EXT_OP_COPY_STACK_TOP): addr1 = GET_OFFSET(); addr2 = GET_OFFSET(); -#if defined(BUILD_TARGET_X86_32) - bh_memcpy_s(frame_lp + addr2, sizeof(int32), - frame_lp + addr1, sizeof(int32)); -#else frame_lp[addr2] = frame_lp[addr1]; -#endif HANDLE_OP_END (); HANDLE_OP (EXT_OP_COPY_STACK_TOP_I64): addr1 = GET_OFFSET(); addr2 = GET_OFFSET(); -#if defined(BUILD_TARGET_X86_32) - bh_memcpy_s(frame_lp + addr2, sizeof(int64), - frame_lp + addr1, sizeof(int64)); -#else - *(float64*)(frame_lp + addr2) = *(float64*)(frame_lp + addr1); -#endif + *(uint64*)(frame_lp + addr2) = *(uint64*)(frame_lp + addr1); HANDLE_OP_END (); HANDLE_OP (WASM_OP_SET_LOCAL): @@ -2441,8 +2425,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint64 bytes, offset, seg_len; uint8* data; - segment = GET_OPERAND(uint32, 0); - frame_ip += 2; + segment = read_uint32(frame_ip); bytes = (uint64)POP_I32(); offset = (uint64)POP_I32(); @@ -2463,8 +2446,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 segment; - segment = GET_OPERAND(uint32, 0); - frame_ip += 2; + segment = read_uint32(frame_ip); module->module->data_segments[segment]->data_length = 0; @@ -2521,7 +2503,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_THREAD_MGR != 0 CHECK_SUSPEND_FLAGS(); #endif - fidx = frame_lp[GET_OFFSET()]; + fidx = read_uint32(frame_ip); #if WASM_ENABLE_MULTI_MODULE != 0 if (fidx >= module->function_count) { wasm_set_exception(module, "unknown function"); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 26491578..9786762f 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3889,13 +3889,13 @@ wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, LOG_OP("%d\t", byte); \ } while (0) -#define emit_leb() do { \ - wasm_loader_emit_leb(loader_ctx, p_org, p); \ +#define emit_uint32(ctx, value) do { \ + wasm_loader_emit_uint32(ctx, value); \ + LOG_OP("%d\t", value); \ } while (0) -#define emit_const(value) do { \ - GET_CONST_OFFSET(VALUE_TYPE_I32, value); \ - emit_operand(loader_ctx, operand_offset); \ +#define emit_leb() do { \ + wasm_loader_emit_leb(loader_ctx, p_org, p); \ } while (0) static bool @@ -3930,6 +3930,17 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx) return true; } +static void +wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) +{ + if (ctx->p_code_compiled) { + *(uint32*)(ctx->p_code_compiled) = value; + ctx->p_code_compiled += sizeof(uint32); + } + else + ctx->code_compiled_size += sizeof(uint32); +} + static void wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value) { @@ -5036,7 +5047,7 @@ re_scan: read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(count); + emit_uint32(loader_ctx, count); #endif POP_I32(); @@ -5097,7 +5108,7 @@ re_scan: read_leb_uint32(p, p_end, func_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(func_idx); + emit_uint32(loader_ctx, func_idx); #endif if (func_idx >= module->import_function_count + module->function_count) { @@ -5150,7 +5161,7 @@ re_scan: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(type_idx); + emit_uint32(loader_ctx, type_idx); #endif /* reserved byte 0x00 */ @@ -5476,7 +5487,7 @@ re_scan: PUSH_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); PUSH_OFFSET_TYPE(global_type); #endif break; @@ -5513,7 +5524,7 @@ re_scan: POP_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); POP_OFFSET_TYPE(global_type); #endif break; @@ -5572,7 +5583,7 @@ re_scan: goto fail; } #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(mem_offset); + emit_uint32(loader_ctx, mem_offset); #endif switch (opcode) { @@ -5951,7 +5962,7 @@ re_scan: case WASM_OP_MEMORY_INIT: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif if (module->import_memory_count == 0 && module->memory_count == 0) goto fail_unknown_memory; @@ -5977,7 +5988,7 @@ re_scan: case WASM_OP_DATA_DROP: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif if (segment_index >= module->data_seg_count) { set_error_buf(error_buf, error_buf_size, diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index dd7f2285..02c68b89 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2881,13 +2881,13 @@ wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, LOG_OP("%d\t", byte); \ } while (0) -#define emit_leb() do { \ - wasm_loader_emit_leb(loader_ctx, p_org, p); \ +#define emit_uint32(ctx, value) do { \ + wasm_loader_emit_uint32(ctx, value); \ + LOG_OP("%d\t", value); \ } while (0) -#define emit_const(value) do { \ - GET_CONST_OFFSET(VALUE_TYPE_I32, value); \ - emit_operand(loader_ctx, operand_offset); \ +#define emit_leb() do { \ + wasm_loader_emit_leb(loader_ctx, p_org, p); \ } while (0) static bool @@ -2922,6 +2922,17 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx) return true; } +static void +wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) +{ + if (ctx->p_code_compiled) { + *(uint32*)(ctx->p_code_compiled) = value; + ctx->p_code_compiled += sizeof(uint32); + } + else + ctx->code_compiled_size += sizeof(uint32); +} + static void wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value) { @@ -3968,7 +3979,7 @@ re_scan: read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(count); + emit_uint32(loader_ctx, count); #endif POP_I32(); @@ -4025,7 +4036,7 @@ re_scan: read_leb_uint32(p, p_end, func_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(func_idx); + emit_uint32(loader_ctx, func_idx); #endif bh_assert(func_idx < module->import_function_count @@ -4069,7 +4080,7 @@ re_scan: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(type_idx); + emit_uint32(loader_ctx, type_idx); #endif /* reserved byte 0x00 */ @@ -4369,7 +4380,7 @@ re_scan: PUSH_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); PUSH_OFFSET_TYPE(global_type); #endif break; @@ -4396,7 +4407,7 @@ re_scan: POP_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); POP_OFFSET_TYPE(global_type); #endif (void)is_mutable; @@ -4452,7 +4463,7 @@ re_scan: read_leb_uint32(p, p_end, align); /* align */ read_leb_uint32(p, p_end, mem_offset); /* offset */ #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(mem_offset); + emit_uint32(loader_ctx, mem_offset); #endif switch (opcode) { @@ -4823,7 +4834,7 @@ re_scan: case WASM_OP_MEMORY_INIT: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif bh_assert(module->import_memory_count + module->memory_count > 0); @@ -4841,7 +4852,7 @@ re_scan: case WASM_OP_DATA_DROP: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif bh_assert(segment_index < module->data_seg_count); bh_assert(module->data_seg_count1 > 0); diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index f7aa9083..a19ac6f5 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -483,6 +483,7 @@ pthread_start_routine(void *arg) return NULL; } + wasm_exec_env_set_thread_info(exec_env); argv[0] = addr_native_to_app(routine_args->arg); if(!wasm_runtime_call_indirect(exec_env, diff --git a/core/shared/platform/alios/alios_platform.c b/core/shared/platform/alios/alios_platform.c index 0af45aeb..81505482 100644 --- a/core/shared/platform/alios/alios_platform.c +++ b/core/shared/platform/alios/alios_platform.c @@ -42,19 +42,21 @@ os_free(void *ptr) } void * -os_mmap(void *hint, unsigned int size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags) { - return BH_MALLOC(size); + if ((uint64)size >= UINT32_MAX) + return NULL; + return BH_MALLOC((uint32)size); } void -os_munmap(void *addr, uint32 size) +os_munmap(void *addr, size_t size) { return BH_FREE(addr); } int -os_mprotect(void *addr, uint32 size, int prot) +os_mprotect(void *addr, size_t size, int prot) { return 0; } diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index bf1248a2..74c3f236 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -48,6 +48,38 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 7625cf66..26b8d842 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -6,7 +6,7 @@ #include "platform_api_vmcore.h" void * -os_mmap(void *hint, uint32 size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags) { int map_prot = PROT_NONE; int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; @@ -17,7 +17,12 @@ os_mmap(void *hint, uint32 size, int prot, int flags) page_size = getpagesize(); request_size = (size + page_size - 1) & ~(page_size - 1); - if (request_size >= UINT32_MAX) + if ((size_t)request_size < size) + /* integer overflow */ + return NULL; + + if (request_size > 16 * (uint64)UINT32_MAX) + /* At most 16 G is allowed */ return NULL; if (prot & MMAP_PROT_READ) @@ -53,7 +58,7 @@ os_mmap(void *hint, uint32 size, int prot, int flags) } void -os_munmap(void *addr, uint32 size) +os_munmap(void *addr, size_t size) { uint64 page_size = getpagesize(); uint64 request_size = (size + page_size - 1) & ~(page_size - 1); @@ -67,9 +72,11 @@ os_munmap(void *addr, uint32 size) } int -os_mprotect(void *addr, uint32 size, int prot) +os_mprotect(void *addr, size_t size, int prot) { int map_prot = PROT_NONE; + uint64 page_size = getpagesize(); + uint64 request_size = (size + page_size - 1) & ~(page_size - 1); if (!addr) return 0; @@ -83,7 +90,7 @@ os_mprotect(void *addr, uint32 size, int prot) if (prot & MMAP_PROT_EXEC) map_prot |= PROT_EXEC; - return mprotect(addr, size, map_prot); + return mprotect(addr, request_size, map_prot); } void diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 54ff0e8c..58d8fee7 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -21,7 +21,7 @@ static void *os_thread_wrapper(void *arg) thread_wrapper_arg * targ = arg; thread_start_routine_t start_func = targ->start; void *thread_arg = targ->arg; - printf("THREAD CREATE %p\n", &targ); + os_printf("THREAD CREATED %p\n", &targ); targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff); BH_FREE(targ); start_func(thread_arg); @@ -41,8 +41,8 @@ int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); if (pthread_attr_setstacksize(&tattr, stack_size) != 0) { - printf("Invalid thread stack size %u. Min stack size on Linux = %u", - stack_size, PTHREAD_STACK_MIN); + os_printf("Invalid thread stack size %u. Min stack size on Linux = %u", + stack_size, PTHREAD_STACK_MIN); pthread_attr_destroy(&tattr); return BHT_ERROR; } @@ -123,7 +123,7 @@ int os_mutex_lock(korp_mutex *mutex) assert(mutex); ret = pthread_mutex_lock(mutex); if (0 != ret) { - printf("vm mutex lock failed (ret=%d)!\n", ret); + os_printf("vm mutex lock failed (ret=%d)!\n", ret); exit(-1); } return ret; @@ -140,7 +140,7 @@ int os_mutex_unlock(korp_mutex *mutex) assert(mutex); ret = pthread_mutex_unlock(mutex); if (0 != ret) { - printf("vm mutex unlock failed (ret=%d)!\n", ret); + os_printf("vm mutex unlock failed (ret=%d)!\n", ret); exit(-1); } return ret; @@ -241,15 +241,16 @@ uint8 *os_thread_get_stack_boundary() pthread_attr_t attr; uint8 *addr = NULL; size_t stack_size, guard_size; + int page_size = getpagesize(); #ifdef __linux__ if (pthread_getattr_np(self, &attr) == 0) { pthread_attr_getstack(&attr, (void**)&addr, &stack_size); pthread_attr_getguardsize(&attr, &guard_size); pthread_attr_destroy(&attr); - if (guard_size < 4 * 1024) - /* Reserved 4 KB guard size at least for safety */ - guard_size = 4 * 1024; + if (guard_size < (size_t)page_size) + /* Reserved 1 guard page at least for safety */ + guard_size = (size_t)page_size; addr += guard_size; } (void)stack_size; @@ -257,10 +258,150 @@ uint8 *os_thread_get_stack_boundary() if ((addr = (uint8*)pthread_get_stackaddr_np(self))) { stack_size = pthread_get_stacksize_np(self); addr -= stack_size; - /* Reserved 4 KB guard size at least for safety */ - addr += 4 * 1024; + /* Reserved 1 guard page at least for safety */ + addr += page_size; } #endif return addr; -} \ No newline at end of file +} + +#ifdef OS_ENABLE_HW_BOUND_CHECK + +#define SIG_ALT_STACK_SIZE (32 * 1024) + +/* The signal alternate stack base addr */ +static uint8 *sigalt_stack_base_addr; + +/* The signal handler passed to os_signal_init() */ +static os_signal_handler signal_handler; + +static void +mask_signals(int how) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGSEGV); + sigaddset(&set, SIGBUS); + pthread_sigmask(how, &set, NULL); +} + +__attribute__((noreturn)) static void +signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext) +{ + int i; + void *sig_addr = sig_info->si_addr; + + mask_signals(SIG_BLOCK); + + if (signal_handler + && (sig_num == SIGSEGV || sig_num == SIGBUS)) { + signal_handler(sig_addr); + } + + /* signal unhandled */ + switch (sig_num) { + case SIGSEGV: + os_printf("unhandled SIGSEGV, si_addr: %p\n", sig_addr); + break; + case SIGBUS: + os_printf("unhandled SIGBUS, si_addr: %p\n", sig_addr); + break; + default: + os_printf("unhandle signal %d, si_addr: %p\n", + sig_num, sig_addr); + break; + } + + /* divived by 0 to make it abort */ + i = os_printf(" "); + os_printf("%d\n", i / (i - 1)); + /* access NULL ptr to make it abort */ + os_printf("%d\n", *(uint32*)(uintptr_t)(i - 1)); + exit(1); +} + +int +os_signal_init(os_signal_handler handler) +{ + int ret = -1; + struct sigaction sig_act; + stack_t sigalt_stack_info; + uint32 map_size = SIG_ALT_STACK_SIZE; + uint8 *map_addr; + + /* Initialize memory for signal alternate stack */ + if (!(map_addr = os_mmap(NULL, map_size, + MMAP_PROT_READ | MMAP_PROT_WRITE, + MMAP_MAP_NONE))) { + os_printf("Failed to mmap memory for alternate stack\n"); + return -1; + } + + /* Initialize signal alternate stack */ + memset(map_addr, 0, map_size); + sigalt_stack_info.ss_sp = map_addr; + sigalt_stack_info.ss_size = map_size; + sigalt_stack_info.ss_flags = 0; + if ((ret = sigaltstack(&sigalt_stack_info, NULL)) != 0) { + goto fail1; + } + + /* Install signal hanlder */ + sig_act.sa_sigaction = signal_callback; + sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; + sigemptyset(&sig_act.sa_mask); + if ((ret = sigaction(SIGSEGV, &sig_act, NULL)) != 0 + || (ret = sigaction(SIGBUS, &sig_act, NULL)) != 0) { + goto fail2; + } + + sigalt_stack_base_addr = map_addr; + signal_handler = handler; + return 0; + +fail2: + memset(&sigalt_stack_info, 0, sizeof(stack_t)); + sigalt_stack_info.ss_flags = SS_DISABLE; + sigalt_stack_info.ss_size = map_size; + sigaltstack(&sigalt_stack_info, NULL); +fail1: + os_munmap(map_addr, map_size); + return ret; +} + +void +os_signal_destroy() +{ + stack_t sigalt_stack_info; + + /* Disable signal alternate stack */ + memset(&sigalt_stack_info, 0, sizeof(stack_t)); + sigalt_stack_info.ss_flags = SS_DISABLE; + sigalt_stack_info.ss_size = SIG_ALT_STACK_SIZE; + sigaltstack(&sigalt_stack_info, NULL); + + os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE); +} + +void +os_signal_unmask() +{ + mask_signals(SIG_UNBLOCK); +} + +void +os_sigreturn() +{ +#if defined(__APPLE__) + #define UC_RESET_ALT_STACK 0x80000000 + extern int __sigreturn(void *, int); + + /* It's necessary to call __sigreturn to restore the sigaltstack state + after exiting the signal handler. */ + __sigreturn(NULL, UC_RESET_ALT_STACK); +#endif +} +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ + diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index 55622028..e0820b32 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -51,6 +51,38 @@ typedef pthread_t korp_thread; #define os_printf printf #define os_vprintf vprintf +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index acf6522a..f7f2cad0 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -110,9 +110,9 @@ enum { MMAP_MAP_FIXED = 2 }; -void *os_mmap(void *hint, unsigned int size, int prot, int flags); -void os_munmap(void *addr, uint32 size); -int os_mprotect(void *addr, uint32 size, int prot); +void *os_mmap(void *hint, size_t size, int prot, int flags); +void os_munmap(void *addr, size_t size); +int os_mprotect(void *addr, size_t size, int prot); /** * Flush cpu data cache, in some CPUs, after applying relocation to the diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index e52df1da..f018db4d 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/core/shared/platform/linux-sgx/sgx_platform.c @@ -82,7 +82,7 @@ int os_vprintf(const char * format, va_list arg) return 0; } -void* os_mmap(void *hint, uint32 size, int prot, int flags) +void* os_mmap(void *hint, size_t size, int prot, int flags) { #if WASM_ENABLE_AOT != 0 int mprot = 0; @@ -124,7 +124,7 @@ void* os_mmap(void *hint, uint32 size, int prot, int flags) #endif } -void os_munmap(void *addr, uint32 size) +void os_munmap(void *addr, size_t size) { #if WASM_ENABLE_AOT != 0 uint64 aligned_size, page_size; @@ -135,11 +135,15 @@ void os_munmap(void *addr, uint32 size) #endif } -int os_mprotect(void *addr, uint32 size, int prot) +int os_mprotect(void *addr, size_t size, int prot) { #if WASM_ENABLE_AOT != 0 int mprot = 0; sgx_status_t st = 0; + uint64 aligned_size, page_size; + + page_size = getpagesize(); + aligned_size = (size + page_size - 1) & ~(page_size - 1); if (prot & MMAP_PROT_READ) mprot |= SGX_PROT_READ; @@ -147,7 +151,7 @@ int os_mprotect(void *addr, uint32 size, int prot) mprot |= SGX_PROT_WRITE; if (prot & MMAP_PROT_EXEC) mprot |= SGX_PROT_EXEC; - st = sgx_tprotect_rsrv_mem(addr, size, mprot); + st = sgx_tprotect_rsrv_mem(addr, aligned_size, mprot); if (st != SGX_SUCCESS) os_printf("os_mprotect(addr=0x%lx, size=%u, prot=0x%x) failed.", addr, size, prot); diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 445d881f..d3bc9d2b 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -51,6 +51,38 @@ typedef pthread_t korp_thread; #define os_printf printf #define os_vprintf vprintf +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index 06b4d3ae..a7836692 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -50,6 +50,38 @@ typedef pthread_t korp_thread; #define os_printf printf #define os_vprintf vprintf +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 0f52d110..d2408948 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -110,16 +110,18 @@ os_vprintf(const char *fmt, va_list ap) } void * -os_mmap(void *hint, unsigned int size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags) { + if ((uint64)size >= UINT32_MAX) + return NULL; if (exec_mem_alloc_func) - return exec_mem_alloc_func(size); + return exec_mem_alloc_func((uint32)size); else return BH_MALLOC(size); } void -os_munmap(void *addr, uint32 size) +os_munmap(void *addr, size_t size) { if (exec_mem_free_func) exec_mem_free_func(addr); @@ -128,7 +130,7 @@ os_munmap(void *addr, uint32 size) } int -os_mprotect(void *addr, uint32 size, int prot) +os_mprotect(void *addr, size_t size, int prot) { return 0; } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index b6d56307..b9405633 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -46,7 +46,7 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the - **WAMR_BUILD_LIBC_BUILTIN**=1/0, default to enable if no set -- **WAMR_BUILD_LIBC_WASI**=1/0, default to disable if no set +- **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if no set #### **Enable Multi-Module feature** @@ -55,7 +55,7 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the #### **Enable WASM mini loader** - **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set -Note: the mini loader doesn't check the integrity of the WASM binary file, user must ensure that the WASM file is not mal-formed. +Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is not mal-formed. #### **Enable shared memory feature** - **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set @@ -63,10 +63,14 @@ Note: the mini loader doesn't check the integrity of the WASM binary file, user #### **Enable thread manager** - **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set -#### **Enable Lib-pthread** +#### **Enable lib-pthread** - **WAMR_BUILD_LIB_PTHREAD**=1/0, default to disable if not set > Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically. +#### **Disable boundary check with hardware trap in AOT or JIT mode** +- **WAMR_DISABLE_HW_BOUND_CHECK=1, default to enable if not set and supported by platform +> Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index 8401da19..b110de3b 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -2,7 +2,7 @@ # Prepare WASM building environments -WASI-SDK version 7.0+ is the major tool supported by WAMR for building WASM applications. There are some other WASM compilers such as the standard clang compiler and Emscripten might also work [here](./other_wasm_compilers.md). +WASI-SDK version 8.0+ is the major tool supported by WAMR to build WASM applications. There are some other WASM compilers such as the standard clang compiler and Emscripten might also work [here](./other_wasm_compilers.md). Install WASI SDK: Download the [wasi-sdk](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk` @@ -38,14 +38,47 @@ int main(int argc, char **argv) } ``` - - -To build the source file to WASM bytecode, input following command: +To build the source file to WASM bytecode, we can input the following command: ``` Bash -/opt/wasi-sdk/bin/clang test.c -o test.wasm +/opt/wasi-sdk/bin/clang -O3 -o test.wasm test.c ``` +There are some useful options which can be specified to build the source code: + +- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the libc-builtin library of WAMR must be built to run the wasm app, otherwise, the libc-wasi library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN** or **-DWAMR_BUILD_LIBC_WASI** for cmake to build WAMR with libc-builtin support or libc-wasi support. + +- **-Wl,--no-entry** Do not output any entry point + +- **-Wl,--export=** Force a symbol to be exported, e.g. **-Wl,--export=main** to export main function + +- **-Wl,--export-all** Export all symbols (normally combined with --no-gc-sections) + +- **-Wl,--initial-memory=** Initial size of the linear memory, which must be a multiple of 65536 + +- **-Wl,--max-memory=** Maximum size of the linear memory, which must be a multiple of 65536 + +- **-z stack-size=** The auxiliary stack size, which is an area of linear memory, and must be smaller than initial memory size. + +- **-Wl,--strip-all** Strip all symbols + +- **-Wl,--shared-memory** Use shared linear memory + +- **-Wl,--threads** or **-Wl,--no-threads** Run or do not run the linker multi-threaded + +- **-Wl,--allow-undefined** Allow undefined symbols in linked binary + +- **-Wl,--allow-undefined-file=** Allow symbols listed in to be undefined in linked binary + +For example, we can build the wasm app with command: +``` Bash +/opt/wasi-sdk/bin/clang -O3 -nostdlib \ + -z stack-size=8192 -Wl,--initial-memory=65536 \ + -Wl,--export=main -o test.wasm test.c \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--no-entry -Wl,--strip-all -Wl,--allow-undefined +``` +to generate a wasm binary with small footprint. # Build a project with cmake diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 642155f4..053e76ea 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -70,6 +70,10 @@ if (NOT DEFINED WAMR_BUILD_MINI_LOADER) set (WAMR_BUILD_MINI_LOADER 0) endif () +if (COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) @@ -108,5 +112,4 @@ install (TARGETS libiwasm DESTINATION lib) set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) -target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) - +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) \ No newline at end of file diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index a0088478..02fadd35 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -15,6 +15,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") add_definitions(-DWASM_ENABLE_INTERP=1) add_definitions(-DWASM_ENABLE_WAMR_COMPILER=1) add_definitions(-DWASM_ENABLE_BULK_MEMORY=1) +add_definitions(-DWASM_DISABLE_HW_BOUND_CHECK=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 72f71707..7b54cd87 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -26,9 +26,13 @@ print_help() printf(" Use +feature to enable a feature, or -feature to disable it\n"); printf(" For example, --cpu-features=+feature1,-feature2\n"); printf(" Use --cpu-features=+help to list all the features supported\n"); - printf(" --opt-level=n Set the optimization level (0 to 3, default: 3, which is fastest)\n"); - printf(" --size-level=n Set the code size level (0 to 3, default: 3, which is smallest)\n"); + printf(" --opt-level=n Set the optimization level (0 to 3, default is 3)\n"); + printf(" --size-level=n Set the code size level (0 to 3, default is 3)\n"); printf(" -sgx Generate code for SGX platform (Intel Software Guard Extention)\n"); + printf(" --bounds-checks=1/0 Enable or disable the bounds checks for memory access:\n"); + printf(" by default it is disabled in all 64-bit platforms except SGX and\n"); + printf(" in these platforms runtime does bounds checks with hardware trap,\n"); + printf(" and by default it is enabled in all 32-bit platforms\n"); printf(" --format= Specifies the format of the output file\n"); printf(" The format supported:\n"); printf(" aot (default) AoT file\n"); @@ -61,6 +65,8 @@ main(int argc, char *argv[]) option.opt_level = 3; option.size_level = 3; option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { @@ -107,6 +113,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "-sgx")) { sgx_mode = true; } + else if (!strncmp(argv[0], "--bounds-checks=", 16)) { + option.bounds_checks = (atoi(argv[0] + 16) == 1) ? 1 : 0; + } else if (!strncmp(argv[0], "--format=", 9)) { if (argv[0][9] == '\0') return print_help(); @@ -138,8 +147,10 @@ main(int argc, char *argv[]) if (argc == 0) return print_help(); - if (sgx_mode) + if (sgx_mode) { option.size_level = 1; + option.is_sgx_platform = true; + } wasm_file_name = argv[0];