feat: dl_call prototype
This commit is contained in:
parent
55d7e94a52
commit
6f3888c1f0
48
main.c
48
main.c
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
132
wrt/dl.c
@ -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) {
|
||||
|
4
wrt/dl.h
4
wrt/dl.h
@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user