Prechádzať zdrojové kódy

Add no_resolve to LoadArgs and wasm_runtime_resolve_symbols (#3790)

Add no_resolve to LoadArgs and wasm_runtime_resolve_symbols so one can
delay resolving of symbols.

This is useful for inspecting the module between loading and instantiating.
Anders Bakken 1 rok pred
rodič
commit
21330990a8

+ 21 - 129
core/iwasm/aot/aot_loader.c

@@ -634,73 +634,6 @@ str2uint32(const char *buf, uint32 *p_res);
 static bool
 str2uint64(const char *buf, uint64 *p_res);
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-static void *
-aot_loader_resolve_function(const AOTModule *module, const char *function_name,
-                            const AOTFuncType *expected_function_type,
-                            char *error_buf, uint32 error_buf_size);
-
-static void *
-aot_loader_resolve_function_ex(const char *module_name,
-                               const char *function_name,
-                               const AOTFuncType *expected_function_type,
-                               char *error_buf, uint32 error_buf_size)
-{
-    WASMModuleCommon *module_reg;
-
-    module_reg = wasm_runtime_find_module_registered(module_name);
-    if (!module_reg || module_reg->module_type != Wasm_Module_AoT) {
-        LOG_DEBUG("can not find a module named %s for function %s", module_name,
-                  function_name);
-        set_error_buf(error_buf, error_buf_size, "unknown import");
-        return NULL;
-    }
-    return aot_loader_resolve_function((AOTModule *)module_reg, function_name,
-                                       expected_function_type, error_buf,
-                                       error_buf_size);
-}
-
-static void *
-aot_loader_resolve_function(const AOTModule *module, const char *function_name,
-                            const AOTFuncType *expected_function_type,
-                            char *error_buf, uint32 error_buf_size)
-{
-    void *function = NULL;
-    AOTExport *export = NULL;
-    AOTFuncType *target_function_type = NULL;
-
-    export = loader_find_export((WASMModuleCommon *)module, module->name,
-                                function_name, EXPORT_KIND_FUNC, error_buf,
-                                error_buf_size);
-    if (!export) {
-        return NULL;
-    }
-
-    /* resolve function type and function */
-    if (export->index < module->import_func_count) {
-        target_function_type = module->import_funcs[export->index].func_type;
-        function = module->import_funcs[export->index].func_ptr_linked;
-    }
-    else {
-        target_function_type =
-            (AOTFuncType *)module
-                ->types[module->func_type_indexes[export->index
-                                                  - module->import_func_count]];
-        function =
-            (module->func_ptrs[export->index - module->import_func_count]);
-    }
-    /* check function type */
-    if (!wasm_type_equal((WASMType *)expected_function_type,
-                         (WASMType *)target_function_type, module->types,
-                         module->type_count)) {
-        LOG_DEBUG("%s.%s failed the type check", module->name, function_name);
-        set_error_buf(error_buf, error_buf_size, "incompatible import type");
-        return NULL;
-    }
-    return function;
-}
-#endif /* end of WASM_ENABLE_MULTI_MODULE */
-
 static bool
 load_native_symbol_section(const uint8 *buf, const uint8 *buf_end,
                            AOTModule *module, bool is_load_from_file_buf,
@@ -2285,19 +2218,13 @@ destroy_import_funcs(AOTImportFunc *import_funcs)
 
 static bool
 load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
-                  bool is_load_from_file_buf, char *error_buf,
+                  bool is_load_from_file_buf, bool no_resolve, char *error_buf,
                   uint32 error_buf_size)
 {
-    char *module_name, *field_name;
     const uint8 *buf = *p_buf;
     AOTImportFunc *import_funcs;
     uint64 size;
     uint32 i;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    AOTModule *sub_module = NULL;
-    AOTFunc *linked_func = NULL;
-    AOTFuncType *declare_func_type = NULL;
-#endif
 
     /* Allocate memory */
     size = sizeof(AOTImportFunc) * (uint64)module->import_func_count;
@@ -2314,53 +2241,17 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
             return false;
         }
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-        declare_func_type =
-            (AOTFuncType *)module->types[import_funcs[i].func_type_index];
-        read_string(buf, buf_end, module_name);
-        read_string(buf, buf_end, field_name);
-
-        import_funcs[i].module_name = module_name;
-        import_funcs[i].func_name = field_name;
-        linked_func = wasm_native_resolve_symbol(
-            module_name, field_name, declare_func_type,
-            &import_funcs[i].signature, &import_funcs[i].attachment,
-            &import_funcs[i].call_conv_raw);
-        if (!linked_func) {
-            sub_module = NULL;
-            if (!wasm_runtime_is_built_in_module(module_name)) {
-                sub_module = (AOTModule *)wasm_runtime_load_depended_module(
-                    (WASMModuleCommon *)module, module_name, error_buf,
-                    error_buf_size);
-                if (!sub_module) {
-                    LOG_ERROR("failed to load sub module: %s", error_buf);
-                    return false;
-                }
-            }
-            if (!sub_module)
-                linked_func = aot_loader_resolve_function_ex(
-                    module_name, field_name, declare_func_type, error_buf,
-                    error_buf_size);
-            else
-                linked_func = aot_loader_resolve_function(
-                    sub_module, field_name, declare_func_type, error_buf,
-                    error_buf_size);
-        }
-        import_funcs[i].func_ptr_linked = linked_func;
-        import_funcs[i].func_type = declare_func_type;
-
-#else
         import_funcs[i].func_type =
             (AOTFuncType *)module->types[import_funcs[i].func_type_index];
         read_string(buf, buf_end, import_funcs[i].module_name);
         read_string(buf, buf_end, import_funcs[i].func_name);
-        module_name = import_funcs[i].module_name;
-        field_name = import_funcs[i].func_name;
-        import_funcs[i].func_ptr_linked = wasm_native_resolve_symbol(
-            module_name, field_name, import_funcs[i].func_type,
-            &import_funcs[i].signature, &import_funcs[i].attachment,
-            &import_funcs[i].call_conv_raw);
-#endif
+        import_funcs[i].attachment = NULL;
+        import_funcs[i].signature = NULL;
+        import_funcs[i].call_conv_raw = false;
+
+        if (!no_resolve) {
+            aot_resolve_import_func(module, &import_funcs[i]);
+        }
 
 #if WASM_ENABLE_LIBC_WASI != 0
         if (!strcmp(import_funcs[i].module_name, "wasi_unstable")
@@ -2378,7 +2269,7 @@ fail:
 static bool
 load_import_func_info(const uint8 **p_buf, const uint8 *buf_end,
                       AOTModule *module, bool is_load_from_file_buf,
-                      char *error_buf, uint32 error_buf_size)
+                      bool no_resolve, char *error_buf, uint32 error_buf_size)
 {
     const uint8 *buf = *p_buf;
 
@@ -2387,7 +2278,7 @@ load_import_func_info(const uint8 **p_buf, const uint8 *buf_end,
     /* load import funcs */
     if (module->import_func_count > 0
         && !load_import_funcs(&buf, buf_end, module, is_load_from_file_buf,
-                              error_buf, error_buf_size))
+                              no_resolve, error_buf, error_buf_size))
         return false;
 
     *p_buf = buf;
@@ -2514,7 +2405,7 @@ fail:
 static bool
 load_init_data_section(const uint8 *buf, const uint8 *buf_end,
                        AOTModule *module, bool is_load_from_file_buf,
-                       char *error_buf, uint32 error_buf_size)
+                       bool no_resolve, char *error_buf, uint32 error_buf_size)
 {
     const uint8 *p = buf, *p_end = buf_end;
 
@@ -2525,7 +2416,7 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end,
                                     error_buf, error_buf_size)
         || !load_global_info(&p, p_end, module, error_buf, error_buf_size)
         || !load_import_func_info(&p, p_end, module, is_load_from_file_buf,
-                                  error_buf, error_buf_size))
+                                  no_resolve, error_buf, error_buf_size))
         return false;
 
     /* load function count and start function index */
