wip: working on externs loading

- WIP: add extern objects initializing/freeing functions
- Feat: add extern objects loading in VM initializer
This commit is contained in:
samsonium
2026-11-08 17:12:31 +03:00
parent 5de995a3c2
commit 1c57525604
4 changed files with 270 additions and 0 deletions
+2
View File
@@ -5,12 +5,14 @@
#include <stddef.h>
#include <stdint.h>
#include <vm/fzl_vm_env.h>
#include <vm/fzl_vm_extern.h>
#include <vm/fzl_vm_reader.h>
// VM descriptor
typedef struct
{
fzl_vm_reader_t *reader;
fzl_vm_extern_t *prep_fns;
size_t ip;
+21
View File
@@ -2,6 +2,8 @@
#define FZL_VM_EXTERN_H
#include <ffi.h>
#include <stddef.h>
#include <vm/fzl_vm_reader.h>
// 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
+9
View File
@@ -8,6 +8,7 @@
#include <string.h>
#include <vm/fzl_vm.h>
#include <vm/fzl_vm_env.h>
#include <vm/fzl_vm_extern.h>
#include <vm/fzl_vm_object.h>
#include <vm/fzl_vm_reader.h>
#include <vm/internals/opcode.h>
@@ -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;
}
+238
View File
@@ -0,0 +1,238 @@
#include <common/fzl_extern.h>
#include <common/fzl_types.h>
#include <dlfcn.h>
#include <ffi.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vm/fzl_vm_extern.h>
#include <vm/fzl_vm_reader.h>
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);
}