working example of loading a library and dynamically linking functions!
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Dec 2021 15:29:31 +0000 (09:29 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Dec 2021 15:29:31 +0000 (09:29 -0600)
build.sh
include/onyx_library.h [new file with mode: 0644]
misc/onyx_library.h [deleted file]
modules/test_library/module.onyx
modules/test_library/test_library.c
src/wasm_runtime.c

index 6fb93aa97e7e5b22e14ca2da29c2eba3d2a66bb0..d13c6e58b5595628286159fbb972a8dd186f72e3 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -45,7 +45,7 @@ fi
 
 C_FILES="$C_FILES wasm_runtime"
 FLAGS="$FLAGS -DENABLE_RUN_WITH_WASMER -rdynamic"
-LIBS="-L$CORE_DIR/lib -lwasmer -Wl,-rpath=$CORE_DIR/lib -lpthread -ldl"
+LIBS="-L$CORE_DIR/lib -lwasmer -Wl,-rpath=$CORE_DIR/lib:./ -lpthread -ldl"
 INCLUDES="-I$WASMER_INCLUDE_DIR"
 
 mkdir -p "$BUILD_DIR"
diff --git a/include/onyx_library.h b/include/onyx_library.h
new file mode 100644 (file)
index 0000000..2f7e8a5
--- /dev/null
@@ -0,0 +1,56 @@
+
+#include "wasm.h"
+
+extern wasm_memory_t* wasm_memory;
+
+typedef struct WasmValkindBuffer {
+    unsigned int count;
+    wasm_valkind_t types[20];
+} WasmValkindBuffer;
+
+typedef struct WasmFuncDefinition {
+    char* module_name;
+    char* import_name;
+    wasm_func_callback_t func;
+
+    WasmValkindBuffer *params;
+    WasmValkindBuffer *results;
+} WasmFuncDefinition;
+
+#define STRINGIFY1(a) #a
+#define STRINGIFY2(a) STRINGIFY1(a)
+#define CONCAT2(a, b) a ## _ ## b
+#define CONCAT3(a, b, c) a ## _ ## b ## _ ## c
+#define ONYX_MODULE_NAME_GEN(m) CONCAT2(__onyx_library, m)
+#define ONYX_LINK_NAME_GEN(m) CONCAT2(onyx_library, m)
+#define ONYX_FUNC_NAME(m, n) CONCAT3(__onyx_internal, m, n)
+#define ONYX_DEF_NAME(m, n) CONCAT3(__onyx_internal_def, m, n)
+#define ONYX_PARAM_NAME(m, n) CONCAT3(__onyx_internal_param_buffer, m, n)
+#define ONYX_RESULT_NAME(m, n) CONCAT3(__onyx_internal_result_buffer, m, n)
+#define ONYX_IMPORT_NAME(m, n) STRINGIFY1(m) "_" #n
+
+#define NUM_VALS(...) (sizeof((wasm_valkind_t []){ 0, __VA_ARGS__ }) / sizeof(wasm_valkind_t))
+#define _VALS(...) { NUM_VALS(__VA_ARGS__) - 1, __VA_ARGS__ }
+
+#define ONYX_DEF(name, params_types, result_types) \
+    static wasm_trap_t* ONYX_FUNC_NAME(ONYX_LIBRARY_NAME, name)(const wasm_val_vec_t* params, wasm_val_vec_t* results); \
+    static struct WasmValkindBuffer  ONYX_PARAM_NAME(ONYX_LIBRARY_NAME, name) = _VALS params_types; \
+    static struct WasmValkindBuffer  ONYX_RESULT_NAME(ONYX_LIBRARY_NAME, name) = _VALS result_types; \
+    static struct WasmFuncDefinition ONYX_DEF_NAME(ONYX_LIBRARY_NAME, name) = { STRINGIFY2(ONYX_LIBRARY_NAME), #name, ONYX_FUNC_NAME(ONYX_LIBRARY_NAME, name), & ONYX_PARAM_NAME(ONYX_LIBRARY_NAME, name), & ONYX_RESULT_NAME(ONYX_LIBRARY_NAME, name) }; \
+    \
+    static wasm_trap_t* ONYX_FUNC_NAME(ONYX_LIBRARY_NAME, name)(const wasm_val_vec_t* params, wasm_val_vec_t* results)
+
+#define ONYX_FUNC(name) & ONYX_DEF_NAME(ONYX_LIBRARY_NAME, name),
+#define ONYX_LIBRARY \
+    extern struct WasmFuncDefinition *ONYX_MODULE_NAME_GEN(ONYX_LIBRARY_NAME)[]; \
+    WasmFuncDefinition** ONYX_LINK_NAME_GEN(ONYX_LIBRARY_NAME)() { \
+        return ONYX_MODULE_NAME_GEN(ONYX_LIBRARY_NAME); \
+    } \
+    struct WasmFuncDefinition *ONYX_MODULE_NAME_GEN(ONYX_LIBRARY_NAME)[] =
+
+// Shorter names
+#define INT WASM_I32
+#define LONG WASM_I64
+#define FLOAT WASM_F32
+#define DOUBLE WASM_F64
+#define PTR WASM_I32
diff --git a/misc/onyx_library.h b/misc/onyx_library.h
deleted file mode 100644 (file)
index d9d9ed1..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-
-#include "wasm.h"
-
-extern wasm_memory_t* wasm_memory;
-
-typedef struct WasmValkindBuffer {
-    unsigned int count;
-    wasm_valkind_t types[20];
-} WasmValkindBuffer;
-
-typedef struct WasmFuncDefinition {
-    char* module_name;
-    char* import_name;
-    wasm_func_callback_t func;
-
-    WasmValkindBuffer *params;
-    WasmValkindBuffer *results;
-} WasmFuncDefinition;
-
-#define STRINGIFY1(a) #a
-#define CONCAT2(a, b) a ## _ ## b
-#define CONCAT3(a, b, c) a ## _ ## b ## _ ## c
-#define ONYX_MODULE_NAME_GEN(m) CONCAT2(__onyx_library, m)
-#define ONYX_LINK_NAME_GEN(m) CONCAT2(onyx_library, m)
-#define ONYX_FUNC_NAME(m, n) CONCAT3(__onyx_internal, m, n)
-#define ONYX_DEF_NAME(m, n) CONCAT3(__onyx_internal_def, m, n)
-#define ONYX_PARAM_NAME(m, n) CONCAT3(__onyx_internal_param_buffer, m, n)
-#define ONYX_RESULT_NAME(m, n) CONCAT3(__onyx_internal_result_buffer, m, n)
-#define ONYX_IMPORT_NAME(m, n) STRINGIFY1(m) "_" #n
-
-#define NUM_VALS(...) (sizeof((wasm_valkind_t []){ 0, __VA_ARGS__ }) / sizeof(wasm_valkind_t))
-#define _VALS(...) { NUM_VALS(__VA_ARGS__) - 1, __VA_ARGS__ }
-
-#define ONYX_DEF(name, params_types, result_types) \
-    static wasm_trap_t* ONYX_FUNC_NAME(ONYX_LIBRARY_NAME, name)(const wasm_val_vec_t* params, wasm_val_vec_t* results); \
-    static struct WasmValkindBuffer  ONYX_PARAM_NAME(ONYX_LIBRARY_NAME, name) = _VALS params_types; \
-    static struct WasmValkindBuffer  ONYX_RESULT_NAME(ONYX_LIBRARY_NAME, name) = _VALS result_types; \
-    static struct WasmFuncDefinition ONYX_DEF_NAME(ONYX_LIBRARY_NAME, name) = { STRINGIFY1(ONYX_LIBRARY_NAME), #name, ONYX_FUNC_NAME(ONYX_LIBRARY_NAME, name), & ONYX_PARAM_NAME(ONYX_LIBRARY_NAME, name), & ONYX_RESULT_NAME(ONYX_LIBRARY_NAME, name) }; \
-    \
-    static wasm_trap_t* ONYX_FUNC_NAME(ONYX_LIBRARY_NAME, name)(const wasm_val_vec_t* params, wasm_val_vec_t* results)
-
-#define ONYX_FUNC(name) & ONYX_DEF_NAME(ONYX_LIBRARY_NAME, name),
-#define ONYX_LIBRARY \
-    extern struct WasmFuncDefinition *ONYX_MODULE_NAME_GEN(ONYX_LIBRARY_NAME)[]; \
-    WasmFuncDefinition** ONYX_LINK_NAME_GEN(ONYX_LIBRARY_NAME)() { \
-        return ONYX_MODULE_NAME_GEN(ONYX_LIBRARY_NAME); \
-    } \
-    struct WasmFuncDefinition *ONYX_MODULE_NAME_GEN(ONYX_LIBRARY_NAME)[] =
-
-// Shorter names
-#define I32 WASM_I32
-#define I64 WASM_I64
-#define F32 WASM_F32
-#define F64 WASM_F64
index 7b505cb677fc290630ddf42935bc5640c43472bf..b0f3d387add02cd7aeb038395b4de082ef323c79 100644 (file)
@@ -1,5 +1,7 @@
 package test_library
 
-#library "test_library"
+// #library "test_library"
 
-foo :: () -> void #foreign "test_library" "foo" ---
\ No newline at end of file
+foo :: () -> void #foreign "test_library" "foo" ---
+add :: (a, b: i32) -> i32 #foreign "test_library" "add" ---
+print_string :: (s: str) -> void #foreign "test_library" "print_string" ---
\ No newline at end of file
index 08df6ad9ac5c0c45f2516dcb629bd28b6c33a885..16e1b0f6e603f2761d5d3969991c755ebf89c866 100644 (file)
@@ -1,5 +1,6 @@
 #include "onyx_library.h"
 #include <stdio.h>
+#include <unistd.h>
 
 #define ONYX_LIBRARY_NAME test_library
 
@@ -8,6 +9,25 @@ ONYX_DEF(foo, (), ()) {
     return NULL;
 }
 
+ONYX_DEF(add, (INT, INT), (INT)) {
+    int a = params->data[0].of.i32;
+    int b = params->data[1].of.i32;
+    results->data[0] = WASM_I32_VAL(a + b);
+    return NULL;
+}
+
+ONYX_DEF(print_string, (PTR, INT), ()) {
+    char *start = wasm_memory_data(wasm_memory) + params->data[0].of.i32;
+    int  length = params->data[1].of.i32;
+
+    write(1, start, length);
+    return NULL;
+}
+
 ONYX_LIBRARY {
     ONYX_FUNC(foo)
+    ONYX_FUNC(add)
+    ONYX_FUNC(print_string)
+
+    NULL
 };
\ No newline at end of file
index 3ca0ccf608eff4dce4f6f4e204828ad8fd38bf7e..816093ddba1cca28d4172e819cf335a2093fa709 100644 (file)
@@ -8,6 +8,7 @@
     #include <pthread.h>
     #include <signal.h>
     #include <sys/wait.h>
+    #include <dlfcn.h>
 #endif
 
 #ifndef WASMER_VERSION
@@ -498,11 +499,34 @@ WASM_INTEROP(onyx_process_destroy_impl) {
     return NULL;
 }
 
-#include <dlfcn.h>
+#include "onyx_library.h"
+
+typedef void *(*LibraryLinker)();
+static bh_arr(WasmFuncDefinition **) linkable_functions = NULL;
+
+static void onyx_load_library(char *name) {
+    char *library_load_name = bh_aprintf(global_scratch_allocator, "onyx_library_%s", name);
+    LibraryLinker library_load;
+
+    #ifdef _BH_LINUX
+    char *library_name = bh_aprintf(global_scratch_allocator, "%s.so", name);
+    void* handle = dlopen(library_name, RTLD_LAZY);
+    if (handle == NULL) {
+        printf("ERROR LOADING LIBRARY %s: %s\n", name, dlerror());
+        return;
+    }
+
+    library_load = (LibraryLinker) dlsym(handle, library_load_name);
+    #endif
+
+    WasmFuncDefinition** funcs = library_load();
+    bh_arr_push(linkable_functions, funcs);
+}
 
 // Returns 1 if successful
 b32 onyx_run_wasm(bh_buffer wasm_bytes) {
-
+    bh_arr_new(global_heap_allocator, linkable_functions, 4);
+    onyx_load_library("test_library");
 
     wasm_instance_t* instance = NULL;
     wasmer_features_t* features = NULL;
@@ -666,6 +690,30 @@ b32 onyx_run_wasm(bh_buffer wasm_bytes) {
             }
         }
 
+        bh_arr_each(WasmFuncDefinition **, library_funcs, linkable_functions) {
+            WasmFuncDefinition **pcurrent_function = *library_funcs;
+            while (*pcurrent_function != NULL) {
+                WasmFuncDefinition *cf = *pcurrent_function;
+                if (wasm_name_equals_string(module_name, cf->module_name) && wasm_name_equals_string(import_name, cf->import_name)) {
+                    wasm_valtype_vec_t wasm_params;
+                    wasm_valtype_vec_new_uninitialized(&wasm_params, cf->params->count);
+                    fori (k, 0, cf->params->count) wasm_params.data[k] = wasm_valtype_new(cf->params->types[k]);
+
+                    wasm_valtype_vec_t wasm_results;
+                    wasm_valtype_vec_new_uninitialized(&wasm_results, cf->results->count);
+                    fori (k, 0, cf->results->count) wasm_results.data[k] = wasm_valtype_new(cf->results->types[k]);
+
+                    wasm_functype_t* wasm_functype = wasm_functype_new(&wasm_params, &wasm_results);
+
+                    wasm_func_t* wasm_func = wasm_func_new(wasm_store, wasm_functype, cf->func);
+                    import = wasm_func_as_extern(wasm_func);
+                    goto import_found;
+                }
+
+                pcurrent_function += 1;
+            }
+        }
+
         goto bad_import;
 
     import_found:
@@ -680,17 +728,6 @@ b32 onyx_run_wasm(bh_buffer wasm_bytes) {
 
     wasm_trap_t* traps = NULL;
 
-    // NOCHECKIN
-    void* handle = dlopen("./test_library.so", RTLD_LAZY);
-    printf("HANDLE: %p\n", handle);
-    if (handle == NULL) {
-        printf("ERROR: %s\n", dlerror());
-    }
-    void *wasm_library = dlsym(handle, "onyx_library_test_library");
-    printf("LOADED: %p\n", wasm_library);
-    printf("TABLE: %p\n", ((void* (*)()) wasm_library)());
-    dlclose(handle);
-
     instance = wasm_instance_new(wasm_store, wasm_module, &wasm_imports, &traps);
     if (!instance) goto error_handling;