@@ -3819,7 +3710,7 @@ has_module_memory64(AOTModule *module)
 
 static bool
 load_from_sections(AOTModule *module, AOTSection *sections,
-                   bool is_load_from_file_buf, char *error_buf,
+                   bool is_load_from_file_buf, bool no_resolve, char *error_buf,
                    uint32 error_buf_size)
 {
     AOTSection *section = sections;
@@ -3852,8 +3743,8 @@ load_from_sections(AOTModule *module, AOTSection *sections,
                 break;
             case AOT_SECTION_TYPE_INIT_DATA:
                 if (!load_init_data_section(buf, buf_end, module,
-                                            is_load_from_file_buf, error_buf,
-                                            error_buf_size))
+                                            is_load_from_file_buf, no_resolve,
+                                            error_buf, error_buf_size))
                     return false;
                 break;
             case AOT_SECTION_TYPE_TEXT:
@@ -4076,7 +3967,7 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf,
     if (!module)
         return NULL;
 
-    if (!load_from_sections(module, section_list, false, error_buf,
+    if (!load_from_sections(module, section_list, false, false, error_buf,
                             error_buf_size)) {
         aot_unload(module);
         return NULL;
@@ -4246,7 +4137,8 @@ fail:
 
 static bool
 load(const uint8 *buf, uint32 size, AOTModule *module,
-     bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size)
+     bool wasm_binary_freeable, bool no_resolve, char *error_buf,
+     uint32 error_buf_size)
 {
     const uint8 *buf_end = buf + size;
     const uint8 *p = buf, *p_end = buf_end;
@@ -4273,7 +4165,7 @@ load(const uint8 *buf, uint32 size, AOTModule *module,
         return false;
 
     ret = load_from_sections(module, section_list, !wasm_binary_freeable,
-                             error_buf, error_buf_size);
+                             no_resolve, error_buf, error_buf_size);
     if (!ret) {
         /* If load_from_sections() fails, then aot text is destroyed
            in destroy_sections() */
@@ -4321,8 +4213,8 @@ aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args,
         return NULL;
 
     os_thread_jit_write_protect_np(false); /* Make memory writable */
-    if (!load(buf, size, module, args->wasm_binary_freeable, error_buf,
-              error_buf_size)) {
+    if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve,
+              error_buf, error_buf_size)) {
         aot_unload(module);
         return NULL;
     }

+ 122 - 0
core/iwasm/aot/aot_runtime.c

@@ -5111,3 +5111,125 @@ aot_get_module_name(AOTModule *module)
 {
     return module->name;
 }
+
+bool
+aot_resolve_symbols(AOTModule *module)
+{
+    bool ret = true;
+    uint32 idx;
+    for (idx = 0; idx < module->import_func_count; ++idx) {
+        AOTImportFunc *aot_import_func = &module->import_funcs[idx];
+        if (!aot_import_func->func_ptr_linked) {
+            if (!aot_resolve_import_func(module, aot_import_func)) {
+                LOG_WARNING("Failed to link function (%s, %s)",
+                            aot_import_func->module_name,
+                            aot_import_func->func_name);
+                ret = false;
+            }
+        }
+    }
+    return ret;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static void *
+aot_resolve_function(const AOTModule *module, const char *function_name,
+                     const AOTFuncType *expected_function_type, char *error_buf,
+                     uint32 error_buf_size);
+
+static void *
+aot_resolve_function_ex(const char *module_name, const char *function_name,
+                        const AOTFuncType *expected_function_type,
+                        char *error_buf, uint32 error_buf_size)
+{
+    WASMModuleCommon *module_reg;
+
+    module_reg = wasm_runtime_find_module_registered(module_name);
+    if (!module_reg || module_reg->module_type != Wasm_Module_AoT) {
+        LOG_DEBUG("can not find a module named %s for function %s", module_name,
+                  function_name);
+        set_error_buf(error_buf, error_buf_size, "unknown import");
+        return NULL;
+    }
+    return aot_resolve_function((AOTModule *)module_reg, function_name,
+                                expected_function_type, error_buf,
+                                error_buf_size);
+}
+
+static void *
+aot_resolve_function(const AOTModule *module, const char *function_name,
+                     const AOTFuncType *expected_function_type, char *error_buf,
+                     uint32 error_buf_size)
+{
+    void *function = NULL;
+    AOTExport *export = NULL;
+    AOTFuncType *target_function_type = NULL;
+
+    export = loader_find_export((WASMModuleCommon *)module, module->name,
+                                function_name, EXPORT_KIND_FUNC, error_buf,
+                                error_buf_size);
+    if (!export) {
+        return NULL;
+    }
+
+    /* resolve function type and function */
+    if (export->index < module->import_func_count) {
+        target_function_type = module->import_funcs[export->index].func_type;
+        function = module->import_funcs[export->index].func_ptr_linked;
+    }
+    else {
+        target_function_type =
+            (AOTFuncType *)module
+                ->types[module->func_type_indexes[export->index
+                                                  - module->import_func_count]];
+        function =
+            (module->func_ptrs[export->index - module->import_func_count]);
+    }
+    /* check function type */
+    if (!wasm_type_equal((WASMType *)expected_function_type,
+                         (WASMType *)target_function_type, module->types,
+                         module->type_count)) {
+        LOG_DEBUG("%s.%s failed the type check", module->name, function_name);
+        set_error_buf(error_buf, error_buf_size, "incompatible import type");
+        return NULL;
+    }
+    return function;
+}
+#endif /* end of WASM_ENABLE_MULTI_MODULE */
+
+bool
+aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func)
+{
+#if WASM_ENABLE_MULTI_MODULE != 0
+    char error_buf[128];
+    AOTModule *sub_module = NULL;
+#endif
+    import_func->func_ptr_linked = wasm_native_resolve_symbol(
+        import_func->module_name, import_func->func_name,
+        import_func->func_type, &import_func->signature,
+        &import_func->attachment, &import_func->call_conv_raw);
+#if WASM_ENABLE_MULTI_MODULE != 0
+    if (!import_func->func_ptr_linked) {
+        if (!wasm_runtime_is_built_in_module(import_func->module_name)) {
+            sub_module = (AOTModule *)wasm_runtime_load_depended_module(
+                (WASMModuleCommon *)module, import_func->module_name, error_buf,
+                sizeof(error_buf));
+            if (!sub_module) {
+                LOG_WARNING("Failed to load sub module: %s", error_buf);
+            }
+            if (!sub_module)
+                import_func->func_ptr_linked = aot_resolve_function_ex(
+                    import_func->module_name, import_func->func_name,
+                    import_func->func_type, error_buf, sizeof(error_buf));
+            else
+                import_func->func_ptr_linked = aot_resolve_function(
+                    sub_module, import_func->func_name, import_func->func_type,
+                    error_buf, sizeof(error_buf));
+            if (!import_func->func_ptr_linked) {
+                LOG_WARNING("Failed to link function: %s", error_buf);
+            }
+        }
+    }
+#endif
+    return import_func->func_ptr_linked != NULL;
+}

+ 12 - 0
core/iwasm/aot/aot_runtime.h

@@ -492,6 +492,18 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf,
 void
 aot_unload(AOTModule *module);
 
+/**
+ * Resolve symbols for an AOT module
+ */
+bool
+aot_resolve_symbols(AOTModule *module);
+
+/**
+ * Helper function to resolve a single function
+ */
+bool
+aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func);
+
 /**
  * Instantiate a AOT module.
  *

+ 16 - 0
core/iwasm/common/wasm_runtime_common.c

@@ -1484,6 +1484,22 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args,
                                           error_buf_size);
 }
 
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_resolve_symbols(WASMModuleCommon *module)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        return wasm_resolve_symbols((WASMModule *)module);
+    }
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        return aot_resolve_symbols((AOTModule *)module);
+    }
+#endif
+    return false;
+}
+
 WASMModuleCommon *
 wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
                   uint32 error_buf_size)

+ 4 - 0
core/iwasm/include/wasm_c_api.h

@@ -534,6 +534,10 @@ typedef struct LoadArgs {
     bool clone_wasm_binary;
     /* This option is only used by the AOT/wasm loader (see wasm_export.h) */
     bool wasm_binary_freeable;
+    /* false by default, if true, don't resolve the symbols yet. The
+       wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols
+       call */
+    bool no_resolve;
     /* TODO: more fields? */
 } LoadArgs;
 #endif /* LOAD_ARGS_OPTION_DEFINED */

+ 11 - 0
core/iwasm/include/wasm_export.h

@@ -252,6 +252,11 @@ typedef struct LoadArgs {
     const strings), making it possible to free the wasm binary buffer after
     loading. */
     bool wasm_binary_freeable;
+
+    /* false by default, if true, don't resolve the symbols yet. The
+       wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols
+       call */
+    bool no_resolve;
     /* TODO: more fields? */
 } LoadArgs;
 #endif /* LOAD_ARGS_OPTION_DEFINED */
