add demo of static binary ffi

this adds a demo where the embedding C wrapper creates a new primitive
module with an ffi table which can be accessed and used from the racket
side to call functions, even when the runtime is hosted in a static
binary
This commit is contained in:
xenia 2020-10-14 18:17:24 -04:00
parent 74daa90c95
commit 35236b5052
3 changed files with 70 additions and 3 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
*.o *.o
*.zo *.zo
*.dep *.dep
.vimrc
.ycm_extra_conf.py

View File

@ -6,9 +6,58 @@
extern const char _binary_app_zo_start; extern const char _binary_app_zo_start;
extern const char _binary_app_zo_end; extern const char _binary_app_zo_end;
static int run_bc(Scheme_Env *e, int argc, char *argv[]) { // ffi example call
Scheme_Object *l = NULL;
Scheme_Object *a[2] = { NULL, NULL }; void example_func() {
printf("hello world ffi call\n");
}
// ffi defs
typedef struct {
const char* name;
uintptr_t ptr;
} ffi_ent;
static const ffi_ent ffi_table[] = {
{"example_func", (uintptr_t) example_func}
};
static const size_t ffi_table_size = sizeof(ffi_table)/sizeof(ffi_ent);
// setup ffi table to be passed to racket
static void bc_setup_ffi_table(Scheme_Env* parent) {
Scheme_Env* mod = NULL;
Scheme_Object* table = NULL;
Scheme_Object* table_ent = NULL;
MZ_GC_DECL_REG(4);
MZ_GC_VAR_IN_REG(0, parent);
MZ_GC_VAR_IN_REG(1, mod);
MZ_GC_VAR_IN_REG(2, table);
MZ_GC_VAR_IN_REG(3, table_ent);
MZ_GC_REG();
mod = scheme_primitive_module(scheme_intern_symbol("static-ffi"), parent);
table = scheme_make_null();
for (size_t i = 0; i < ffi_table_size; i++) {
table_ent = scheme_make_null();
table_ent = scheme_make_pair(scheme_make_integer(ffi_table[i].ptr), table_ent);
table_ent = scheme_make_pair(scheme_intern_symbol(ffi_table[i].name), table_ent);
table = scheme_make_pair(table_ent, table);
}
scheme_add_global("table", table, mod);
scheme_finish_primitive_module(mod);
MZ_GC_UNREG();
}
static int run_bc(Scheme_Env* e, int argc, char* argv[]) {
(void)argc;
(void)argv;
Scheme_Object* l = NULL;
Scheme_Object* a[2] = { NULL, NULL };
MZ_GC_DECL_REG(5); MZ_GC_DECL_REG(5);
MZ_GC_VAR_IN_REG(0, e); MZ_GC_VAR_IN_REG(0, e);
@ -16,6 +65,8 @@ static int run_bc(Scheme_Env *e, int argc, char *argv[]) {
MZ_GC_ARRAY_VAR_IN_REG(2, a, 2); MZ_GC_ARRAY_VAR_IN_REG(2, a, 2);
MZ_GC_REG(); MZ_GC_REG();
bc_setup_ffi_table(e);
size_t load_size = ((uintptr_t) &_binary_app_zo_end) - ((uintptr_t) &_binary_app_zo_start); size_t load_size = ((uintptr_t) &_binary_app_zo_end) - ((uintptr_t) &_binary_app_zo_start);
scheme_register_embedded_load(load_size, &_binary_app_zo_start); scheme_register_embedded_load(load_size, &_binary_app_zo_start);
scheme_embedded_load(load_size, &_binary_app_zo_start, 1); scheme_embedded_load(load_size, &_binary_app_zo_start, 1);

14
run.rkt
View File

@ -1,3 +1,17 @@
#lang racket/base #lang racket/base
(require ffi/unsafe)
(displayln "hello world") (displayln "hello world")
(void (for/list ([i (in-list '(1 2 3 4 5))]) (printf "loop: ~a\n" i)))
(define table (dynamic-require ''static-ffi 'table))
(displayln "ffi table")
(displayln table)
(define func (cast (cadr (car table)) _int64 (_fun -> _void)))
(displayln "calling")
(func)
(displayln "back")