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:
liang.he 2021-12-29 11:04:36 +08:00 committed by GitHub
parent 936206f97b
commit 50b6474f54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 654 additions and 219 deletions

7
.gitignore vendored
View File

@ -4,6 +4,10 @@
/.idea /.idea
**/cmake-build-*/ **/cmake-build-*/
**/*build/ **/*build/
*.obj
*.a
*.so
core/deps/** core/deps/**
core/shared/mem-alloc/tlsf core/shared/mem-alloc/tlsf
core/app-framework/wgl core/app-framework/wgl
@ -12,6 +16,9 @@ wamr-sdk/out/
wamr-sdk/runtime/build_runtime_sdk/ wamr-sdk/runtime/build_runtime_sdk/
test-tools/host-tool/bin/ test-tools/host-tool/bin/
product-mini/app-samples/hello-world/test.wasm 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 build_out
tests/wamr-test-suites/workspace tests/wamr-test-suites/workspace

View File

@ -1284,7 +1284,7 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
if (!strcmp(import_funcs[i].module_name, "wasi_unstable") if (!strcmp(import_funcs[i].module_name, "wasi_unstable")
|| !strcmp(import_funcs[i].module_name, "wasi_snapshot_preview1")) || !strcmp(import_funcs[i].module_name, "wasi_snapshot_preview1"))
module->is_wasi_module = true; module->import_wasi_api = true;
#endif #endif
} }
@ -2925,7 +2925,7 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
module->comp_data = comp_data; module->comp_data = comp_data;
#if WASM_ENABLE_LIBC_WASI != 0 #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 #endif
return module; return module;

View File

@ -1059,7 +1059,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
#if WASM_ENABLE_BULK_MEMORY != 0 #if WASM_ENABLE_BULK_MEMORY != 0
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
if (!module->is_wasi_module) { if (!module->import_wasi_api) {
#endif #endif
/* Only execute the memory init function for main instance because /* Only execute the memory init function for main instance because
the data segments will be dropped once initialized. the data segments will be dropped once initialized.

View File

@ -256,7 +256,7 @@ typedef struct AOTModule {
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
WASIArguments wasi_args; WASIArguments wasi_args;
bool is_wasi_module; bool import_wasi_api;
#endif #endif
#if WASM_ENABLE_DEBUG_AOT != 0 #if WASM_ENABLE_DEBUG_AOT != 0
void *elf_hdr; void *elf_hdr;

View File

@ -48,10 +48,6 @@ static union {
/** /**
* Implementation of wasm_application_execute_main() * Implementation of wasm_application_execute_main()
*/ */
static WASMFunctionInstanceCommon *
resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name);
static bool static bool
check_main_func_type(const WASMType *type) 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; bool ret, is_import_func = true;
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
if (wasm_runtime_is_wasi_mode(module_inst)) { /* In wasi mode, we should call function named "_start"
/* In wasi mode, we should call function named "_start" which initializes the wasi envrionment and then calls
which initializes the wasi envrionment and then calls the actual main function. Directly call main function
the actual main function. Directly call main function may cause exception thrown. */
may cause exception thrown. */ if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) {
if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, 0,
return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, NULL);
0, NULL);
/* If no start function was found, we execute
the main function as normal */
} }
#endif /* end of WASM_ENABLE_LIBC_WASI */ #endif /* end of WASM_ENABLE_LIBC_WASI */
if (!(func = resolve_function(module_inst, "main")) if (!(func = wasm_runtime_lookup_function(module_inst, "main", NULL))
&& !(func = resolve_function(module_inst, "__main_argc_argv")) && !(func = wasm_runtime_lookup_function(module_inst,
&& !(func = resolve_function(module_inst, "_main"))) { "__main_argc_argv", NULL))
wasm_runtime_set_exception(module_inst, "lookup main function failed"); && !(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; return false;
} }
@ -238,21 +240,23 @@ parse_function_name(char *orig_function_name, char **p_module_name,
* Implementation of wasm_application_execute_func() * Implementation of wasm_application_execute_func()
*/ */
static WASMFunctionInstanceCommon * static bool
resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name) resolve_function(WASMModuleInstanceCommon *module_inst, const char *name,
WASMFunctionInstanceCommon **out_func,
WASMModuleInstanceCommon **out_module_inst)
{ {
uint32 i = 0; WASMFunctionInstanceCommon *target_func = NULL;
WASMFunctionInstanceCommon *ret = NULL; WASMModuleInstanceCommon *target_inst = NULL;
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
WASMModuleInstance *sub_module_inst = NULL; char *function_name = NULL;
char *orig_name = NULL; char *orig_name = NULL;
char *sub_module_name = NULL; char *sub_module_name = NULL;
char *function_name = NULL;
uint32 length = (uint32)(strlen(name) + 1); uint32 length = (uint32)(strlen(name) + 1);
orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0); orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0);
if (!orig_name) { if (!orig_name) {
return NULL; goto LEAVE;
} }
strncpy(orig_name, name, length); 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); LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name);
if (sub_module_name) { if (sub_module_name) {
sub_module_inst = get_sub_module_inst((WASMModuleInstance *)module_inst, target_inst = (WASMModuleInstanceCommon *)get_sub_module_inst(
sub_module_name); (WASMModuleInstance *)module_inst, sub_module_name);
if (!sub_module_inst) { if (!target_inst) {
LOG_DEBUG("can not find a sub module named %s", sub_module_name); LOG_DEBUG("can not find a sub module named %s", sub_module_name);
goto LEAVE; goto LEAVE;
} }
} }
else {
target_inst = module_inst;
}
#else #else
const char *function_name = name; const char *function_name = name;
target_inst = module_inst;
#endif #endif
#if WASM_ENABLE_INTERP != 0 target_func =
if (module_inst->module_type == Wasm_Module_Bytecode) { wasm_runtime_lookup_function(target_inst, function_name, NULL);
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
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
LEAVE: LEAVE:
wasm_runtime_free(orig_name); if (orig_name)
wasm_runtime_free(orig_name);
#endif #endif
return ret;
*out_func = target_func;
*out_module_inst = target_inst;
return target_func;
} }
union ieee754_float { union ieee754_float {
@ -358,7 +342,8 @@ bool
wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
const char *name, int32 argc, char *argv[]) const char *name, int32 argc, char *argv[])
{ {
WASMFunctionInstanceCommon *func; WASMFunctionInstanceCommon *target_func;
WASMModuleInstanceCommon *target_inst;
WASMType *type = NULL; WASMType *type = NULL;
uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0;
int32 i, p, module_type; int32 i, p, module_type;
@ -368,31 +353,15 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
bh_assert(argc >= 0); bh_assert(argc >= 0);
LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc); 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); snprintf(buf, sizeof(buf), "lookup function %s failed", name);
wasm_runtime_set_exception(module_inst, buf); wasm_runtime_set_exception(module_inst, buf);
goto fail; goto fail;
} }
#if WASM_ENABLE_INTERP != 0 module_type = target_inst->module_type;
if (module_inst->module_type == Wasm_Module_Bytecode) { type = wasm_runtime_get_function_type(target_func, module_type);
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);
if (!type) { if (!type) {
LOG_ERROR("invalid module instance 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; cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num;
total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); 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; goto fail;
} }
@ -538,7 +507,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
void *extern_obj = (void *)(uintptr_t)val; void *extern_obj = (void *)(uintptr_t)val;
uint32 externref_idx; uint32 externref_idx;
if (!wasm_externref_obj2ref(module_inst, extern_obj, if (!wasm_externref_obj2ref(target_inst, extern_obj,
&externref_idx)) { &externref_idx)) {
wasm_runtime_set_exception( wasm_runtime_set_exception(
module_inst, "map extern object to ref failed"); module_inst, "map extern object to ref failed");
@ -563,8 +532,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
bh_assert(p == (int32)argc1); bh_assert(p == (int32)argc1);
wasm_runtime_set_exception(module_inst, NULL); wasm_runtime_set_exception(module_inst, NULL);
if (!wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, argc1, if (!wasm_runtime_create_exec_env_and_call_wasm(target_inst, target_func,
argv1)) { argc1, argv1)) {
goto fail; goto fail;
} }

View File

@ -2294,13 +2294,13 @@ wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst)
{ {
#if WASM_ENABLE_INTERP != 0 #if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode if (module_inst->module_type == Wasm_Module_Bytecode
&& ((WASMModuleInstance *)module_inst)->module->is_wasi_module) && ((WASMModuleInstance *)module_inst)->module->import_wasi_api)
return true; return true;
#endif #endif
#if WASM_ENABLE_AOT != 0 #if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT if (module_inst->module_type == Wasm_Module_AoT
&& ((AOTModule *)((AOTModuleInstance *)module_inst)->aot_module.ptr) && ((AOTModule *)((AOTModuleInstance *)module_inst)->aot_module.ptr)
->is_wasi_module) ->import_wasi_api)
return true; return true;
#endif #endif
return false; return false;