@@ -569,6 +574,12 @@ WASM_RUNTIME_API_EXTERN wasm_module_t
 wasm_runtime_load_ex(uint8_t *buf, uint32_t size, const LoadArgs *args,
                      char *error_buf, uint32_t error_buf_size);
 
+/**
+ * Resolve symbols for a previously loaded WASM module. Only useful when the
+ * module was loaded with LoadArgs::no_resolve set to true
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_resolve_symbols(wasm_module_t module);
 /**
  * Load a WASM module from a specified WASM or AOT section list.
  *

+ 26 - 112
core/iwasm/interpreter/wasm_loader.c

@@ -2246,60 +2246,6 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name,
 #endif
 
 #if WASM_ENABLE_MULTI_MODULE != 0
-static WASMFunction *
-wasm_loader_resolve_function(const char *module_name, const char *function_name,
-                             const WASMFuncType *expected_function_type,
-                             char *error_buf, uint32 error_buf_size)
-{
-    WASMModuleCommon *module_reg;
-    WASMFunction *function = NULL;
-    WASMExport *export = NULL;
-    WASMModule *module = NULL;
-    WASMFuncType *target_function_type = NULL;
-
-    module_reg = wasm_runtime_find_module_registered(module_name);
-    if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
-        LOG_DEBUG("can not find a module named %s for function %s", module_name,
-                  function_name);
-        set_error_buf(error_buf, error_buf_size, "unknown import");
-        return NULL;
-    }
-
-    module = (WASMModule *)module_reg;
-    export =
-        wasm_loader_find_export(module, module_name, function_name,
-                                EXPORT_KIND_FUNC, error_buf, error_buf_size);
-    if (!export) {
-        return NULL;
-    }
-
-    /* resolve function type and function */
-    if (export->index < module->import_function_count) {
-        target_function_type =
-            module->import_functions[export->index].u.function.func_type;
-        function = module->import_functions[export->index]
-                       .u.function.import_func_linked;
-    }
-    else {
-        target_function_type =
-            module->functions[export->index - module->import_function_count]
-                ->func_type;
-        function =
-            module->functions[export->index - module->import_function_count];
-    }
-
-    /* check function type */
-    if (!wasm_type_equal((WASMType *)expected_function_type,
-                         (WASMType *)target_function_type, module->types,
-                         module->type_count)) {
-        LOG_DEBUG("%s.%s failed the type check", module_name, function_name);
-        set_error_buf(error_buf, error_buf_size, "incompatible import type");
-        return NULL;
-    }
-
-    return function;
-}
-
 static WASMTable *
 wasm_loader_resolve_table(const char *module_name, const char *table_name,
                           uint32 init_size, uint32 max_size, char *error_buf,
@@ -2494,21 +2440,11 @@ static bool
 load_function_import(const uint8 **p_buf, const uint8 *buf_end,
                      const WASMModule *parent_module,
                      const char *sub_module_name, const char *function_name,
-                     WASMFunctionImport *function, char *error_buf,
-                     uint32 error_buf_size)
+                     WASMFunctionImport *function, bool no_resolve,
+                     char *error_buf, uint32 error_buf_size)
 {
     const uint8 *p = *p_buf, *p_end = buf_end;
     uint32 declare_type_index = 0;
-    WASMFuncType *declare_func_type = NULL;
-    WASMFunction *linked_func = NULL;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    WASMModule *sub_module = NULL;
-    bool is_built_in_module = false;
-#endif
-    const char *linked_signature = NULL;
-    void *linked_attachment = NULL;
-    bool linked_call_conv_raw = false;
-    bool is_native_symbol = false;
 
     read_leb_uint32(p, p_end, declare_type_index);
     *p_buf = p;
@@ -2527,43 +2463,19 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end,
         parent_module->types, parent_module->type_count, declare_type_index);
 #endif
 
