diff --git a/include/vm/fzl_vm.h b/include/vm/fzl_vm.h index 49149c0..2f81d2c 100644 --- a/include/vm/fzl_vm.h +++ b/include/vm/fzl_vm.h @@ -5,12 +5,14 @@ #include #include #include +#include #include // VM descriptor typedef struct { fzl_vm_reader_t *reader; + fzl_vm_extern_t *prep_fns; size_t ip; diff --git a/include/vm/fzl_vm_extern.h b/include/vm/fzl_vm_extern.h index 19f3f80..550a4c6 100644 --- a/include/vm/fzl_vm_extern.h +++ b/include/vm/fzl_vm_extern.h @@ -2,6 +2,8 @@ #define FZL_VM_EXTERN_H #include +#include +#include // Loaded extern function definition typedef struct @@ -9,6 +11,25 @@ typedef struct void *func_ptr; ffi_cif cif; ffi_type **arg_types; +} fzl_vm_sym_t; + +// Extern object descriptor +typedef struct +{ + void **libs; + size_t libs_loaded; + + fzl_vm_sym_t *syms; + size_t syms_loaded; } fzl_vm_extern_t; +// Load externs +fzl_vm_extern_t *fzl_vm_init_externs(fzl_vm_reader_t *reader); + +// Get last error from externs loader +char *fzl_vm_externs_geterror(); + +// Close and free externs +void fzl_vm_free_externs(fzl_vm_extern_t *ex); + #endif // FZL_VM_EXTERN_H diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index 6bc7184..358ee4b 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,14 @@ fzl_vm_t *fzl_mkvm(fzl_vm_reader_t *reader) memset(vm, 0, sizeof(fzl_vm_t)); vm->reader = reader; + vm->prep_fns = fzl_vm_init_externs(reader); + if (!vm->prep_fns) + { + char *err = fzl_vm_externs_geterror(); + strcpy(last_err, err); + return NULL; + } + return vm; } diff --git a/src/vm/fzl_vm_extern.c b/src/vm/fzl_vm_extern.c new file mode 100644 index 0000000..52f8fdf --- /dev/null +++ b/src/vm/fzl_vm_extern.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char ex_err[256]; + +// Resolve specified type reference +ffi_type *resolve_type(fzl_vm_reader_t *reader, fzl_extern_type_ref_t *ref) +{ + if (ref->is_primitive) + { + switch (ref->primitive) + { + case FZL_TYPE_INT8: + return &ffi_type_sint8; + + case FZL_TYPE_INT16: + return &ffi_type_sint16; + + case FZL_TYPE_INT32: + return &ffi_type_sint32; + + case FZL_TYPE_INT64: + return &ffi_type_sint64; + + case FZL_TYPE_UINT8: + case FZL_TYPE_BOOL: + return &ffi_type_uint8; + + case FZL_TYPE_UINT16: + return &ffi_type_uint16; + + case FZL_TYPE_UINT32: + return &ffi_type_uint32; + + case FZL_TYPE_UINT64: + return &ffi_type_uint64; + + case FZL_TYPE_CHAR: + return &ffi_type_schar; + + case FZL_TYPE_STRING: + case FZL_TYPE_HANDLE: + case FZL_TYPE_STRUCT: + return &ffi_type_pointer; + + default: + return &ffi_type_void; + } + } + else + { + fzl_extern_type_t *t = &reader->extern_types[ref->type_slot]; + if (!t) + return &ffi_type_void; + + switch (t->kind) + { + case FZL_EXTERN_KIND_STRUCT: + case FZL_EXTERN_KIND_HANDLE: + case FZL_EXTERN_KIND_REF: + return &ffi_type_pointer; + + case FZL_EXTERN_KIND_ALIAS: + return resolve_type(reader, &t->alias_target); + } + } +} + +// Preapre sym, put result in out and return operation result +bool prepare_sym(fzl_vm_reader_t *reader, void *sym, fzl_extern_fn_t *fn, + fzl_vm_sym_t *out) +{ + if (!reader || !fn || !sym || !out) + { + snprintf(ex_err, sizeof(ex_err), + "cannot prepare sym: function def, symbol handle or outvar is not " + "specified"); + return false; + } + + out->func_ptr = sym; + // TODO: fill the FFI CIF struct values + return false; +} + +fzl_vm_extern_t *fzl_vm_init_externs(fzl_vm_reader_t *reader) +{ + if (!reader) + { + snprintf(ex_err, sizeof(ex_err), "reader is not provided"); + return NULL; + } + + fzl_vm_extern_t *ex = malloc(sizeof(fzl_vm_extern_t)); + if (!ex) + { + snprintf(ex_err, sizeof(ex_err), "out of memory"); + return NULL; + } + + memset(ex, 0, sizeof(fzl_vm_extern_t)); + + if (reader->extern_libs_count < 1 || reader->extern_fns_count < 1) + return ex; + + ex->libs = malloc(sizeof(void *) * reader->extern_libs_count); + if (!ex->libs) + { + snprintf(ex_err, sizeof(ex_err), "out of memory"); + free(ex); + return NULL; + } + + memset(ex->libs, 0, sizeof(void *) * reader->extern_libs_count); + for (uint16_t i = 0; i < reader->extern_libs_count; i++) + { + void *lib = dlopen(reader->extern_libs[i], RTLD_NOW); + if (!lib) + { + snprintf(ex_err, sizeof(ex_err), "cannot open library '%s'", + reader->extern_libs[i]); + + if (i > 0) + { + for (size_t j = 0; j < ex->libs_loaded; j++) + if (ex->libs[j]) + dlclose(ex->libs[j]); + } + + free(ex->libs); + free(ex); + return NULL; + } + + ex->libs[ex->libs_loaded++] = lib; + } + + ex->syms = malloc(sizeof(fzl_vm_sym_t) * reader->extern_fns_count); + if (!ex->syms) + { + snprintf(ex_err, sizeof(ex_err), "out of memory"); + + for (size_t i = 0; i < ex->libs_loaded; i++) + if (ex->libs[i]) + dlclose(ex->libs[i]); + + free(ex->libs); + free(ex); + return NULL; + } + + memset(ex->syms, 0, sizeof(fzl_vm_sym_t) * reader->extern_fns_count); + for (uint16_t i = 0; i < reader->extern_fns_count; i++) + { + fzl_extern_fn_t *fn = &reader->extern_fns[i]; + char *fnname = fn->symbol_name != NULL ? fn->symbol_name : fn->used_name; + + void *sym = dlsym(ex->libs[fn->lib_slot], fnname); + if (!sym) + { + snprintf(ex_err, sizeof(ex_err), "couldn't find symbol '%s' in lib '%s'", + fnname, reader->extern_libs[fn->lib_slot]); + + for (size_t j = 0; j < ex->libs_loaded; j++) + if (ex->libs[j]) + dlclose(ex->libs[j]); + + free(ex->libs); + + for (size_t j = 0; j < ex->syms_loaded; j++) + { + if (ex->syms->arg_types) + free(ex->syms->arg_types); + } + + free(ex->syms); + free(ex); + return NULL; + } + + if (!prepare_sym(reader, sym, fn, &ex->syms[i])) + { + if (!ex_err[0]) + { + snprintf(ex_err, sizeof(ex_err), + "failed to preapre FFI structure for sym '%s'", fnname); + } + + for (size_t j = 0; j < ex->libs_loaded; j++) + if (ex->libs[j]) + dlclose(ex->libs[j]); + + free(ex->libs); + free(ex->syms); + free(ex); + return NULL; + } + } + + return ex; +} + +char *fzl_vm_externs_geterror() { return ex_err; } + +void fzl_vm_free_externs(fzl_vm_extern_t *ex) +{ + if (!ex) + return; + + if (ex->libs) + { + for (size_t i = 0; i < ex->libs_loaded; i++) + if (ex->libs[i]) + dlclose(ex->libs[i]); + + free(ex->libs); + } + + if (ex->syms) + { + for (size_t i = 0; i < ex->syms_loaded; i++) + free(ex->syms[i].arg_types); + + free(ex->syms); + } + + free(ex); +}