Преглед на файлове

Implement dynamic linking section loading (#3720)

Also added build flags to enable dynamic linking.
Marcin Kolny преди 1 година
родител
ревизия
9be775e0ec

+ 3 - 0
build-scripts/config_common.cmake

@@ -282,6 +282,9 @@ endif ()
 if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
 if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
   message ("     Lib wasi-threads enabled")
   message ("     Lib wasi-threads enabled")
 endif ()
 endif ()
+if (WAMR_BUILD_DYNAMIC_LINKING EQUAL 1)
+  message ("     Dynamic linking enabled")
+endif ()
 if (WAMR_BUILD_LIBC_EMCC EQUAL 1)
 if (WAMR_BUILD_LIBC_EMCC EQUAL 1)
   message ("     Libc emcc enabled")
   message ("     Libc emcc enabled")
 endif ()
 endif ()

+ 5 - 0
build-scripts/runtime_lib.cmake

@@ -119,6 +119,10 @@ if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
     set (WAMR_BUILD_SHARED_MEMORY 1)
     set (WAMR_BUILD_SHARED_MEMORY 1)
 endif ()
 endif ()
 
 
+if (WAMR_BUILD_DYNAMIC_LINKING EQUAL 1)
+    include (${IWASM_DIR}/libraries/lib-dynlink/lib_dynlink.cmake)
+endif ()
+
 if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
 if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
     set (WAMR_BUILD_THREAD_MGR 1)
     set (WAMR_BUILD_THREAD_MGR 1)
     include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
     include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
@@ -189,6 +193,7 @@ set (source_all
     ${IWASM_GC_SOURCE}
     ${IWASM_GC_SOURCE}
     ${LIB_WASI_THREADS_SOURCE}
     ${LIB_WASI_THREADS_SOURCE}
     ${LIB_PTHREAD_SOURCE}
     ${LIB_PTHREAD_SOURCE}
+    ${LIB_DYNLINK_SOURCE}
     ${THREAD_MGR_SOURCE}
     ${THREAD_MGR_SOURCE}
     ${LIBC_EMCC_SOURCE}
     ${LIBC_EMCC_SOURCE}
     ${LIB_RATS_SOURCE}
     ${LIB_RATS_SOURCE}

+ 5 - 0
core/config.h

@@ -292,6 +292,11 @@
 #define WASM_ENABLE_MULTI_MODULE 0
 #define WASM_ENABLE_MULTI_MODULE 0
 #endif
 #endif
 
 
+/* Support a dynamic linking */
+#ifndef WASM_ENABLE_DYNAMIC_LINKING
+#define WASM_ENABLE_DYNAMIC_LINKING 0
+#endif
+
 /* Enable wasm mini loader or not */
 /* Enable wasm mini loader or not */
 #ifndef WASM_ENABLE_MINI_LOADER
 #ifndef WASM_ENABLE_MINI_LOADER
 #define WASM_ENABLE_MINI_LOADER 0
 #define WASM_ENABLE_MINI_LOADER 0

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

@@ -12,6 +12,9 @@
 #if WASM_ENABLE_GC != 0
 #if WASM_ENABLE_GC != 0
 #include "gc_export.h"
 #include "gc_export.h"
 #endif
 #endif
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+#include "dynlink_types.h"
+#endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -1008,6 +1011,10 @@ struct WASMModule {
     WASMCustomSection *custom_section_list;
     WASMCustomSection *custom_section_list;
 #endif
 #endif
 
 
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+    DynLinkSections dynlink_sections;
+#endif
+
 #if WASM_ENABLE_FAST_JIT != 0
 #if WASM_ENABLE_FAST_JIT != 0
     /**
     /**
      * func pointers of Fast JITed (un-imported) functions
      * func pointers of Fast JITed (un-imported) functions

+ 15 - 0
core/iwasm/interpreter/wasm_loader.c

@@ -26,6 +26,9 @@
 #if WASM_ENABLE_JIT != 0
 #if WASM_ENABLE_JIT != 0
 #include "../compilation/aot_llvm.h"
 #include "../compilation/aot_llvm.h"
 #endif
 #endif
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+#include "dynlink_section_loader.h"
+#endif
 
 
 #ifndef TRACE_WASM_LOADER
 #ifndef TRACE_WASM_LOADER
 #define TRACE_WASM_LOADER 0
 #define TRACE_WASM_LOADER 0
@@ -5236,6 +5239,14 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
     }
     }
 #endif
 #endif
 
 
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+    if (!dynlink_try_load_dylink0_section(p, p_end, name_len, module,
+                                          is_load_from_file_buf, error_buf,
+                                          error_buf_size)) {
+        return false;
+    }
+#endif
+
 #if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
 #if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
     {
     {
         WASMCustomSection *section =
         WASMCustomSection *section =
@@ -6937,6 +6948,10 @@ wasm_loader_unload(WASMModule *module)
     wasm_runtime_destroy_custom_sections(module->custom_section_list);
     wasm_runtime_destroy_custom_sections(module->custom_section_list);
 #endif
 #endif
 
 
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+    dynlink_sections_deinit(&module->dynlink_sections);
+#endif
+
 #if WASM_ENABLE_FAST_JIT != 0
 #if WASM_ENABLE_FAST_JIT != 0
     if (module->fast_jit_func_ptrs) {
     if (module->fast_jit_func_ptrs) {
         wasm_runtime_free(module->fast_jit_func_ptrs);
         wasm_runtime_free(module->fast_jit_func_ptrs);

+ 16 - 0
core/iwasm/interpreter/wasm_mini_loader.c

@@ -19,6 +19,9 @@
 #if WASM_ENABLE_JIT != 0
 #if WASM_ENABLE_JIT != 0
 #include "../compilation/aot_llvm.h"
 #include "../compilation/aot_llvm.h"
 #endif
 #endif
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+#include "dynlink_section_loader.h"
+#endif
 
 
 /* Read a value of given type from the address pointed to by the given
 /* Read a value of given type from the address pointed to by the given
    pointer and increase the pointer to the position just after the
    pointer and increase the pointer to the position just after the
@@ -2009,6 +2012,15 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
         }
         }
     }
     }
 #endif
 #endif
+
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+    if (!dynlink_try_load_dylink0_section(p, p_end, name_len, module,
+                                          is_load_from_file_buf, error_buf,
+                                          error_buf_size)) {
+        return false;
+    }
+#endif
+
     LOG_VERBOSE("Load custom section success.\n");
     LOG_VERBOSE("Load custom section success.\n");
     (void)name_len;
     (void)name_len;
     return true;
     return true;
@@ -3371,6 +3383,10 @@ wasm_loader_unload(WASMModule *module)
     }
     }
 #endif
 #endif
 
 
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
+    dynlink_sections_deinit(&module->dynlink_sections);
+#endif
+
 #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
 #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
     && WASM_ENABLE_LAZY_JIT != 0
     && WASM_ENABLE_LAZY_JIT != 0
     os_mutex_destroy(&module->instance_list_lock);
     os_mutex_destroy(&module->instance_list_lock);

+ 307 - 0
core/iwasm/libraries/lib-dynlink/dynlink_section_loader.c

@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "dynlink_section_loader.h"
+#include "wasm_runtime.h"
+#include "wasm_loader_common.h"
+
+#define SECTION_NAME "dylink.0"
+#define SECTION_NAME_LEN (sizeof(SECTION_NAME) - 1)
+
+enum DynLinkSubSectionType {
+    WASM_DYLINK_MEM_INFO = 1,
+    WASM_DYLINK_NEEDED,
+    WASM_DYLINK_EXPORT_INFO,
+    WASM_DYLINK_IMPORT_INFO,
+};
+
+typedef struct {
+    uint8 *ptr;
+    const uint8 *ptr_end;
+    WASMModule *module;
+    bool is_load_from_file_buf;
+    char *error_buf;
+    uint32 error_buf_size;
+} DynLinkLoaderCtx;
+
+#define read_leb_uint32(p, p_end, res)                                        \
+    do {                                                                      \
+        uint64 res64;                                                         \
+        if (!read_leb((uint8 **)&p, p_end, 32, false, &res64, ctx->error_buf, \
+                      ctx->error_buf_size))                                   \
+            goto fail;                                                        \
+        res = (uint32)res64;                                                  \
+    } while (0)
+
+static void
+set_error_buf(const DynLinkLoaderCtx *ctx, const char *string)
+{
+    if (ctx->error_buf != NULL) {
+        snprintf(ctx->error_buf, ctx->error_buf_size,
+                 "Loading dynlink.0 section failed: %s", string);
+    }
+}
+
+static bool
+check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length,
+          const DynLinkLoaderCtx *ctx)
+{
+    if ((uintptr_t)buf + length < (uintptr_t)buf
+        || (uintptr_t)buf + length > (uintptr_t)buf_end) {
+        set_error_buf(ctx, "unexpected end of section or function");
+        return false;
+    }
+    return true;
+}
+
+static char *
+load_string(DynLinkLoaderCtx *ctx)
+{
+    uint32 length;
+    char *ret = NULL;
+    bh_assert(ctx);
+
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, length);
+    if (!check_buf(ctx->ptr, ctx->ptr_end, length, ctx)) {
+        goto fail;
+    }
+
+    ret = wasm_const_str_list_insert(ctx->ptr, length, ctx->module,
+                                     ctx->is_load_from_file_buf, ctx->error_buf,
+                                     ctx->error_buf_size);
+
+    if (ret != NULL) {
+        ctx->ptr += length;
+    }
+
+fail:
+    return ret;
+}
+
+static bool
+load_mem_info_section(DynLinkLoaderCtx *ctx)
+{
+    DynLinkSectionMemInfo *mem_info = &ctx->module->dynlink_sections.mem_info;
+
+    bh_assert(ctx);
+
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, mem_info->memory_size);
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, mem_info->memory_alignment);
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, mem_info->table_size);
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, mem_info->table_alignment);
+
+    LOG_VERBOSE("Load dylink memory section success:");
+    LOG_VERBOSE("  memory size: %" PRIu32, mem_info->memory_size);
+    LOG_VERBOSE("  memory alignment: %" PRIu32, mem_info->memory_alignment);
+    LOG_VERBOSE("  table size: %" PRIu32, mem_info->table_size);
+    LOG_VERBOSE("  table alignment: %" PRIu32, mem_info->table_alignment);
+
+    return true;
+
+fail:
+    return false;
+}
+
+static bool
+load_needed_section(DynLinkLoaderCtx *ctx)
+{
+    DynLinkSectionNeeded *needed = &ctx->module->dynlink_sections.needed;
+    uint32 i;
+
+    bh_assert(ctx);
+
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, needed->count);
+
+    needed->entries =
+        wasm_runtime_malloc(sizeof(*needed->entries) * needed->count);
+    if (needed->entries == NULL) {
+        set_error_buf(ctx, "out of memory");
+        return false;
+    }
+
+    for (i = 0; i < needed->count; i++) {
+        if (!(needed->entries[i] = load_string(ctx))) {
+            goto fail;
+        }
+        LOG_VERBOSE("Load dylink needed entry success: %s", needed->entries[i]);
+    }
+
+    LOG_VERBOSE("Load dylink needed section success.");
+
+    return true;
+
+fail:
+    if (needed->entries != NULL) {
+        wasm_runtime_free(needed->entries);
+    }
+    needed->entries = NULL;
+
+    return false;
+}
+
+static bool
+load_export_info_section(DynLinkLoaderCtx *ctx)
+{
+    DynLinkSectionExportInfo *export_info =
+        &ctx->module->dynlink_sections.export_info;
+    uint32 i;
+
+    bh_assert(ctx);
+
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, export_info->count);
+
+    export_info->entries =
+        wasm_runtime_malloc(sizeof(*export_info->entries) * export_info->count);
+
+    if (export_info->entries == NULL) {
+        set_error_buf(ctx, "out of memory");
+        return false;
+    }
+
+    for (i = 0; i < export_info->count; i++) {
+        if (!(export_info->entries[i].name = load_string(ctx))) {
+            goto fail;
+        }
+        read_leb_uint32(ctx->ptr, ctx->ptr_end, export_info->entries[i].flags);
+
+        LOG_VERBOSE("Load dylink export entry success: %s %" PRIu32,
+                    export_info->entries[i].name,
+                    export_info->entries[i].flags);
+    }
+
+    LOG_VERBOSE("Load dylink export section success.");
+
+    return true;
+fail:
+    if (export_info->entries != NULL) {
+        wasm_runtime_free(export_info->entries);
+        export_info->entries = NULL;
+    }
+
+    return false;
+}
+
+static bool
+load_import_info_section(DynLinkLoaderCtx *ctx)
+{
+    DynLinkSectionImportInfo *import_info =
+        &ctx->module->dynlink_sections.import_info;
+
+    bh_assert(ctx);
+
+    if (!(import_info->module = load_string(ctx))) {
+        goto fail;
+    }
+
+    if (!(import_info->field = load_string(ctx))) {
+        goto fail;
+    }
+
+    read_leb_uint32(ctx->ptr, ctx->ptr_end, import_info->flags);
+
+    LOG_VERBOSE("Load dylink import section success: %s %s %" PRIu32,
+                import_info->module, import_info->field, import_info->flags);
+
+    return true;
+
+fail:
+    return false;
+}
+
+static bool
+dynlink_load_subsections(DynLinkLoaderCtx *ctx)
+{
+    while (ctx->ptr < ctx->ptr_end) {
+        uint8 type = *ctx->ptr++;
+        uint32 subsection_size;
+
+        read_leb_uint32(ctx->ptr, ctx->ptr_end, subsection_size);
+
+        if (!check_buf(ctx->ptr, ctx->ptr_end, subsection_size, ctx)) {
+            return false;
+        }
+
+        switch (type) {
+            case WASM_DYLINK_MEM_INFO:
+                if (!load_mem_info_section(ctx)) {
+                    return false;
+                }
+                break;
+            case WASM_DYLINK_NEEDED:
+                if (!load_needed_section(ctx)) {
+                    return false;
+                }
+                break;
+            case WASM_DYLINK_EXPORT_INFO:
+                if (!load_export_info_section(ctx)) {
+                    return false;
+                }
+                break;
+            case WASM_DYLINK_IMPORT_INFO:
+                if (!load_import_info_section(ctx)) {
+                    return false;
+                }
+                break;
+            default:
+                set_error_buf(ctx, "unknown subsection type");
+                return false;
+        }
+    }
+
+    return true;
+
+fail:
+    return false;
+}
+
+bool
+dynlink_load_dylink0_section(const uint8 *buf, const uint8 *buf_end,
+                             WASMModule *module, bool is_load_from_file_buf,
+                             char *error_buf, uint32 error_buf_size)
+{
+    const uint8 *p = buf, *p_end = buf_end;
+
+    DynLinkLoaderCtx ctx = {
+        .ptr = (uint8 *)p,
+        .ptr_end = p_end,
+        .module = module,
+        .is_load_from_file_buf = is_load_from_file_buf,
+        .error_buf = error_buf,
+        .error_buf_size = error_buf_size,
+    };
+
+    if (p >= p_end) {
+        set_error_buf(&ctx, "unexpected end");
+        return false;
+    }
+
+    memset(&module->dynlink_sections, 0, sizeof(module->dynlink_sections));
+
+    return dynlink_load_subsections(&ctx);
+}
+
+static bool
+dynlink_is_dylink0_section(const uint8 *buf, uint32 section_name_len)
+{
+    return section_name_len == SECTION_NAME_LEN
+           && memcmp(buf, SECTION_NAME, SECTION_NAME_LEN) == 0;
+}
+
+bool
+dynlink_try_load_dylink0_section(const uint8 *buf, const uint8 *buf_end,
+                                 uint32 section_name_len, WASMModule *module,
+                                 bool is_load_from_file_buf, char *error_buf,
+                                 uint32 error_buf_size)
+{
+
+    if (dynlink_is_dylink0_section(buf, section_name_len)) {
+        buf += section_name_len;
+        return dynlink_load_dylink0_section(buf, buf_end, module,
+                                            is_load_from_file_buf, error_buf,
+                                            error_buf_size);
+    }
+
+    return true;
+}

+ 17 - 0
core/iwasm/libraries/lib-dynlink/dynlink_section_loader.h

@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _DYNLINK_SECTION_LOADER_H
+#define _DYNLINK_SECTION_LOADER_H
+
+#include "wasm.h"
+#include "dynlink_types.h"
+
+bool
+dynlink_try_load_dylink0_section(const uint8 *buf, const uint8 *buf_end,
+                                 uint32 section_name_len, WASMModule *module,
+                                 bool is_load_from_file_buf, char *error_buf,
+                                 uint32 error_buf_size);
+#endif

+ 21 - 0
core/iwasm/libraries/lib-dynlink/dynlink_types.c

@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+#include "dynlink_types.h"
+#include "bh_assert.h"
+
+void
+dynlink_sections_deinit(DynLinkSections *sections)
+{
+    bh_assert(sections);
+
+    if (sections->needed.entries) {
+        wasm_runtime_free(sections->needed.entries);
+    }
+    if (sections->export_info.entries) {
+        wasm_runtime_free(sections->export_info.entries);
+    }
+
+    memset(sections, 0, sizeof(*sections));
+}

+ 49 - 0
core/iwasm/libraries/lib-dynlink/dynlink_types.h

@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _DYNLINK_TYPES_H
+#define _DYNLINK_TYPES_H
+
+#include "platform_common.h"
+
+typedef struct {
+    uint32 memory_size;
+    uint32 memory_alignment;
+    uint32 table_size;
+    uint32 table_alignment;
+} DynLinkSectionMemInfo;
+
+typedef struct {
+    uint32 count;
+    char **entries;
+} DynLinkSectionNeeded;
+
+typedef struct {
+    char *name;
+    uint32 flags;
+} DynLinkSectionExportInfoEntry;
+
+typedef struct {
+    uint32 count;
+    DynLinkSectionExportInfoEntry *entries;
+} DynLinkSectionExportInfo;
+
+typedef struct {
+    char *module;
+    char *field;
+    uint32 flags;
+} DynLinkSectionImportInfo;
+
+typedef struct {
+    DynLinkSectionMemInfo mem_info;
+    DynLinkSectionNeeded needed;
+    DynLinkSectionExportInfo export_info;
+    DynLinkSectionImportInfo import_info;
+} DynLinkSections;
+
+void
+dynlink_sections_deinit(DynLinkSections *sections);
+
+#endif

+ 12 - 0
core/iwasm/libraries/lib-dynlink/lib_dynlink.cmake

@@ -0,0 +1,12 @@
+# Copyright (C) 2024 Amazon.com Inc. or its affiliates. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set (LIB_DYNLINK_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+add_definitions (-DWASM_ENABLE_DYNAMIC_LINKING=1)
+
+include_directories(${LIB_DYNLINK_DIR})
+
+set (LIB_DYNLINK_SOURCE
+    ${LIB_DYNLINK_DIR}/dynlink_section_loader.c
+    ${LIB_DYNLINK_DIR}/dynlink_types.c)

+ 4 - 0
doc/build_wamr.md

@@ -64,6 +64,10 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
 - **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set
 - **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set
 > Note: See [Multiple Modules as Dependencies](./multi_module.md) for more details.
 > Note: See [Multiple Modules as Dependencies](./multi_module.md) for more details.
 
 
+#### **Enable Dynamic Linking feature**
+
+- **WAMR_BUILD_DYNAMIC_LINKING**=1/0, build the [Dynamic Linking](https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md) support, default to disable if not set
+
 #### **Enable WASM mini loader**
 #### **Enable WASM mini loader**
 
 
 - **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set
 - **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set