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);
|
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() {
|
int main() {
|
||||||
LOG_INFO("WRT Test");
|
LOG_INFO("WRT Test");
|
||||||
|
|
||||||
|
test_ffi();
|
||||||
test_wrt();
|
test_wrt();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -7,6 +7,8 @@ int fib_recurse(int n);
|
|||||||
int fib_iterate(int n);
|
int fib_iterate(int n);
|
||||||
int fib_tail_call(int n);
|
int fib_tail_call(int n);
|
||||||
int fib_fast(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) {
|
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 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_open(const char *filename, int flags);
|
||||||
int dl_sym(int handle, const char *symbol, const char *signature);
|
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_sym(int handle, int symbol);
|
||||||
Status dl_close(int handle);
|
Status dl_close(int handle);
|
||||||
|
|
||||||
|
@ -4,14 +4,47 @@
|
|||||||
unsigned fib(unsigned n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }
|
unsigned fib(unsigned n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }
|
||||||
|
|
||||||
void entry() {
|
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);
|
int hnd = dl_open("./SimpleLib.so", 1);
|
||||||
printf("hnd = %d\n", hnd);
|
printf("hnd = %d\n", hnd);
|
||||||
|
|
||||||
|
{
|
||||||
int fib_iterate_sym = dl_sym(hnd, "fib_iterate", "(i)i");
|
int fib_iterate_sym = dl_sym(hnd, "fib_iterate", "(i)i");
|
||||||
printf("fib_iterate_sym = %d\n", fib_iterate_sym);
|
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);
|
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);
|
printf("close lib status = %d\n", status);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,10 @@ typedef enum {
|
|||||||
typedef void *(*Allocator)(unsigned long);
|
typedef void *(*Allocator)(unsigned long);
|
||||||
typedef void (*DeAllocator)(void *);
|
typedef void (*DeAllocator)(void *);
|
||||||
|
|
||||||
|
typedef char *_va_list;
|
||||||
|
|
||||||
#define DL_MAX_HANDLES 8
|
#define DL_MAX_HANDLES 8
|
||||||
#define DL_MAX_SYMBOLS 16
|
#define DL_MAX_SYMBOLS 16
|
||||||
|
#define DL_SYM_TABLE_SIZE 5
|
||||||
|
|
||||||
#endif // WRT_DEFS_H
|
#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(0, dl_open, "($i)i");
|
||||||
EXPORT(1, dl_sym, "(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(3, dl_close_sym, "(ii)i");
|
||||||
EXPORT(4, dl_close, "(i)i");
|
EXPORT(4, dl_close, "(i)i");
|
||||||
|
|
||||||
@ -55,6 +55,8 @@ Status dl_free(DLContext *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define GET_CONTEXT \
|
#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); \
|
DLContext *ctx = wasm_runtime_get_function_attachment(exec_env); \
|
||||||
if (ctx == NULL) return WRT_ERROR;
|
if (ctx == NULL) return WRT_ERROR;
|
||||||
|
|
||||||
@ -172,8 +174,8 @@ ffi_cif *create_ffi_cif(DLContext *ctx, const char *signature) {
|
|||||||
ch++;
|
ch++;
|
||||||
{ // extract ret
|
{ // extract ret
|
||||||
switch (*ch) {
|
switch (*ch) {
|
||||||
case 'i': ret_type = &ffi_type_sint; break;
|
case 'i': ret_type = &ffi_type_sint32; break;
|
||||||
case 'l': ret_type = &ffi_type_slong; break;
|
case 'l': ret_type = &ffi_type_sint64; break;
|
||||||
case 'f': ret_type = &ffi_type_float; break;
|
case 'f': ret_type = &ffi_type_float; break;
|
||||||
case 'd': ret_type = &ffi_type_double; break;
|
case 'd': ret_type = &ffi_type_double; break;
|
||||||
case 'p': ret_type = &ffi_type_pointer; break; // TODO: pointer to pointer
|
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;
|
return WRT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dl_call(wasm_exec_env_t exec_env) {
|
Status dl_call(wasm_exec_env_t exec_env, int symbol, _va_list va_args) {
|
||||||
// int sym = (int)wrt_pop();
|
if (symbol < 1 || symbol > DL_MAX_SYMBOLS) {
|
||||||
// if (sym < 1 || sym > DL_MAX_SYMBOLS) {
|
LOG_ERR("dl_call: invalid symbol");
|
||||||
// LOG_ERR("dl_call: invalid symbol");
|
return WRT_ERROR;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
//
|
GET_CONTEXT
|
||||||
// if (dl_context.sym[sym - 1].symbol == NULL) {
|
|
||||||
// LOG_ERR("dl_call: symbol not found");
|
if (ctx->sym[symbol - 1].symbol == NULL) {
|
||||||
// return;
|
LOG_ERR("dl_call: symbol not found");
|
||||||
// }
|
return WRT_ERROR;
|
||||||
//
|
}
|
||||||
// ffi_cif *cif = dl_context.sym[sym - 1].cif;
|
|
||||||
//
|
if (!wasm_runtime_validate_native_addr(module_inst, va_args, sizeof(uint32_t))) {
|
||||||
// int arg_count = cif->nargs;
|
LOG_ERR("dl_call: invalid va_args");
|
||||||
// void *args[arg_count];
|
return WRT_ERROR;
|
||||||
// for (int i = arg_count - 1; i >= 0; i--) {
|
}
|
||||||
// args[i] = (void *)wrt_pop();
|
|
||||||
// }
|
uint8_t *native_end_addr;
|
||||||
//
|
if (!wasm_runtime_get_native_addr_range(module_inst, (uint8_t *)va_args, NULL,
|
||||||
// void *ret = NULL;
|
&native_end_addr)) {
|
||||||
// if (cif->rtype != &ffi_type_void) {
|
LOG_ERR("dl_call: va_args out of range");
|
||||||
// ret = dl_malloc(cif->rtype->size);
|
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
|
||||||
// }
|
return WRT_ERROR;
|
||||||
//
|
}
|
||||||
// ffi_call(cif, FFI_FN(dl_context.sym[sym - 1].symbol), ret, args);
|
|
||||||
//
|
ffi_cif *cif = ctx->sym[symbol - 1].cif;
|
||||||
// if (ret != NULL) {
|
|
||||||
// wrt_push((int)ret);
|
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) {
|
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"
|
#include "utils/defs.h"
|
||||||
|
|
||||||
#define DL_SYM_TABLE_SIZE 5
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct {
|
struct {
|
||||||
Allocator malloc;
|
Allocator malloc;
|
||||||
@ -29,7 +27,7 @@ Status dl_init(DLContext *context);
|
|||||||
Status dl_free(DLContext *context);
|
Status dl_free(DLContext *context);
|
||||||
int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags);
|
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);
|
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_sym(wasm_exec_env_t exec_env, int handle, int symbol);
|
||||||
Status dl_close(wasm_exec_env_t exec_env, int handle);
|
Status dl_close(wasm_exec_env_t exec_env, int handle);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user