feat: dl_call prototype

This commit is contained in:
Paul Pan 2023-02-07 23:19:28 +08:00
parent 55d7e94a52
commit 6f3888c1f0
7 changed files with 199 additions and 44 deletions

48
main.c
View File

@ -40,9 +40,57 @@ void test_wrt() {
free(buf);
}
unsigned char foo(unsigned int x, float y, char z, double w) {
printf("foo: x=%u, y=%f, z=%c, w=%lf\n", x, y, z, w);
return 'P';
}
void test_ffi() {
ffi_cif cif;
ffi_type *arg_types[4];
void *arg_values[4];
ffi_status status;
// Because the return value from foo() is smaller than sizeof(long), it
// must be passed as ffi_arg or ffi_sarg.
ffi_arg result;
// Specify the data type of each argument. Available types are defined
// in <ffi/ffi.h>.
arg_types[0] = &ffi_type_uint;
arg_types[1] = &ffi_type_float;
arg_types[2] = &ffi_type_schar;
arg_types[3] = &ffi_type_double;
// Prepare the ffi_cif structure.
if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_uint8, arg_types)) != FFI_OK) {
// Handle the ffi_status error.
LOG_ERR("ffi_prep_cif failed: %d", status);
}
// Specify the values of each argument.
unsigned int arg1 = 42;
float arg2 = 5.1f;
char arg3 = 'A';
double arg4 = 114.1514;
arg_values[0] = &arg1;
arg_values[1] = &arg2;
arg_values[2] = &arg3;
arg_values[3] = &arg4;
// Invoke the function.
ffi_call(&cif, FFI_FN(foo), &result, arg_values);
// The ffi_arg 'result' now contains the unsigned char returned from foo(),
// which can be accessed by a typecast.
printf("result is %c\n", (unsigned char)result);
}
int main() {
LOG_INFO("WRT Test");
test_ffi();
test_wrt();
return 0;

View File

@ -7,6 +7,8 @@ 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 fib_recurse(int n) {
@ -47,3 +49,7 @@ HIDE inline std::pair<int, int> 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; }
int call_test2(int a, long long b, int c, float d) { return a + b + c + d; }

View File

@ -8,6 +8,7 @@ typedef enum {
int dl_open(const char *filename, int flags);
int dl_sym(int handle, const char *symbol, const char *signature);
Status dl_call(int symbol, ...);
Status dl_close_sym(int handle, int symbol);
Status dl_close(int handle);

View File

@ -4,14 +4,47 @@
unsigned fib(unsigned n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }
void entry() {
// for (unsigned i = 0; i <= 35; i++) printf("fib(%2u) = %u\n", i, fib(i));
printf("Hello WASM\n");
for (unsigned i = 0; i <= 5; i++) printf("fib(%u) = %u\n", i, fib(i));
int hnd = dl_open("./SimpleLib.so", 1);
printf("hnd = %d\n", hnd);
{
int fib_iterate_sym = dl_sym(hnd, "fib_iterate", "(i)i");
printf("fib_iterate_sym = %d\n", fib_iterate_sym);
Status status = dl_close_sym(hnd, fib_iterate_sym);
Status status = dl_call(fib_iterate_sym, 6);
printf("call status = %d\n", status);
status = dl_close_sym(hnd, fib_iterate_sym);
printf("close sym status = %d\n", status);
status = dl_close(hnd);
}
{
int call_test_sym = dl_sym(hnd, "call_test", "(ilfd)i");
printf("call_test_sym = %d\n", call_test_sym);
Status status =
dl_call(call_test_sym, 42, 0x12345678abcdef01, 3.1415926f, 2.718281828459045);
printf("call status = %d\n", status);
status = dl_close_sym(hnd, call_test_sym);
printf("close sym status = %d\n", status);
}
{
int call_test2_sym = dl_sym(hnd, "call_test2", "(ilid)i");
printf("call_test2_sym = %d\n", call_test2_sym);
Status status = dl_call(call_test2_sym, 42, 0x12345678abcdef01, 21, 3.1415926f);
printf("call status = %d\n", status);
status = dl_close_sym(hnd, call_test2_sym);
printf("close sym status = %d\n", status);
}
Status status = dl_close(hnd);
printf("close lib status = %d\n", status);
}

View File

@ -9,7 +9,10 @@ typedef enum {
typedef void *(*Allocator)(unsigned long);
typedef void (*DeAllocator)(void *);
typedef char *_va_list;
#define DL_MAX_HANDLES 8
#define DL_MAX_SYMBOLS 16
#define DL_SYM_TABLE_SIZE 5
#endif // WRT_DEFS_H

132
wrt/dl.c
View File

@ -29,7 +29,7 @@ Status dl_init(DLContext *ctx) {
EXPORT(0, dl_open, "($i)i");
EXPORT(1, dl_sym, "(i$$)i");
EXPORT(2, dl_call, "(i)i");
EXPORT(2, dl_call, "(i*)i");
EXPORT(3, dl_close_sym, "(ii)i");
EXPORT(4, dl_close, "(i)i");
@ -55,6 +55,8 @@ Status dl_free(DLContext *ctx) {
}
#define GET_CONTEXT \
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 WRT_ERROR;
@ -172,8 +174,8 @@ ffi_cif *create_ffi_cif(DLContext *ctx, const char *signature) {
ch++;
{ // extract ret
switch (*ch) {
case 'i': ret_type = &ffi_type_sint; break;
case 'l': ret_type = &ffi_type_slong; break;
case 'i': ret_type = &ffi_type_sint32; break;
case 'l': ret_type = &ffi_type_sint64; break;
case 'f': ret_type = &ffi_type_float; break;
case 'd': ret_type = &ffi_type_double; break;
case 'p': ret_type = &ffi_type_pointer; break; // TODO: pointer to pointer
@ -231,36 +233,100 @@ 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 sym = (int)wrt_pop();
// if (sym < 1 || sym > DL_MAX_SYMBOLS) {
// LOG_ERR("dl_call: invalid symbol");
// return;
// }
//
// if (dl_context.sym[sym - 1].symbol == NULL) {
// LOG_ERR("dl_call: symbol not found");
// return;
// }
//
// ffi_cif *cif = dl_context.sym[sym - 1].cif;
//
// int arg_count = cif->nargs;
// void *args[arg_count];
// for (int i = arg_count - 1; i >= 0; i--) {
// args[i] = (void *)wrt_pop();
// }
//
// void *ret = NULL;
// if (cif->rtype != &ffi_type_void) {
// ret = dl_malloc(cif->rtype->size);
// }
//
// ffi_call(cif, FFI_FN(dl_context.sym[sym - 1].symbol), ret, args);
//
// if (ret != NULL) {
// wrt_push((int)ret);
// }
Status dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args) {
if (symbol < 1 || symbol > DL_MAX_SYMBOLS) {
LOG_ERR("dl_call: invalid symbol");
return WRT_ERROR;
}
GET_CONTEXT
if (ctx->sym[symbol - 1].symbol == NULL) {
LOG_ERR("dl_call: symbol not found");
return WRT_ERROR;
}
if (!wasm_runtime_validate_native_addr(module_inst, va_args, sizeof(uint32_t))) {
LOG_ERR("dl_call: invalid va_args");
return 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_ERR("dl_call: va_args out of range");
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
return WRT_ERROR;
}
ffi_cif *cif = ctx->sym[symbol - 1].cif;
unsigned arg_count = cif->nargs;
void *args[arg_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_ERR("dl_call: va_args out of range"); \
wasm_runtime_set_exception(module_inst, "out of bounds memory access"); \
return WRT_ERROR; \
} \
} while (0)
_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
// int 32, long long 32, float 64, double 64, pointer 32
switch (cif->arg_types[i]->type) {
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER: {
CHECK_VA_ARG(cur, int32_t);
args[i] = &GET_ARG(cur, int32_t);
LOG_DBG("dl_call: arg[%d] = %d / 0x%x", i, *(int32_t *)args[i],
*(int32_t *)args[i]);
break;
}
case FFI_TYPE_SINT64: {
cur = (_va_list)ALIGN(cur, 7);
CHECK_VA_ARG(cur, int64_t);
args[i] = &GET_ARG(cur, int64_t);
LOG_DBG("dl_call: arg[%d] = %ld / 0x%lx", i, *(int64_t *)args[i],
*(int64_t *)args[i]);
break;
}
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE: {
cur = (_va_list)ALIGN(cur, 7);
CHECK_VA_ARG(cur, double);
args[i] = &GET_ARG(cur, double);
LOG_DBG("dl_call: arg[%d] = %lf", i, *(double *)args[i]);
break;
}
default: {
LOG_ERR("dl_call: unsupported type");
return WRT_ERROR;
}
}
}
#undef CHECK_VA_ARG
#undef GET_ARG
#undef ALIGN
void *ret = NULL;
if (cif->rtype != &ffi_type_void) {
// TODO: return val storage, re-design dl_call
ret = ctx->mem.malloc(cif->rtype->size);
}
ffi_call(cif, FFI_FN(ctx->sym[symbol - 1].symbol), ret, args);
LOG_DBG("dl_call: symbol = %d, ret = 0x%x", symbol, *(unsigned *)ret);
return WRT_OK;
}
Status dl_close_sym(wasm_exec_env_t exec_env, int handle, int symbol) {

View File

@ -7,8 +7,6 @@
#include "utils/defs.h"
#define DL_SYM_TABLE_SIZE 5
typedef struct {
struct {
Allocator malloc;
@ -29,7 +27,7 @@ Status dl_init(DLContext *context);
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); // TODO
Status dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args); // TODO
Status dl_close_sym(wasm_exec_env_t exec_env, int handle, int symbol);
Status dl_close(wasm_exec_env_t exec_env, int handle);