View File

@ -403,7 +403,7 @@ struct WASMModule {
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
WASIArguments wasi_args; WASIArguments wasi_args;
bool is_wasi_module; bool import_wasi_api;
#endif #endif
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0

View File

@ -647,11 +647,11 @@ adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size)
static WASMExport * static WASMExport *
wasm_loader_find_export(const WASMModule *module, const char *module_name, wasm_loader_find_export(const WASMModule *module, const char *module_name,
const char *field_name, uint8 export_kind, const char *field_name, uint8 export_kind,
uint32 export_index_boundary, char *error_buf, char *error_buf, uint32 error_buf_size)
uint32 error_buf_size)
{ {
WASMExport *export; WASMExport *export;
uint32 i; uint32 i;
uint32 export_index_boundary = 0;
for (i = 0, export = module->exports; i < module->export_count; for (i = 0, export = module->exports; i < module->export_count;
++i, ++export) { ++i, ++export) {
@ -674,6 +674,27 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name,
return NULL; 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) { if (export->index >= export_index_boundary) {
LOG_DEBUG("%s in the module %s is out of index (%d >= %d )", field_name, LOG_DEBUG("%s in the module %s is out of index (%d >= %d )", field_name,
module_name, export->index, export_index_boundary); 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; module = (WASMModule *)module_reg;
export = wasm_loader_find_export( export =
module, module_name, function_name, EXPORT_KIND_FUNC, wasm_loader_find_export(module, module_name, function_name,
module->import_function_count + module->function_count, error_buf, EXPORT_KIND_FUNC, error_buf, error_buf_size);
error_buf_size);
if (!export) { if (!export) {
return NULL; return NULL;
} }
@ -755,10 +775,9 @@ wasm_loader_resolve_table(const char *module_name, const char *table_name,
} }
module = (WASMModule *)module_reg; module = (WASMModule *)module_reg;
export = wasm_loader_find_export( export =
module, module_name, table_name, EXPORT_KIND_TABLE, wasm_loader_find_export(module, module_name, table_name,
module->table_count + module->import_table_count, error_buf, EXPORT_KIND_TABLE, error_buf, error_buf_size);
error_buf_size);
if (!export) { if (!export) {
return NULL; return NULL;
} }
@ -800,10 +819,9 @@ wasm_loader_resolve_memory(const char *module_name, const char *memory_name,
} }
module = (WASMModule *)module_reg; module = (WASMModule *)module_reg;
export = wasm_loader_find_export( export =
module, module_name, memory_name, EXPORT_KIND_MEMORY, wasm_loader_find_export(module, module_name, memory_name,
module->import_memory_count + module->memory_count, error_buf, EXPORT_KIND_MEMORY, error_buf, error_buf_size);
error_buf_size);
if (!export) { if (!export) {
return NULL; return NULL;
} }
@ -846,10 +864,9 @@ wasm_loader_resolve_global(const char *module_name, const char *global_name,
} }
module = (WASMModule *)module_reg; module = (WASMModule *)module_reg;
export = wasm_loader_find_export( export =
module, module_name, global_name, EXPORT_KIND_GLOBAL, wasm_loader_find_export(module, module_name, global_name,
module->import_global_count + module->global_count, error_buf, EXPORT_KIND_GLOBAL, error_buf, error_buf_size);
error_buf_size);
if (!export) { if (!export) {
return NULL; return NULL;
} }
@ -969,7 +986,7 @@ load_depended_module(const WASMModule *parent_module,
} }
sub_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) { if (!sub_module) {
LOG_DEBUG("error: can not load the sub_module %s", sub_module_name); LOG_DEBUG("error: can not load the sub_module %s", sub_module_name);
/* others will be destroyed in runtime_destroy() */ /* 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") if (!strcmp(import->u.names.module_name, "wasi_unstable")
|| !strcmp(import->u.names.module_name, || !strcmp(import->u.names.module_name,
"wasi_snapshot_preview1")) { "wasi_snapshot_preview1")) {
module->is_wasi_module = true; module->import_wasi_api = true;
break; break;
} }
} }
@ -3440,9 +3457,129 @@ fail:
return false; 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 * WASMModule *
wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, wasm_loader_load(const uint8 *buf, uint32 size,
uint32 error_buf_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); WASMModule *module = create_module(error_buf, error_buf_size);
if (!module) { if (!module) {
@ -3458,6 +3595,14 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf,
goto fail; 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"); LOG_VERBOSE("Load module success.\n");
return module; return module;

View File

@ -24,8 +24,11 @@ extern "C" {
* @return return module loaded, NULL if failed * @return return module loaded, NULL if failed
*/ */
WASMModule * WASMModule *
wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, wasm_loader_load(const uint8 *buf, uint32 size,
uint32 error_buf_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. * Load a WASM module from a specified WASM section list.

View File

@ -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") if (!strcmp(import->u.names.module_name, "wasi_unstable")
|| !strcmp(import->u.names.module_name, || !strcmp(import->u.names.module_name,
"wasi_snapshot_preview1")) { "wasi_snapshot_preview1")) {
module->is_wasi_module = true; module->import_wasi_api = true;
break; break;
} }
} }
@ -2120,7 +2120,6 @@ load_from_sections(WASMModule *module, WASMSection *sections,
} }
} }
#if WASM_ENABLE_MULTI_MODULE == 0
if (module->import_memory_count) { if (module->import_memory_count) {
memory_import = &module->import_memories[0].u.memory; memory_import = &module->import_memories[0].u.memory;
/* Memory init page count cannot be larger than 65536, we don't /* 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->num_bytes_per_page *= memory_import->init_page_count;
memory_import->init_page_count = memory_import->max_page_count = 1; memory_import->init_page_count = memory_import->max_page_count = 1;
} }
if (module->memory_count) { if (module->memory_count) {
/* Memory init page count cannot be larger than 65536, we don't /* Memory init page count cannot be larger than 65536, we don't
check integer overflow again. */ 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->num_bytes_per_page *= memory->init_page_count;
memory->init_page_count = memory->max_page_count = 1; memory->init_page_count = memory->max_page_count = 1;
} }
#endif
} }
#if WASM_ENABLE_MEMORY_TRACING != 0 #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 */ /* Set start_function to -1, means no start function */
module->start_function = (uint32)-1; module->start_function = (uint32)-1;
#if WASM_ENABLE_MULTI_MODULE != 0
module->import_module_list = &module->import_module_list_head;
#endif
return module; return module;
} }

