#define MZ_PRECISE_GC #include #include #include // patchups for musl vs glibc stuff #include extern int __xstat(int, const char* restrict, struct stat* restrict); extern int __lxstat(int, const char* restrict, struct stat* restrict); extern int __fxstat(int, int, struct stat*); int stat(const char* restrict path, struct stat* restrict buf) { return __xstat(1, path, buf); } int fstat(int fildes, struct stat* buf) { return __fxstat(1, fildes, buf); } int lstat(const char* restrict path, struct stat* restrict buf) { return __lxstat(1, path, buf); } extern void* __dso_handle; extern int __cxa_atexit(void (*)(), void*, void*); int atexit(void (*function)(void)) { return __cxa_atexit(function, NULL, __dso_handle); } // custom entry wrapper // the thing with this project is it's going to generate a binary that can run literally everwhere // if you build it on exactly the right environment // as opposed to the usual portable build, unportable output // ok so this basically assumes startup.bin contains ONLY .text and .rodata and that it's PIE and // that .rodata directly follows .text and that entry is at the top of .text, and like, this is all // true but it's not _guaranteed_ so like, weh void __attribute__((noinline)) crimes_startup_run(void* addr) { // haha yes asm volatile(".incbin \"startup.bin\"" :: "rm"(addr) : "memory"); } #include extern void _start(unsigned long, unsigned long, unsigned long, unsigned long); void elf_crimes(void) { // re-exec if necessary crimes_startup_run(__builtin_frame_address(0)); // this _should_ tail call and all should be well...hopefully... return _start(0, 0, 0, 0); } // embedded zo (but fast, we avoid rendering and subsequently unrendering megabytes of C which is // Mega Slow and simply ld -r -b the zo at the cost of build portability but idk i'm pretty sure // bsd has -r -b too tbh) extern const char _binary_app_zo_start; extern const char _binary_app_zo_end; // ffi example call 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; volatile mz_jmp_buf* save; mz_jmp_buf fresh; int rv = 0; size_t load_size = ((uintptr_t) &_binary_app_zo_end) - ((uintptr_t) &_binary_app_zo_start); Scheme_Object* l = NULL; Scheme_Object* a[2] = { NULL, NULL }; // gc setup MZ_GC_DECL_REG(5); MZ_GC_VAR_IN_REG(0, e); MZ_GC_VAR_IN_REG(1, l); MZ_GC_ARRAY_VAR_IN_REG(2, a, 2); MZ_GC_REG(); bc_setup_ffi_table(e); scheme_register_embedded_load(load_size, &_binary_app_zo_start); scheme_embedded_load(load_size, &_binary_app_zo_start, 1); l = scheme_make_null(); l = scheme_make_pair(scheme_intern_symbol(APP_NAME), l); l = scheme_make_pair(scheme_intern_symbol("quote"), l); a[0] = l; a[1] = scheme_false; save = scheme_current_thread->error_buf; scheme_current_thread->error_buf = &fresh; if (scheme_setjmp(scheme_error_buf)) { fprintf(stderr, "[WRAPPER] encountered top-level racket error. aborting\n"); rv = -1; } else { scheme_dynamic_require(2, a); } scheme_current_thread->error_buf = (mz_jmp_buf*) save; MZ_GC_UNREG(); return rv; } int main(int argc, char *argv[]) { return scheme_main_setup(1, run_bc, argc, argv); }