-    declare_func_type =
+    function->func_type =
         (WASMFuncType *)parent_module->types[declare_type_index];
 
-    /* lookup registered native symbols first */
-    linked_func = wasm_native_resolve_symbol(
-        sub_module_name, function_name, declare_func_type, &linked_signature,
-        &linked_attachment, &linked_call_conv_raw);
-    if (linked_func) {
-        is_native_symbol = true;
-    }
-#if WASM_ENABLE_MULTI_MODULE != 0
-    else {
-        if (!(is_built_in_module =
-                  wasm_runtime_is_built_in_module(sub_module_name))) {
-            sub_module = (WASMModule *)wasm_runtime_load_depended_module(
-                (WASMModuleCommon *)parent_module, sub_module_name, error_buf,
-                error_buf_size);
-        }
-        if (is_built_in_module || sub_module)
-            linked_func = wasm_loader_resolve_function(
-                sub_module_name, function_name, declare_func_type, error_buf,
-                error_buf_size);
-    }
-#endif
-
     function->module_name = (char *)sub_module_name;
     function->field_name = (char *)function_name;
-    function->func_type = declare_func_type;
-    /* func_ptr_linked is for native registered symbol */
-    function->func_ptr_linked = is_native_symbol ? linked_func : NULL;
-    function->signature = linked_signature;
-    function->attachment = linked_attachment;
-    function->call_conv_raw = linked_call_conv_raw;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    function->import_module = is_native_symbol ? NULL : sub_module;
-    function->import_func_linked = is_native_symbol ? NULL : linked_func;
-#endif
+    function->attachment = NULL;
+    function->signature = NULL;
+    function->call_conv_raw = false;
+
+    /* lookup registered native symbols first */
+    if (!no_resolve) {
+        wasm_resolve_import_func(parent_module, function);
+    }
     return true;
 fail:
     return false;