View File

@ -47,7 +47,11 @@ set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, ...)
WASMModule * WASMModule *
wasm_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) 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 * WASMModule *
@ -105,7 +109,7 @@ memories_deinstantiate(WASMModuleInstance *module_inst,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (memories[i]) { if (memories[i]) {
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
if (memories[i]->owner != module_inst) if (i < module_inst->module->import_memory_count)
continue; continue;
#endif #endif
#if WASM_ENABLE_SHARED_MEMORY != 0 #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); memories_deinstantiate(module_inst, memories, memory_count);
return NULL; 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); memories_deinstantiate(module_inst, memories, memory_count);
return NULL; return NULL;
} }
#if WASM_ENABLE_MULTI_MODULE != 0
memory->owner = module_inst;
#endif
} }
if (mem_index == 0) { if (mem_index == 0) {
@ -1007,15 +1001,17 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
bh_list_first_elem(module->import_module_list); bh_list_first_elem(module->import_module_list);
while (sub_module_list_node) { 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; 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, wasm_instantiate(sub_module, false, stack_size, heap_size,
error_buf, error_buf_size); error_buf, error_buf_size);
if (!sub_module_inst) { if (!sub_module_inst) {
LOG_DEBUG("instantiate %s failed", LOG_DEBUG("instantiate %s failed",
sub_module_list_node->module_name); sub_module_list_node->module_name);
return false; goto failed;
} }
sub_module_inst_list_node = runtime_malloc(sizeof(WASMSubModInstNode), 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) { if (!sub_module_inst_list_node) {
LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d", LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d",
sizeof(WASMSubModInstNode)); sizeof(WASMSubModInstNode));
wasm_deinstantiate(sub_module_inst, false); goto failed;
return false;
} }
sub_module_inst_list_node->module_inst = sub_module_inst; sub_module_inst_list_node->module_inst = sub_module_inst;
@ -1036,6 +1031,39 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
(void)ret; (void)ret;
sub_module_list_node = bh_list_elem_next(sub_module_list_node); 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; 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_BULK_MEMORY != 0
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
if (!module->is_wasi_module) { if (!module->import_wasi_api) {
#endif #endif
/* Only execute the memory init function for main instance because /* Only execute the memory init function for main instance because
the data segments will be dropped once initialized. the data segments will be dropped once initialized.

View File

@ -40,11 +40,6 @@ struct WASMMemoryInstance {
/* The heap created */ /* The heap created */
void *heap_handle; 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 #if WASM_ENABLE_SHARED_MEMORY != 0
/* mutex lock for the memory, used in atomic operation */ /* mutex lock for the memory, used in atomic operation */
korp_mutex mem_lock; korp_mutex mem_lock;

View File

@ -1,7 +1,7 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved. # Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # 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) project(multi_module)
################ runtime settings ################ ################ runtime settings ################
@ -41,7 +41,7 @@ set(WAMR_BUILD_INTERP 1)
set(WAMR_BUILD_AOT 0) set(WAMR_BUILD_AOT 0)
set(WAMR_BUILD_JIT 0) set(WAMR_BUILD_JIT 0)
set(WAMR_BUILD_LIBC_BUILTIN 1) set(WAMR_BUILD_LIBC_BUILTIN 1)
set(WAMR_BUILD_LIBC_WASI 0) set(WAMR_BUILD_LIBC_WASI 1)
set(WAMR_BUILD_MULTI_MODULE 1) set(WAMR_BUILD_MULTI_MODULE 1)
# compiling and linking flags # compiling and linking flags
@ -66,8 +66,79 @@ add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE})
################ application related ################ ################ application related ################
################ WASM MODULES ################ 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 # .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 ################ NATIVE
include_directories(${CMAKE_CURRENT_LIST_DIR}/src) 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_executable(multi_module src/main.c ${UNCOMMON_SHARED_SOURCE})
add_dependencies(multi_module vmlib wasm-modules) add_dependencies(multi_module vmlib WASM_MODULE)
# libraries # libraries
target_link_libraries(multi_module PRIVATE vmlib -lpthread -lm) target_link_libraries(multi_module PRIVATE vmlib -lpthread -lm)

