summaryrefslogtreecommitdiffstats
path: root/asmrun/natdynlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'asmrun/natdynlink.c')
-rw-r--r--asmrun/natdynlink.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/asmrun/natdynlink.c b/asmrun/natdynlink.c
new file mode 100644
index 000000000..05da896b9
--- /dev/null
+++ b/asmrun/natdynlink.c
@@ -0,0 +1,169 @@
+#include "misc.h"
+#include "mlvalues.h"
+#include "memory.h"
+#include "stack.h"
+#include "callback.h"
+#include "alloc.h"
+#include "natdynlink.h"
+#include "osdeps.h"
+#include "fail.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static void *getsym(void *handle, char *module, char *name, int opt){
+ char *fullname = malloc(strlen(module) + strlen(name) + 5);
+ void *sym;
+ sprintf(fullname, "caml%s%s", module, name);
+ sym = caml_dlsym (handle, fullname);
+ /* printf("%s => %lx\n", fullname, (uintnat) sym); */
+ free(fullname);
+ if (NULL == sym && !opt) {
+ printf("natdynlink: cannot find symbol %s\n", fullname);
+ exit(2);
+ }
+ return sym;
+}
+
+
+/* Data segments are used by the Is_atom predicate (mlvalues.h)
+ to detect static Caml blocks.
+
+ Code segments are used in signals_asm.c
+
+ TODO: use dichotomic search
+*/
+
+typedef struct segment {
+ void *begin;
+ void *end;
+ struct segment *next;
+} segment;
+
+segment *caml_dyn_data_segments = NULL;
+segment *caml_dyn_code_segments = NULL;
+
+static segment *segment_cons(void *begin, void *end, segment *tl) {
+ segment *lnk = caml_stat_alloc(sizeof(segment));
+ lnk->begin = begin;
+ lnk->end = end;
+ lnk->next = tl;
+ return lnk;
+}
+
+int caml_is_in_data(void *p) {
+ segment *lnk;
+ for (lnk = caml_dyn_data_segments; NULL != lnk; lnk = lnk->next)
+ if (p >= lnk->begin && p <= lnk->end) return 1;
+ return 0;
+}
+int caml_is_in_code(void *p) {
+ segment *lnk;
+ for (lnk = caml_dyn_code_segments; NULL != lnk; lnk = lnk->next)
+ if (p >= lnk->begin && p <= lnk->end) return 1;
+ return 0;
+}
+
+extern char caml_globals_map[];
+
+CAMLprim value caml_natdynlink_getmap(value unit)
+{
+ return (value)caml_globals_map;
+}
+
+CAMLprim value caml_natdynlink_globals_inited(value unit)
+{
+ return Val_int(caml_globals_inited);
+}
+
+CAMLprim value caml_natdynlink_open(value filename)
+{
+ CAMLparam1 (filename);
+ CAMLlocal1 (res);
+ void *sym;
+ void *handle;
+
+ /* TODO: dlclose in case of error... */
+
+ handle = caml_dlopen(String_val(filename), 1);
+
+ if (NULL == handle)
+ CAMLreturn(caml_copy_string(caml_dlerror()));
+
+ sym = caml_dlsym(handle, "caml_plugin_header");
+ if (NULL == sym)
+ CAMLreturn(caml_copy_string("not an OCaml plugin"));
+
+ res = caml_alloc_tuple(2);
+ Field(res, 0) = (value) handle;
+ Field(res, 1) = (value) (sym);
+ CAMLreturn(res);
+}
+
+CAMLprim value caml_natdynlink_run(void *handle, value symbol) {
+ CAMLparam1 (symbol);
+ CAMLlocal1 (result);
+ void *sym,*sym2;
+
+#define optsym(n) getsym(handle,unit,n,1)
+ char *unit;
+ void (*entrypoint)(void);
+
+ unit = String_val(symbol);
+
+ sym = optsym("__frametable");
+ if (NULL != sym) caml_register_frametable(sym);
+
+ sym = optsym("");
+ if (NULL != sym) caml_register_dyn_global(sym);
+
+ sym = optsym("__data_begin");
+ sym2 = optsym("__data_end");
+ if (NULL != sym && NULL != sym2)
+ caml_dyn_data_segments = segment_cons(sym,sym2,caml_dyn_data_segments);
+
+ sym = optsym("__code_begin");
+ sym2 = optsym("__code_end");
+ if (NULL != sym && NULL != sym2)
+ caml_dyn_code_segments = segment_cons(sym,sym2,caml_dyn_code_segments);
+
+ entrypoint = optsym("__entry");
+ if (NULL != entrypoint) result = caml_callback((value)(&entrypoint), 0);
+ else result = Val_unit;
+
+#undef optsym
+
+ CAMLreturn (result);
+}
+
+CAMLprim value caml_natdynlink_run_toplevel(value filename, value symbol)
+{
+ CAMLparam2 (filename, symbol);
+ CAMLlocal2 (res, v);
+ void *handle;
+
+ /* TODO: dlclose in case of error... */
+
+ handle = caml_dlopen(String_val(filename), 1);
+
+ if (NULL == handle) {
+ res = caml_alloc(1,1);
+ v = caml_copy_string(caml_dlerror());
+ Store_field(res, 0, v);
+ } else {
+ res = caml_alloc(1,0);
+ v = caml_natdynlink_run(handle, symbol);
+ Store_field(res, 0, v);
+ }
+ CAMLreturn(res);
+}
+
+CAMLprim value caml_natdynlink_loadsym(value symbol)
+{
+ CAMLparam1 (symbol);
+ CAMLlocal1 (sym);
+
+ sym = (value) caml_globalsym(String_val(symbol));
+ if (!sym) caml_failwith(String_val(symbol));
+ CAMLreturn(sym);
+}