2020-10-14 21:33:47 +00:00
|
|
|
#define MZ_PRECISE_GC
|
|
|
|
|
|
|
|
#include <racket/scheme.h>
|
2020-10-15 02:18:35 +00:00
|
|
|
#include <stdint.h>
|
2020-10-14 21:33:47 +00:00
|
|
|
#include <stdio.h>
|
2020-10-17 03:33:50 +00:00
|
|
|
|
|
|
|
// patchups for musl vs glibc stuff
|
|
|
|
#include <sys/stat.h>
|
2020-10-19 06:35:20 +00:00
|
|
|
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) {
|
2020-10-17 03:33:50 +00:00
|
|
|
return __xstat(1, path, buf);
|
|
|
|
}
|
2020-10-19 06:35:20 +00:00
|
|
|
int fstat(int fildes, struct stat* buf) {
|
2020-10-17 03:33:50 +00:00
|
|
|
return __fxstat(1, fildes, buf);
|
|
|
|
}
|
2020-10-19 06:35:20 +00:00
|
|
|
int lstat(const char* restrict path, struct stat* restrict buf) {
|
2020-10-17 03:33:50 +00:00
|
|
|
return __lxstat(1, path, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void* __dso_handle;
|
2020-10-19 06:35:20 +00:00
|
|
|
extern int __cxa_atexit(void (*)(), void*, void*);
|
2020-10-17 03:33:50 +00:00
|
|
|
|
|
|
|
int atexit(void (*function)(void)) {
|
|
|
|
return __cxa_atexit(function, NULL, __dso_handle);
|
|
|
|
}
|
2020-10-14 21:33:47 +00:00
|
|
|
|
2020-10-19 06:35:20 +00:00
|
|
|
// 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 <dlfcn.h>
|
|
|
|
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)
|
2020-10-14 21:33:47 +00:00
|
|
|
extern const char _binary_app_zo_start;
|
|
|
|
extern const char _binary_app_zo_end;
|
|
|
|
|
2020-10-14 22:17:24 +00:00
|
|
|
// 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;
|
2020-10-15 02:18:35 +00:00
|
|
|
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);
|
2020-10-14 22:17:24 +00:00
|
|
|
Scheme_Object* l = NULL;
|
|
|
|
Scheme_Object* a[2] = { NULL, NULL };
|
2020-10-14 21:33:47 +00:00
|
|
|
|
2020-10-15 02:18:35 +00:00
|
|
|
// gc setup
|
2020-10-14 21:33:47 +00:00
|
|
|
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();
|
|
|
|
|
2020-10-14 22:17:24 +00:00
|
|
|
bc_setup_ffi_table(e);
|
|
|
|
|
2020-10-14 21:33:47 +00:00
|
|
|
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;
|
|
|
|
|
2020-10-15 02:18:35 +00:00
|
|
|
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);
|
|
|
|
}
|
2020-10-14 21:33:47 +00:00
|
|
|
|
2020-10-15 02:18:35 +00:00
|
|
|
scheme_current_thread->error_buf = (mz_jmp_buf*) save;
|
2020-10-14 21:33:47 +00:00
|
|
|
MZ_GC_UNREG();
|
2020-10-15 02:18:35 +00:00
|
|
|
return rv;
|
2020-10-14 21:33:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
return scheme_main_setup(1, run_bc, argc, argv);
|
|
|
|
}
|