View File

@ -9,7 +9,7 @@
static char * static char *
build_module_path(const char *module_name) 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"; const char *format = "%s/%s.wasm";
int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) int sz = strlen(module_search_path) + strlen("/") + strlen(module_name)
+ strlen(".wasm") + 1; + strlen(".wasm") + 1;
@ -107,24 +107,36 @@ main()
goto UNLOAD_MODULE; goto UNLOAD_MODULE;
} }
/* call some functions of mC */ /* call functions of mC */
printf("\n----------------------------------------\n"); printf("\n----------------------------------------\n");
printf("call \"C\", it will return 0xc:i32, ===> "); printf("call \"C1\", it will return 0x1f:i32, ===> ");
wasm_application_execute_func(module_inst, "C", 0, &args[0]); wasm_application_execute_func(module_inst, "C1", 0, args);
printf("call \"call_B\", it will return 0xb:i32, ===> "); printf("call \"C2\", it will call B1() of mB and return 0x15:i32, ===> ");
wasm_application_execute_func(module_inst, "call_B", 0, &args[0]); wasm_application_execute_func(module_inst, "C2", 0, args);
printf("call \"call_A\", it will return 0xa:i32, ===>"); printf("call \"C3\", it will call A1() of mA and return 0xb:i32, ===> ");
wasm_application_execute_func(module_inst, "call_A", 0, &args[0]); 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 */ /* call functions of mB */
printf("call \"mB.B\", it will return 0xb:i32, ===>"); printf("call \"mB.B1\", it will return 0x15:i32, ===> ");
wasm_application_execute_func(module_inst, "$mB$B", 0, &args[0]); wasm_application_execute_func(module_inst, "$mB$B1", 0, args);
printf("call \"mB.call_A\", it will return 0xa:i32, ===>"); printf("call \"mB.B2\", it will call A1() of mA and return 0xb:i32, ===> ");
wasm_application_execute_func(module_inst, "$mB$call_A", 0, &args[0]); 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 */ /* call functions of mA */
printf("call \"mA.A\", it will return 0xa:i32, ===>"); printf("call \"mA.A1\", it will return 0xb:i32, ===>");
wasm_application_execute_func(module_inst, "$mA$A", 0, &args[0]); 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"); printf("----------------------------------------\n\n");
ret = true; ret = true;