@@ -3258,8 +3170,8 @@ fail:
 
 static bool
 load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
-                    bool is_load_from_file_buf, char *error_buf,
-                    uint32 error_buf_size)
+                    bool is_load_from_file_buf, bool no_resolve,
+                    char *error_buf, uint32 error_buf_size)
 {
     const uint8 *p = buf, *p_end = buf_end, *p_old;
     uint32 import_count, name_len, type_index, i, u32, flags;
@@ -3442,9 +3354,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                 case IMPORT_KIND_FUNC: /* import function */
                     bh_assert(import_functions);
                     import = import_functions++;
-                    if (!load_function_import(
-                            &p, p_end, module, sub_module_name, field_name,
-                            &import->u.function, error_buf, error_buf_size)) {
+                    if (!load_function_import(&p, p_end, module,
+                                              sub_module_name, field_name,
+                                              &import->u.function, no_resolve,
+                                              error_buf, error_buf_size)) {
                         return false;
                     }
                     break;
@@ -5760,7 +5673,7 @@ static void **handle_table;
 static bool
 load_from_sections(WASMModule *module, WASMSection *sections,
                    bool is_load_from_file_buf, bool wasm_binary_freeable,
-                   char *error_buf, uint32 error_buf_size)
+                   bool no_resolve, char *error_buf, uint32 error_buf_size)
 {
     WASMExport *export;
     WASMSection *section = sections;
@@ -5817,8 +5730,8 @@ load_from_sections(WASMModule *module, WASMSection *sections,
                 break;
             case SECTION_TYPE_IMPORT:
                 if (!load_import_section(buf, buf_end, module,
-                                         reuse_const_strings, error_buf,
-                                         error_buf_size))
+                                         reuse_const_strings, no_resolve,
+                                         error_buf, error_buf_size))
                     return false;
                 break;
             case SECTION_TYPE_FUNC:
@@ -6343,7 +6256,7 @@ wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf,
     if (!module)
         return NULL;
 
-    if (!load_from_sections(module, section_list, false, true, error_buf,
+    if (!load_from_sections(module, section_list, false, true, false, error_buf,
                             error_buf_size)) {
         wasm_loader_unload(module);
         return NULL;
@@ -6488,7 +6401,8 @@ static union {
 
 static bool
 load(const uint8 *buf, uint32 size, WASMModule *module,
-     bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size)
+     bool wasm_binary_freeable, bool no_resolve, char *error_buf,
+     uint32 error_buf_size)
 {
     const uint8 *buf_end = buf + size;
     const uint8 *p = buf, *p_end = buf_end;
@@ -6519,7 +6433,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module,
 
     if (!create_sections(buf, size, &section_list, error_buf, error_buf_size)
         || !load_from_sections(module, section_list, true, wasm_binary_freeable,
-                               error_buf, error_buf_size)) {
+                               no_resolve, error_buf, error_buf_size)) {
         destroy_sections(section_list);
         return false;
     }
@@ -6695,8 +6609,8 @@ wasm_loader_load(uint8 *buf, uint32 size,
     module->load_size = size;
 #endif
 
-    if (!load(buf, size, module, args->wasm_binary_freeable, error_buf,
-              error_buf_size)) {
+    if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve,
+              error_buf, error_buf_size)) {
         goto fail;
     }
 

+ 118 - 0
core/iwasm/interpreter/wasm_runtime.c

@@ -83,6 +83,124 @@ wasm_unload(WASMModule *module)
     wasm_loader_unload(module);
 }
 
+bool
+wasm_resolve_symbols(WASMModule *module)
+{
+    bool ret = true;
+    uint32 idx;
+    for (idx = 0; idx < module->import_function_count; ++idx) {
+        WASMFunctionImport *import = &module->import_functions[idx].u.function;
+        bool linked = import->func_ptr_linked;
+#if WASM_ENABLE_MULTI_MODULE != 0
+        if (import->import_func_linked) {
+            linked = true;
+        }
+#endif
+        if (!linked && !wasm_resolve_import_func(module, import)) {
+            ret = false;
+        }
+    }
+    return ret;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static WASMFunction *
+wasm_resolve_function(const char *module_name, const char *function_name,
+                      const WASMFuncType *expected_function_type,
+                      char *error_buf, uint32 error_buf_size)
+{
+    WASMModuleCommon *module_reg;
+    WASMFunction *function = NULL;
+    WASMExport *export = NULL;
+    WASMModule *module = NULL;
+    WASMFuncType *target_function_type = NULL;
+
+    module_reg = wasm_runtime_find_module_registered(module_name);
+    if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
+        LOG_DEBUG("can not find a module named %s for function %s", module_name,
+                  function_name);
+        set_error_buf(error_buf, error_buf_size, "unknown import");
+        return NULL;
+    }
+
+    module = (WASMModule *)module_reg;
+    export = loader_find_export((WASMModuleCommon *)module, module_name,
+                                function_name, EXPORT_KIND_FUNC, error_buf,
+                                error_buf_size);
+    if (!export) {
+        return NULL;
+    }
+
+    /* resolve function type and function */
+    if (export->index < module->import_function_count) {
+        target_function_type =
+            module->import_functions[export->index].u.function.func_type;
+        function = module->import_functions[export->index]
+                       .u.function.import_func_linked;
+    }
+    else {
+        target_function_type =
+            module->functions[export->index - module->import_function_count]
+                ->func_type;
+        function =
+            module->functions[export->index - module->import_function_count];
+    }
+
+    /* check function type */
+    if (!wasm_type_equal((WASMType *)expected_function_type,
+                         (WASMType *)target_function_type, module->types,
+                         module->type_count)) {
+        LOG_DEBUG("%s.%s failed the type check", module_name, function_name);
+        set_error_buf(error_buf, error_buf_size, "incompatible import type");
+        return NULL;
+    }
+
+    return function;
+}
+#endif
+
+bool
+wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function)
+{
+#if WASM_ENABLE_MULTI_MODULE != 0
+    char error_buf[128];
+    WASMModule *sub_module = NULL;
+#endif
+    function->func_ptr_linked = wasm_native_resolve_symbol(
+        function->module_name, function->field_name, function->func_type,
+        &function->signature, &function->attachment, &function->call_conv_raw);
+
+    if (function->func_ptr_linked) {
+        return true;
+    }
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+    if (!wasm_runtime_is_built_in_module(function->module_name)) {
+        sub_module = (WASMModule *)wasm_runtime_load_depended_module(
+            (WASMModuleCommon *)module, function->module_name, error_buf,
+            sizeof(error_buf));
+        if (!sub_module) {
+            LOG_WARNING("failed to load sub module: %s", error_buf);
+            return false;
+        }
+    }
+    function->import_func_linked = wasm_resolve_function(
+        function->module_name, function->field_name, function->func_type,
+        error_buf, sizeof(error_buf));
+
+    if (function->import_func_linked) {
+        function->import_module = sub_module;
+        return true;
+    }
+    else {
+        LOG_WARNING("failed to link function (%s, %s): %s",
+                    function->module_name, function->field_name, error_buf);
+    }
+#endif
+
+    return false;
+}
+
 static void *
 runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
 {

+ 7 - 0
core/iwasm/interpreter/wasm_runtime.h

@@ -513,6 +513,13 @@ wasm_load_from_sections(WASMSection *section_list, char *error_buf,
 void
 wasm_unload(WASMModule *module);
 
+bool
+wasm_resolve_symbols(WASMModule *module);
+
+bool
+wasm_resolve_import_func(const WASMModule *module,
+                         WASMFunctionImport *function);
+
 WASMModuleInstance *
 wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                  WASMExecEnv *exec_env_main, uint32 stack_size,