From 5c31d4e7bab49fed400c0e1a9a0613e15c674c05 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sat, 11 Feb 2023 23:59:58 +0800 Subject: [PATCH] feat: now gets a functional dl_call 1. update examples 2. implements dl_call 3. add documentations --- tests/lib/SimpleLib.cpp | 32 ++++++--- tests/wasm/dl.h | 12 ++-- tests/wasm/example.c | 61 +++++++---------- utils/tinymap.c | 130 ------------------------------------- utils/tinymap.h | 32 --------- wrt/lib/dl.c | 140 ++++++++++++++++++++++------------------ wrt/lib/dl.h | 64 ++++++++++++++++-- 7 files changed, 190 insertions(+), 281 deletions(-) delete mode 100644 utils/tinymap.c delete mode 100644 utils/tinymap.h diff --git a/tests/lib/SimpleLib.cpp b/tests/lib/SimpleLib.cpp index b0ca8f0..c094615 100644 --- a/tests/lib/SimpleLib.cpp +++ b/tests/lib/SimpleLib.cpp @@ -1,15 +1,16 @@ +#include #include #define HIDE __attribute__((visibility("hidden"))) extern "C" { -int fib_recurse(int n); -int fib_iterate(int n); -int fib_tail_call(int n); -int fib_fast(int n); -int call_test(int a, long long b, float c, double d); -int call_test2(int a, long long b, int c, float d); -int my_cpy(char *dest, char *src, int len); +int fib_recurse(int n); +int fib_iterate(int n); +int fib_tail_call(int n); +int fib_fast(int n); +float call_test(int a, long long b, float c, double d); +double call_test2(int a, long long b, int c, float d); +int my_cpy(char *dest, char *src, int len); } int fib_recurse(int n) { @@ -51,15 +52,28 @@ HIDE inline std::pair fib_fast_internal(int n) { int fib_fast(int n) { return fib_fast_internal(n).first; } -int call_test(int a, long long b, float c, double d) { return a + b + c + d; } +float call_test(int a, long long b, float c, double d) { + float ans = a + b + c + d; + std::cout << "SimpleLib.cpp: call_test(" << a << ", " << b << ", " << c << ", " << d + << ") = " << ans << std::endl; + return ans; +} -int call_test2(int a, long long b, int c, float d) { return a + b + c + d; } +double call_test2(int a, long long b, int c, float d) { + double ans = a + b + c + d; + std::cout << "SimpleLib.cpp: call_test2(" << a << ", " << b << ", " << c << ", " << d + << ") = " << ans << std::endl; + return ans; +} int my_cpy(char *dest, char *src, int len) { + printf("SimpleLib.cpp: my_cpy(dest=%p, src=%p)\n", dest, src); char seed = 0x42; for (int i = 0; i < len; i++) { dest[i] = src[i]; seed ^= src[i]; } + std::cout << "SimpleLib.cpp: my_cpy(\"" << dest << "\", \"" << src << "\", " << len + << ") = " << (int)seed << std::endl; return seed; } diff --git a/tests/wasm/dl.h b/tests/wasm/dl.h index af9d659..8d7a66a 100644 --- a/tests/wasm/dl.h +++ b/tests/wasm/dl.h @@ -1,15 +1,17 @@ #ifndef WRT_DL_H #define WRT_DL_H +#include + typedef enum { WRT_OK = 0, WRT_ERROR = -1, } Status; -int dl_open(const char *filename, int flags); -int dl_sym(int handle, const char *symbol, const char *signature); -void *dl_call(int symbol, ...); -Status dl_close_sym(int handle, int symbol); -Status dl_close(int handle); +int dl_open(const char *filename, int flags); +int dl_sym(int handle, const char *symbol, const char *signature); +int64_t dl_call(int symbol, ...); +Status dl_close_sym(int symbol); +Status dl_close(int handle); #endif // WRT_DL_H diff --git a/tests/wasm/example.c b/tests/wasm/example.c index 45f5243..7defbae 100644 --- a/tests/wasm/example.c +++ b/tests/wasm/example.c @@ -4,62 +4,49 @@ unsigned fib(unsigned n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); } void dl_test() { - int hnd, fib_iterate_sym, call_test_sym, call_test2_sym, my_cpy_sym; - Status status; - void *result; + int hnd, fib_iterate_sym, call_test_sym, call_test2_sym, my_cpy_sym; + int64_t result; { // Load library hnd = dl_open("./SimpleLib.so", 1); - printf("hnd = %d\n", hnd); } { // Load symbols fib_iterate_sym = dl_sym(hnd, "fib_iterate", "(i)i"); - printf("fib_iterate_sym = %d\n", fib_iterate_sym); - - call_test_sym = dl_sym(hnd, "call_test", "(ilfd)i"); - printf("call_test_sym = %d\n", call_test_sym); - - call_test2_sym = dl_sym(hnd, "call_test2", "(ilid)i"); - printf("call_test2_sym = %d\n", call_test2_sym); - - my_cpy_sym = dl_sym(hnd, "my_cpy", "(ppi)i"); - printf("my_cpy_sym = %d\n", my_cpy_sym); + call_test_sym = dl_sym(hnd, "call_test", "(ilfd)f"); + call_test2_sym = dl_sym(hnd, "call_test2", "(ilid)d"); + my_cpy_sym = dl_sym(hnd, "my_cpy", "(ppi)i"); } { // Call function result = dl_call(fib_iterate_sym, 6); - printf("fib_iterate(6) = %d\n", (int)result); + printf("fib_iterate(6) = %lld\n", result); - result = dl_call(call_test_sym, 42, 0x12345678abcdef01, 3.1415926f, 2.718281828459045); - printf("call_test_sym = %d\n", (int)result); + float pi = 3.1415926f; + double e = 2.718281828459045; + long long ll = 0x12345678abcdef01; - result = dl_call(call_test2_sym, 42, 0x12345678abcdef01, 21, 3.1415926f); - printf("call_test2_sym = %d\n", (int)result); + result = dl_call(call_test_sym, 42, ll, pi, e); + printf("call_test(...) = %f\n", (float)result); + + result = dl_call(call_test2_sym, 42, 21, 10, pi); + printf("call_test2(...) = %lf\n", (double)result); volatile char src[16] = "Hello, World!"; - volatile char dst[16] = "++++++++++++++++"; - result = dl_call(my_cpy_sym, dst, src, 16); - printf("my_cpy = %d, src = %s , dst = %s\n", (int)result, src, dst); + volatile char dst[16] = "+++++++++++++"; + result = dl_call(my_cpy_sym, dst, 16, src, 16, 16); + printf("my_cpy(...) = %lld, src = %s , dst = %s\n", result, src, dst); } { // Close symbols - status = dl_close_sym(hnd, fib_iterate_sym); - printf("close sym status = %d\n", status); - - status = dl_close_sym(hnd, call_test_sym); - printf("close sym status = %d\n", status); - - status = dl_close_sym(hnd, call_test2_sym); - printf("close sym status = %d\n", status); - - status = dl_close_sym(hnd, my_cpy_sym); - printf("close sym status = %d\n", status); + dl_close_sym(fib_iterate_sym); + dl_close_sym(call_test_sym); + dl_close_sym(call_test2_sym); + dl_close_sym(my_cpy_sym); } { // Close library - status = dl_close(hnd); - printf("close lib status = %d\n", status); + dl_close(hnd); } } @@ -80,12 +67,12 @@ void evil_test() { // 3. valid symbol, valid args dl_call(my_cpy_sym, (void *)evil_test, (void *)evil_test, 1); - dl_close_sym(hnd, my_cpy_sym); + dl_close_sym(my_cpy_sym); dl_close(hnd); } void entry() { printf("Hello WASM\n"); dl_test(); - evil_test(); + // evil_test(); } diff --git a/utils/tinymap.c b/utils/tinymap.c deleted file mode 100644 index 6a4985d..0000000 --- a/utils/tinymap.c +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include - -#include "utils/log.h" -#include "wrt/tinymap.h" - -#define FOR(i) for (unsigned i = map->head[hash]; i; i = map->node[i].next) - -static inline unsigned map_hash(int key) { return (key % BUK_SIZE + BUK_SIZE) % BUK_SIZE; } - -void map_init(Map *map) { - map->count = 0; - memset(map->head, 0, sizeof(map->head)); - memset(map->node, 0, sizeof(map->node)); -} - -void *map_get(Map *map, int key) { - if (key == 0) return NULL; - - unsigned hash = map_hash(key); - FOR(i) { - if (map->node[i].key == key) return map->node[i].value; - } - return NULL; -} - -bool map_set(Map *map, int key, void *value) { - if (key == 0) return false; - - unsigned hash = map_hash(key); - FOR(i) { - if (map->node[i].key == key) { - LOG_DBG("map_set: upd key=%d, val=0x%llx, pos=%d", key, (unsigned long long)value, i); - map->node[i].value = value; - return true; - } - } - - if (map->count >= NOD_SIZE) { - LOG_DBG("map_set: nod full, compact"); - map_compact(map); - if (map->count == NOD_SIZE) return false; - } - - map->node[++map->count] = (MapNode){key, value, map->head[hash]}; - map->head[hash] = map->count; - LOG_DBG("map_set: ins key=%d, val=0x%llx, pos=%d", key, (unsigned long long)value, map->count); - - return true; -} - -void map_delete(Map *map, int key) { - if (key == 0) return; - - unsigned hash = map_hash(key); - FOR(i) { - if (map->node[i].key == key) { - LOG_DBG("map_delete: del key=%d, pos=%d", key, i); - map->node[i].key = 0; - return; - } - } -} - -void map_compact(Map *map) { - LOG_DBG("map_compact: before count=%d", map->count); - - { - // compact map->node - // i = last empty node, j = current scanning node - // node[0] is undefined - unsigned i = 1, j = 2; - for (; j <= NOD_SIZE;) { - if (map->node[i].key) { - i++, j++; - continue; - } - - if (map->node[j].key) { - LOG_DBG("map_compact: move node[%d] to node[%d]", j, i); - - map->node[i] = map->node[j]; - map->node[j].key = 0; - - i++, j++; - continue; - } - - j++; - } - - map->count = i - 1; - - LOG_DBG("map_compact: after count=%d", map->count); - } - - { - // rebuild map->head - for (unsigned i = 0; i <= NOD_SIZE; i++) map->node[i].next = 0; - memset(map->head, 0, sizeof(map->head)); - for (unsigned i = 1; i <= NOD_SIZE; i++) { - if (!map->node[i].key) break; - - unsigned hash = map_hash(map->node[i].key); - - if (map->head[hash] == 0) { - map->head[hash] = i; - } else { - unsigned j = map->head[hash]; - map->head[hash] = i; - map->node[i].next = j; - } - } - } -} - -void map_dbg(Map *map) { - for (int hash = 0; hash < BUK_SIZE; hash++) { - printf("[+] BUK[%2d]:\n", hash); - int spaces = 5; - FOR(i) { - for (int j = 0; j < spaces; j++) putchar(' '); - printf("└─ NOD[" __COLOR_GREEN "%2d" __COLOR_RESET "]: key=" __COLOR_YELLOW - "%d" __COLOR_RESET ", val=" __COLOR_CYAN "0x%llx" __COLOR_RESET - ", nxt=" __COLOR_RED "%d" __COLOR_RESET "\n", - i, map->node[i].key, (unsigned long long)map->node[i].value, map->node[i].next); - spaces += 4; - } - } -} diff --git a/utils/tinymap.h b/utils/tinymap.h deleted file mode 100644 index 0537de5..0000000 --- a/utils/tinymap.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef WRT_TINYMAP_H -#define WRT_TINYMAP_H - -#include - -#ifndef BUK_SIZE - #define BUK_SIZE 8 -#endif - -#ifndef NOD_SIZE - #define NOD_SIZE 32 -#endif - -typedef struct { - int key; - void *value; - unsigned next; -} MapNode; - -typedef struct { - MapNode node[NOD_SIZE + 1]; - unsigned head[BUK_SIZE]; - unsigned count; -} Map; - -void map_init(Map *map); -void *map_get(Map *map, int key); -bool map_set(Map *map, int key, void *value); -void map_delete(Map *map, int key); -void map_compact(Map *map); - -#endif // WRT_TINYMAP_H diff --git a/wrt/lib/dl.c b/wrt/lib/dl.c index 5a28bfd..8a7325f 100644 --- a/wrt/lib/dl.c +++ b/wrt/lib/dl.c @@ -1,11 +1,25 @@ #include #include +#include #include "utils/log.h" #include "wrt/lib/dl.h" #warning "TODO: Permission Check" +#define LOG_AND_QUIT(msg, ret) \ + do { \ + LOG_ERR(msg); \ + wasm_runtime_set_exception(module_inst, msg); \ + return ret; \ + } while (0) + +#define GET_CONTEXT(ret) \ + wasm_module_inst_t module_inst = get_module_inst(exec_env); \ + (void)module_inst; \ + DLContext *ctx = wasm_runtime_get_function_attachment(exec_env); \ + if (ctx == NULL) LOG_AND_QUIT("dl_get_context: NULL", ret); + Status dl_init(DLContext *ctx) { memset(ctx->hnd, 0, sizeof(ctx->hnd)); memset(ctx->sym, 0, sizeof(ctx->sym)); @@ -26,8 +40,8 @@ Status dl_init(DLContext *ctx) { EXPORT(0, dl_open, "($i)i"); EXPORT(1, dl_sym, "(i$$)i"); - EXPORT(2, dl_call, "(i*)i"); - EXPORT(3, dl_close_sym, "(ii)i"); + EXPORT(2, dl_call, "(i*)I"); + EXPORT(3, dl_close_sym, "(i)i"); EXPORT(4, dl_close, "(i)i"); #undef EXPORT @@ -51,12 +65,6 @@ Status dl_free(DLContext *ctx) { return WRT_OK; } -#define GET_CONTEXT(ret) \ - wasm_module_inst_t module_inst = get_module_inst(exec_env); \ - (void)module_inst; \ - DLContext *ctx = wasm_runtime_get_function_attachment(exec_env); \ - if (ctx == NULL) return ret; - int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags) { if (filename == NULL) return WRT_ERROR; if (filename[0] == '\0') return WRT_ERROR; @@ -82,9 +90,10 @@ int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags) { return WRT_ERROR; } +// TODO: integrate it into create_ffi_cif bool signature_check(const char *signature, int *arg_count, bool *has_ret) { - const static char allowed_chars[] = {'i', 'l', 'f', 'd', 'p'}; - const static int allowed_chars_len = sizeof(allowed_chars) / sizeof(char); + const char allowed_chars[] = {'i', 'l', 'f', 'd', 'p'}; + const int allowed_chars_len = sizeof(allowed_chars) / sizeof(char); // tmpl: '(' ch* ')' ch? @@ -230,50 +239,47 @@ int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char return WRT_ERROR; } -void *dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args) { - GET_CONTEXT(NULL) - -#define LOG_AND_QUIT(msg) \ - do { \ - LOG_ERR(msg); \ - wasm_runtime_set_exception(module_inst, msg); \ - return NULL; \ - } while (0) +int64_t dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args) { + GET_CONTEXT(WRT_ERROR) if (symbol < 1 || symbol > DL_MAX_SYMBOLS) { - LOG_AND_QUIT("dl_call: invalid symbol"); + LOG_AND_QUIT("dl_call: invalid symbol", WRT_ERROR); } if (ctx->sym[symbol - 1].symbol == NULL) { - LOG_AND_QUIT("dl_call: symbol not found"); + LOG_AND_QUIT("dl_call: symbol not found", WRT_ERROR); } if (!wasm_runtime_validate_native_addr(module_inst, va_args, sizeof(uint32_t))) { - LOG_AND_QUIT("dl_call: invalid va_args"); + LOG_AND_QUIT("dl_call: invalid va_args", WRT_ERROR); } uint8_t *native_end_addr; if (!wasm_runtime_get_native_addr_range(module_inst, (uint8_t *)va_args, NULL, &native_end_addr)) { - LOG_AND_QUIT("dl_call: va_args out of bounds"); + LOG_AND_QUIT("dl_call: va_args out of bounds", WRT_ERROR); } - ffi_cif *cif = ctx->sym[symbol - 1].cif; - - unsigned arg_count = cif->nargs; - void *args[arg_count]; - void *tmp_buffer[arg_count]; // TODO: tmp_buffer only used for ptr args, which wastes memory + ffi_cif *cif = ctx->sym[symbol - 1].cif; + unsigned arg_count = cif->nargs, ext_ptr_count = 0, ext_float_count = 0; + for (int i = 0; i < arg_count; i++) { + if (cif->arg_types[i]->type == FFI_TYPE_POINTER) ext_ptr_count++; + if (cif->arg_types[i]->type == FFI_TYPE_FLOAT) ext_float_count++; + } #define ALIGN(n, b) (((uintptr_t)(n) + b) & (uintptr_t)~b) #define GET_ARG(ptr, type) (*(type *)((ptr += ALIGN(sizeof(type), 3)) - ALIGN(sizeof(type), 3))) -#define CHECK_VA_ARG(ptr, type) \ - do { \ - if ((uint8_t *)ptr + ALIGN(type, 3) > native_end_addr) { \ - LOG_AND_QUIT("dl_call: func args out of bounds"); \ - } \ +#define CHECK_VA_ARG(ptr, type) \ + do { \ + if ((uint8_t *)ptr + ALIGN(type, 3) > native_end_addr) { \ + LOG_AND_QUIT("dl_call: func args out of bounds", WRT_ERROR); \ + } \ } while (0) - _va_list cur = va_args; + void **args = alloca(sizeof(void *) * arg_count); + void **ext_ptrs = alloca(sizeof(void *) * ext_ptr_count); + float *ext_floats = alloca(sizeof(float *) * ext_float_count); + _va_list cur = va_args; for (int i = 0; i < arg_count; i++) { // TODO: check wasm abi // only support int, long long, float, double, pointer now @@ -288,6 +294,8 @@ void *dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args) { case FFI_TYPE_POINTER: { // 32 bit CHECK_VA_ARG(cur, int32_t); uint32_t ptr = GET_ARG(cur, int32_t); + CHECK_VA_ARG(cur, int32_t); + uint32_t len = GET_ARG(cur, int32_t); /* TODO: Security Warning !! * - 3rd-party libraries could access native memory directly, which means a buffer @@ -298,12 +306,14 @@ void *dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args) { * force memory alignment) * - On embedded devices: maybe disable this feature? or embedded native symbols? */ - if (!wasm_runtime_validate_app_addr(module_inst, ptr, 0)) { - LOG_AND_QUIT("dl_call: invalid ptr"); + if (!wasm_runtime_validate_app_addr(module_inst, ptr, len)) { + LOG_AND_QUIT("dl_call: invalid ptr", WRT_ERROR); } - tmp_buffer[i] = wasm_runtime_addr_app_to_native(module_inst, ptr); - args[i] = &tmp_buffer[i]; - LOG_WARN("dl_call: ptr arg[%d] = 0x%lx", i, (uintptr_t)tmp_buffer[i]); + *ext_ptrs = wasm_runtime_addr_app_to_native(module_inst, ptr); + args[i] = ext_ptrs; + LOG_WARN("dl_call: ptr arg[%d] = 0x%lx, buf = %p", i, (uintptr_t)*ext_ptrs, + ext_ptrs); + ext_ptrs++; break; } @@ -313,53 +323,55 @@ void *dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args) { args[i] = &GET_ARG(cur, int64_t); break; } - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: { // 64 bit: FLOAT and DOUBLE are the same in WASM + case FFI_TYPE_FLOAT: { // 64 bit in WASM + cur = (_va_list)ALIGN(cur, 7); + CHECK_VA_ARG(cur, double); + *ext_floats = (float)GET_ARG(cur, double); + args[i] = ext_floats; + ext_floats++; + break; + } + case FFI_TYPE_DOUBLE: { // 64 bit cur = (_va_list)ALIGN(cur, 7); CHECK_VA_ARG(cur, double); args[i] = &GET_ARG(cur, double); break; } default: { - LOG_AND_QUIT("dl_call: unsupported type"); + LOG_AND_QUIT("dl_call: unsupported type", WRT_ERROR); } } } +#undef CHECK_VA_ARG +#undef GET_ARG +#undef ALIGN + void *ret = NULL; if (cif->rtype->type != FFI_TYPE_VOID) { unsigned size = cif->rtype->size; if (cif->rtype->type == FFI_TYPE_FLOAT) size = (&ffi_type_double)->size; - ret = ctx->mem.malloc(size); + ret = alloca(size); } - unsigned short not_implemented[4] = {FFI_TYPE_POINTER, FFI_TYPE_SINT64, FFI_TYPE_DOUBLE, - FFI_TYPE_FLOAT}; - for (int i = 0; i < 4; i++) - if (cif->rtype->type == not_implemented[i]) { - /* TODO: - * - FFI_TYPE_POINTER: copy the data, but how to free?(make a linked list?), how to - * determine the size? - * - Others: 64 bit, how to return? change signature to return int64? which suits ptr - * :) - */ - LOG_AND_QUIT("dl_call: unsupported return type (pointer)"); - } - ffi_call(cif, FFI_FN(ctx->sym[symbol - 1].symbol), ret, args); - LOG_DBG("dl_call: symbol = %d, ret = 0x%x", symbol, *(unsigned *)ret); + int64_t ret_val; + switch (cif->rtype->type) { + case FFI_TYPE_SINT32: ret_val = *(int32_t *)ret; break; + case FFI_TYPE_SINT64: ret_val = *(int64_t *)ret; break; + case FFI_TYPE_FLOAT: ret_val = (int64_t)(double)(*(float *)ret); break; + case FFI_TYPE_DOUBLE: ret_val = (int64_t)(*(double *)ret); break; + case FFI_TYPE_VOID: ret_val = 0; break; + default: LOG_AND_QUIT("dl_call: unsupported type", WRT_ERROR); + } - return (void *)0x42; + LOG_DBG("dl_call: symbol = %d, ret = 0x%lx", symbol, ret_val); -#undef CHECK_VA_ARG -#undef GET_ARG -#undef ALIGN -#undef LOG_AND_QUIT + return ret_val; } -Status dl_close_sym(wasm_exec_env_t exec_env, int handle, int symbol) { - if (handle < 1 || handle > DL_MAX_HANDLES) return WRT_ERROR; +Status dl_close_sym(wasm_exec_env_t exec_env, int symbol) { if (symbol < 1 || symbol > DL_MAX_SYMBOLS) return WRT_ERROR; GET_CONTEXT(WRT_ERROR) diff --git a/wrt/lib/dl.h b/wrt/lib/dl.h index 1341a4f..f764a2b 100644 --- a/wrt/lib/dl.h +++ b/wrt/lib/dl.h @@ -23,12 +23,68 @@ typedef struct { } sym[DL_MAX_SYMBOLS]; } DLContext; +/// Init DL environment +/// \param ctx DLContext to be initialized, ctx->mem.malloc and ctx->mem.free must be set before +/// \return WRT_OK, unless malloc failed Status dl_init(DLContext *context); + +/// Free DL environment +/// \param ctx DLContext to be freed +/// \return always WRT_OK Status dl_free(DLContext *context); -int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags); -int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char *signature); -void *dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args); -Status dl_close_sym(wasm_exec_env_t exec_env, int handle, int symbol); + +/// Open a dynamic library +/// \param exec_env WAMR execution environment +/// \param filename dynamic library file name +/// \param flags dlopen flags (man dlopen) +/// \return handle of the opened dynamic library, or WRT_ERROR if failed +int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags); + +/// Get symbol from a dynamic library +/// \param exec_env WAMR execution environment +/// \param handle handle of the dynamic library, returned by dl_open +/// \param symbol symbol name +/// \param signature function signature: \n +/// signature grammar: \n +/// -# `type_ret ::= 'i' | 'l' | 'f' | 'd'` \n +/// -# `type_arg ::= type_ret | 'p'` \n +/// -# `signature ::= '(' type_arg* ')' type_ret?` \n +/// 'i' for int(sint32), 'l' for long(sint64), 'f' for float, 'd' for double, 'p' for pointer \n +/// Examples: \n +/// -# `()` for function: `void func(void)` \n +/// -# `(i)` for function: `void func(int)` \n +/// -# `(ip)f` for function: `float func(int, void*)` \n +/// Several Notes: \n +/// -# Pointer type: \n +/// -# A int must be followed after the pointer indicating the length of the pointer \n +/// -# For example: \n +/// + if a native function is defined as `void func(int *p, int *q)` \n +/// + then, in WASM environment, the function should be defined as `void func(int *p, int +/// p_len, int *q, int q_len)` \n +/// -# We do not guarantee the same behavior when there are multiple pointers intervene with each +/// other \n +/// -# We do not support return value of type pointer, since we don't know how the data length \n +/// -# More types will be supported in the future \n +/// \return native function's output, or terminated if failed +int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char *signature); + +/// Call a native function +/// \param exec_env WASM execution environment +/// \param symbol symbol handle, returned by dl_sym +/// \param va_args arguments, in WASM runtime, variadic arguments are pushed into stack, just like a +/// array \return function's return value +int64_t dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args); + +/// Destroy a symbol, it will free the cif structure +/// \param exec_env WAMR execution environment +/// \param symbol symbol handle, returned by dl_sym +/// \return WRT_OK, unless symbol is invalid +Status dl_close_sym(wasm_exec_env_t exec_env, int symbol); + +/// Close a dynamic library +/// \param exec_env WASM execution environment +/// \param handle handle of the dynamic library, returned by dl_open +/// \return WRT_OK, unless handle is invalid or dlclose failed Status dl_close(wasm_exec_env_t exec_env, int handle); #endif // WRT_DL_H