View File

@ -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) 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}/../../..) message(CHECK_START "Detecting WASM_OBJDUMP at ${WABT_DIR}")
set(CLANG_COMMAND "/opt/wasi-sdk/bin/clang") find_program(WASM_OBJDUMP
wasm-objdump
set(CLANG_FLAGS --target=wasm32 -nostdlib) PATHS "${WABT_DIR}/bin"
set(CLANG_FLAGS ${CLANG_FLAGS} -Wl,--no-entry,--allow-undefined,--export-all) NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
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
) )
if(WASM_OBJDUMP)
message(CHECK_PASS "found")
else()
message(CHECK_FAIL "not found")
endif()
set(SOURCE_B ${CMAKE_CURRENT_SOURCE_DIR}/mB.c) message(CHECK_START "Detecting WASM2WAT at ${WABT_DIR}")
add_custom_command( find_program(WASM2WAT
OUTPUT mB.wasm wasm2wat
COMMENT "Transform mB.C to mB.WASM" PATHS "${WABT_DIR}/bin"
COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mB.wasm ${SOURCE_B} NO_DEFAULT_PATH
DEPENDS ${SOURCE_B} NO_CMAKE_FIND_ROOT_PATH
VERBATIM
) )
if(WASM2WAT)
message(CHECK_PASS "found")
else()
message(CHECK_FAIL "not found")
endif()
set(SOURCE_C ${CMAKE_CURRENT_SOURCE_DIR}/mC.c) function(COMPILE_WITH_CLANG SOURCE_FILE COMMAND)
add_custom_command( get_filename_component(FILE_NAME ${SOURCE_FILE} NAME_WLE)
OUTPUT mC.wasm
COMMENT "Transform mC.C to mC.WASM" set(WASM_MODULE ${FILE_NAME}.wasm)
COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mC.wasm ${SOURCE_C}
DEPENDS ${SOURCE_C} set(MAIN_TARGET_NAME MODULE_${FILE_NAME})
VERBATIM
) 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
)

