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