View File

@ -1,5 +1,13 @@
int __attribute__((export_name("A1"))) int
A() A1()
{ {
return 10; return 11;
} }
int
A2()
{
return 12;
}
/* mA is a reactor. it doesn't need a main() */

View File

@ -1,15 +1,23 @@
__attribute__((import_module("mA"))) __attribute__((import_module("mA")))
__attribute__((import_name("A"))) extern int __attribute__((import_name("A1"))) extern int
A(); A1();
int __attribute__((export_name("B1"))) int
B() B1()
{ {
return 11; return 21;
}
__attribute__((export_name("B2"))) int
B2()
{
return A1();
} }
int int
call_A() B3()
{ {
return A(); return 23;
} }
/* mA is a reactor. it doesn't need a main() */

View File

@ -1,25 +1,51 @@
#include <stdio.h>
#include <stdlib.h>
__attribute__((import_module("mA"))) __attribute__((import_module("mA")))
__attribute__((import_name("A"))) extern int __attribute__((import_name("A1"))) extern int
A(); A1();
__attribute__((import_module("mB"))) __attribute__((import_module("mB")))
__attribute__((import_name("B"))) extern int __attribute__((import_name("B1"))) extern int
B(); B1();
int __attribute__((import_module("mB")))
C() __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 int
call_A() C5()
{ {
return A(); return C1() + C2() + C3() + 35;
} }
int int
call_B() main()
{ {
return B(); printf("%u\n", C5());
return EXIT_SUCCESS;
} }

View 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;
}

View 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;
}