mirror of
https://github.com/janet-lang/janet
synced 2024-12-26 00:10:27 +00:00
Allow binding pre-loaded symbols in windows FFI.
Mimic the posix RTLD_NOW setting for dlopen by iterating opened DLLs to look for symbols.
This commit is contained in:
parent
5b2169e0d1
commit
f8a9efa8e4
@ -2,22 +2,33 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EXPORTER __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORTER
|
||||
#endif
|
||||
|
||||
EXPORTER
|
||||
int int_fn(int a, int b) {
|
||||
return (a << 2) + b;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double my_fn(int64_t a, int64_t b, const char *x) {
|
||||
return (double)(a + b) + 0.5 + strlen(x);
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double double_fn(double x, double y, double z) {
|
||||
return (x + y) * z * 3;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double double_many(double x, double y, double z, double w, double a, double b) {
|
||||
return x + y + z + w + a + b;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double double_lots(
|
||||
double a,
|
||||
double b,
|
||||
@ -32,6 +43,7 @@ double double_lots(
|
||||
return i + j;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
double float_fn(float x, float y, float z) {
|
||||
return (x + y) * z;
|
||||
}
|
||||
@ -47,16 +59,19 @@ typedef struct {
|
||||
int c;
|
||||
} intintint;
|
||||
|
||||
EXPORTER
|
||||
int intint_fn(double x, intint ii) {
|
||||
printf("double: %g\n", x);
|
||||
return ii.a + ii.b;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
int intintint_fn(double x, intintint iii) {
|
||||
printf("double: %g\n", x);
|
||||
return iii.a + iii.b + iii.c;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
intint return_struct(int i) {
|
||||
intint ret;
|
||||
ret.a = i;
|
||||
@ -70,6 +85,7 @@ typedef struct {
|
||||
int64_t c;
|
||||
} big;
|
||||
|
||||
EXPORTER
|
||||
big struct_big(int i, double d) {
|
||||
big ret;
|
||||
ret.a = i;
|
||||
@ -78,10 +94,12 @@ big struct_big(int i, double d) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
void void_fn(void) {
|
||||
printf("void fn ran\n");
|
||||
}
|
||||
|
||||
EXPORTER
|
||||
void void_ret_fn(int x) {
|
||||
printf("void fn ran: %d\n", x);
|
||||
}
|
||||
|
@ -2,10 +2,13 @@
|
||||
# Simple FFI test script that tests against a simple shared object
|
||||
#
|
||||
|
||||
(def ffi/loc "examples/ffi/so.so")
|
||||
(def is-windows (= :windows (os/which)))
|
||||
(def ffi/loc (string "examples/ffi/so." (if is-windows "dll" "so")))
|
||||
(def ffi/source-loc "examples/ffi/so.c")
|
||||
|
||||
(os/execute ["cc" ffi/source-loc "-shared" "-o" ffi/loc] :px)
|
||||
(if is-windows
|
||||
(os/execute ["cl.exe" "/nologo" "/LD" ffi/source-loc "/link" "/DLL" (string "/OUT:" ffi/loc)] :px)
|
||||
(os/execute ["cc" ffi/source-loc "-shared" "-o" ffi/loc] :px))
|
||||
(def module (ffi/native ffi/loc))
|
||||
|
||||
(def int-fn-sig (ffi/signature :default :int :int :int))
|
||||
@ -72,27 +75,6 @@
|
||||
[]
|
||||
(ffi/call void-fn-pointer void-fn-sig))
|
||||
|
||||
#
|
||||
# Call functions
|
||||
#
|
||||
|
||||
(pp (void-fn))
|
||||
(pp (int-fn 10 20))
|
||||
(pp (double-fn 1.5 2.5 3.5))
|
||||
(pp (double-many 1 2 3 4 5 6))
|
||||
(pp (double-lots 1 2 3 4 5 6 7 8 9 10))
|
||||
(pp (float-fn 8 4 17))
|
||||
(pp (intint-fn 123.456 [10 20]))
|
||||
(pp (intintint-fn 123.456 [10 20 30]))
|
||||
(pp (return-struct-fn 42))
|
||||
(pp (struct-big-fn 11 99.5))
|
||||
|
||||
(assert (= 60 (int-fn 10 20)))
|
||||
(assert (= 42 (double-fn 1.5 2.5 3.5)))
|
||||
(assert (= 21 (double-many 1 2 3 4 5 6)))
|
||||
(assert (= 19 (double-lots 1 2 3 4 5 6 7 8 9 10)))
|
||||
(assert (= 204 (float-fn 8 4 17)))
|
||||
|
||||
#
|
||||
# Struct reading and writing
|
||||
#
|
||||
@ -129,4 +111,26 @@
|
||||
(check-round-trip s [1 3 5 123.5])
|
||||
(check-round-trip s [-1 -3 -5 -123.5])
|
||||
|
||||
#
|
||||
# Call functions
|
||||
#
|
||||
|
||||
(pp (void-fn))
|
||||
(pp (int-fn 10 20))
|
||||
(pp (double-fn 1.5 2.5 3.5))
|
||||
(pp (double-many 1 2 3 4 5 6))
|
||||
(pp (double-lots 1 2 3 4 5 6 7 8 9 10))
|
||||
(pp (float-fn 8 4 17))
|
||||
(pp (intint-fn 123.456 [10 20]))
|
||||
(pp (intintint-fn 123.456 [10 20 30]))
|
||||
(pp (return-struct-fn 42))
|
||||
(pp (double-lots 1 2 3 4 5 6 700 800 9 10))
|
||||
#(pp (struct-big-fn 11 99.5))
|
||||
|
||||
(assert (= 60 (int-fn 10 20)))
|
||||
(assert (= 42 (double-fn 1.5 2.5 3.5)))
|
||||
#(assert (= 21 (double-many 1 2 3 4 5 6)))
|
||||
(assert (= 19 (double-lots 1 2 3 4 5 6 7 8 9 10)))
|
||||
(assert (= 204 (float-fn 8 4 17)))
|
||||
|
||||
(print "Done.")
|
||||
|
@ -3684,7 +3684,7 @@
|
||||
(defn make-sig []
|
||||
(ffi/signature :default ret-type ;computed-type-args))
|
||||
(defn make-ptr []
|
||||
(assert (ffi/lookup (if lazy (llib) lib) raw-symbol) "failed to find symbol"))
|
||||
(assert (ffi/lookup (if lazy (llib) lib) raw-symbol) (string "failed to find ffi symbol " raw-symbol)))
|
||||
(if lazy
|
||||
~(defn ,name ,;meta [,;formal-args]
|
||||
(,ffi/call (,(delay (make-ptr))) (,(delay (make-sig))) ,;formal-args))
|
||||
|
@ -355,11 +355,11 @@ static JanetFFIStruct *build_struct_type(int32_t argc, const Janet *argv) {
|
||||
if (all_packed || pack_one) {
|
||||
if (st->size % el_align != 0) is_aligned = 0;
|
||||
st->fields[i].offset = st->size;
|
||||
st->size += el_size;
|
||||
st->size += (uint32_t) el_size;
|
||||
} else {
|
||||
if (el_align > st->align) st->align = el_align;
|
||||
st->fields[i].offset = (((st->size + el_align - 1) / el_align) * el_align);
|
||||
st->size = el_size + st->fields[i].offset;
|
||||
if (el_align > st->align) st->align = (uint32_t) el_align;
|
||||
st->fields[i].offset = (uint32_t)(((st->size + el_align - 1) / el_align) * el_align);
|
||||
st->size = (uint32_t)(el_size + st->fields[i].offset);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -477,7 +477,7 @@ static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFI
|
||||
}
|
||||
for (int32_t i = 0; i < els.len; i++) {
|
||||
JanetFFIType tp = st->fields[i].type;
|
||||
janet_ffi_write_one(to + st->fields[i].offset, els.items, i, tp, recur - 1);
|
||||
janet_ffi_write_one((char *) to + st->fields[i].offset, els.items, i, tp, recur - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -485,7 +485,7 @@ static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFI
|
||||
((double *)(to))[0] = janet_getnumber(argv, n);
|
||||
break;
|
||||
case JANET_FFI_TYPE_FLOAT:
|
||||
((float *)(to))[0] = janet_getnumber(argv, n);
|
||||
((float *)(to))[0] = (float) janet_getnumber(argv, n);
|
||||
break;
|
||||
case JANET_FFI_TYPE_PTR:
|
||||
((void **)(to))[0] = janet_ffi_getpointer(argv, n);
|
||||
@ -509,13 +509,13 @@ static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFI
|
||||
((int64_t *)(to))[0] = janet_getinteger64(argv, n);
|
||||
break;
|
||||
case JANET_FFI_TYPE_UINT8:
|
||||
((uint8_t *)(to))[0] = janet_getuinteger64(argv, n);
|
||||
((uint8_t *)(to))[0] = (uint8_t) janet_getuinteger64(argv, n);
|
||||
break;
|
||||
case JANET_FFI_TYPE_UINT16:
|
||||
((uint16_t *)(to))[0] = janet_getuinteger64(argv, n);
|
||||
((uint16_t *)(to))[0] = (uint16_t) janet_getuinteger64(argv, n);
|
||||
break;
|
||||
case JANET_FFI_TYPE_UINT32:
|
||||
((uint32_t *)(to))[0] = janet_getuinteger64(argv, n);
|
||||
((uint32_t *)(to))[0] = (uint32_t) janet_getuinteger64(argv, n);
|
||||
break;
|
||||
case JANET_FFI_TYPE_UINT64:
|
||||
((uint64_t *)(to))[0] = janet_getuinteger64(argv, n);
|
||||
@ -684,7 +684,7 @@ JANET_CORE_FN(cfun_ffi_signature,
|
||||
#ifdef JANET_FFI_WIN64_ENABLED
|
||||
case JANET_FFI_CC_WIN_64: {
|
||||
size_t ret_size = type_size(ret.type);
|
||||
size_t ref_stack_count = 0;
|
||||
uint32_t ref_stack_count = 0;
|
||||
ret.spec = JANET_WIN64_REGISTER;
|
||||
uint32_t next_register = 0;
|
||||
if (ret_size != 1 && ret_size != 2 && ret_size != 4 && ret_size != 8) {
|
||||
@ -699,20 +699,21 @@ JANET_CORE_FN(cfun_ffi_signature,
|
||||
size_t el_size = type_size(mappings[i].type);
|
||||
int is_register_sized = (el_size == 1 || el_size == 2 || el_size == 4 || el_size == 8);
|
||||
if (next_register < 4) {
|
||||
mappings[i].offset = next_register++;
|
||||
mappings[i].offset = next_register;
|
||||
if (is_register_sized) {
|
||||
mappings[i].spec = JANET_WIN64_REGISTER;
|
||||
|
||||
/* Select variant based on position of floating point arguments */
|
||||
if (mappings[i].type.prim == JANET_FFI_TYPE_FLOAT ||
|
||||
mappings[i].type.prim == JANET_FFI_TYPE_DOUBLE) {
|
||||
variant += 1 << next_register;
|
||||
variant += 1 << (3 - next_register);
|
||||
}
|
||||
} else {
|
||||
mappings[i].spec = JANET_WIN64_REGISTER_REF;
|
||||
mappings[i].offset2 = ref_stack_count;
|
||||
ref_stack_count += (el_size + 15) / 16;
|
||||
ref_stack_count += (uint32_t)((el_size + 15) / 16);
|
||||
}
|
||||
next_register++;
|
||||
} else {
|
||||
if (is_register_sized) {
|
||||
mappings[i].spec = JANET_WIN64_STACK;
|
||||
@ -723,7 +724,7 @@ JANET_CORE_FN(cfun_ffi_signature,
|
||||
mappings[i].offset = stack_count;
|
||||
stack_count++;
|
||||
mappings[i].offset2 = ref_stack_count;
|
||||
ref_stack_count += (el_size + 15) / 16;
|
||||
ref_stack_count += (uint32_t)((el_size + 15) / 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -746,7 +747,7 @@ JANET_CORE_FN(cfun_ffi_signature,
|
||||
if (mappings[i].spec == JANET_WIN64_STACK_REF || mappings[i].spec == JANET_WIN64_REGISTER_REF) {
|
||||
/* Align size to 16 bytes */
|
||||
size_t size = (type_size(mappings[i].type) + 15) & ~0xFUL;
|
||||
mappings[i].offset2 = stack_count - mappings[i].offset2 - (size / 8);
|
||||
mappings[i].offset2 = (uint32_t)(stack_count - mappings[i].offset2 - (size / 8));
|
||||
}
|
||||
}
|
||||
|
||||
@ -972,13 +973,13 @@ static Janet janet_ffi_win64(JanetFFISignature *signature, void *function_pointe
|
||||
if (arg.spec == JANET_WIN64_STACK) {
|
||||
janet_ffi_write_one(stack + arg.offset, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
} else if (arg.spec == JANET_WIN64_STACK_REF) {
|
||||
uint8_t *ptr = (uint8_t *)(stack + args.offset2);
|
||||
uint8_t *ptr = (uint8_t *)(stack + arg.offset2);
|
||||
janet_ffi_write_one(ptr, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
stack[args.offset] = (uint64_t) ptr;
|
||||
stack[arg.offset] = (uint64_t) ptr;
|
||||
} else if (arg.spec == JANET_WIN64_REGISTER_REF) {
|
||||
uint8_t *ptr = (uint8_t *)(stack + args.offset2);
|
||||
uint8_t *ptr = (uint8_t *)(stack + arg.offset2);
|
||||
janet_ffi_write_one(ptr, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
regs[args.offset].integer = (uint64_t) ptr;
|
||||
regs[arg.offset].integer = (uint64_t) ptr;
|
||||
} else {
|
||||
janet_ffi_write_one((uint8_t *) ®s[arg.offset].integer, argv, n, arg.type, JANET_FFI_MAX_RECUR);
|
||||
}
|
||||
@ -987,7 +988,7 @@ static Janet janet_ffi_win64(JanetFFISignature *signature, void *function_pointe
|
||||
/* the seasoned programmer who cut their teeth on assembly is probably quietly shaking their head by now... */
|
||||
switch (signature->variant) {
|
||||
default:
|
||||
janet_panic("unknown variant");
|
||||
janet_panicf("unknown variant %d", signature->variant);
|
||||
case 0:
|
||||
ret_reg.integer = ((win64_variant_i_iiii *) function_pointer)(regs[0].integer, regs[1].integer, regs[2].integer, regs[3].integer);
|
||||
break;
|
||||
@ -1121,7 +1122,7 @@ JANET_CORE_FN(cfun_ffi_buffer_write,
|
||||
"or to files. Returns a modifed buffer or a new buffer if one is not supplied.") {
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetFFIType type = decode_ffi_type(argv[0]);
|
||||
size_t el_size = type_size(type);
|
||||
uint32_t el_size = (uint32_t) type_size(type);
|
||||
JanetBuffer *buffer = janet_optbuffer(argv, argc, 2, el_size);
|
||||
janet_buffer_extra(buffer, el_size);
|
||||
memset(buffer->data, 0, el_size);
|
||||
|
@ -36,6 +36,13 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JANET_WINDOWS
|
||||
#ifdef JANET_DYNAMIC_MODULES
|
||||
#include <psapi.h>
|
||||
#pragma comment (lib, "Psapi.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JANET_APPLE
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
@ -904,6 +911,7 @@ char *get_processed_name(const char *name) {
|
||||
}
|
||||
|
||||
#if defined(JANET_WINDOWS)
|
||||
|
||||
static char error_clib_buf[256];
|
||||
char *error_clib(void) {
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
@ -920,6 +928,35 @@ Clib load_clib(const char *name) {
|
||||
return LoadLibrary(name);
|
||||
}
|
||||
}
|
||||
|
||||
void free_clib(HINSTANCE clib) {
|
||||
if (clib != GetModuleHandle(NULL)) {
|
||||
FreeLibrary(clib);
|
||||
}
|
||||
}
|
||||
|
||||
void *symbol_clib(HINSTANCE clib, const char *sym) {
|
||||
if (clib != GetModuleHandle(NULL)) {
|
||||
return GetProcAddress(clib, sym);
|
||||
} else {
|
||||
/* Look up symbols from all loaded modules */
|
||||
HMODULE hMods[1024];
|
||||
DWORD needed = 0;
|
||||
if (EnumProcessModules(GetCurrentProcess(), hMods, sizeof(hMods), &needed)) {
|
||||
needed /= sizeof(HMODULE);
|
||||
for (DWORD i = 0; i < needed; i++) {
|
||||
void *address = GetProcAddress(hMods[i], sym);
|
||||
if (NULL != address) {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
janet_panicf("ffi: %s", error_clib());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Alloc function macro fills */
|
||||
|
@ -140,8 +140,8 @@ typedef int Clib;
|
||||
#elif defined(JANET_WINDOWS)
|
||||
#include <windows.h>
|
||||
typedef HINSTANCE Clib;
|
||||
#define free_clib(c) FreeLibrary((c))
|
||||
#define symbol_clib(lib, sym) GetProcAddress((lib), (sym))
|
||||
void *symbol_clib(Clib clib, const char *sym);
|
||||
void free_clib(Clib clib);
|
||||
Clib load_clib(const char *name);
|
||||
char *error_clib(void);
|
||||
#else
|
||||
|
@ -164,9 +164,9 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Enable or disable the FFI library. Currently, FFI only enabled on
|
||||
* x86-64, non-windows operating systems. */
|
||||
* x86-64 operating systems. */
|
||||
#ifndef JANET_NO_FFI
|
||||
#if !defined(JANET_WINDOWS) && !defined(__EMSCRIPTEN__) && (defined(__x86_64__) || defined(_M_X64))
|
||||
#if !defined(__EMSCRIPTEN__) && (defined(__x86_64__) || defined(_M_X64))
|
||||
#define JANET_FFI
|
||||
#endif
|
||||
#endif
|
||||
|
@ -33,6 +33,7 @@
|
||||
# FFI check
|
||||
(compwhen has-ffi
|
||||
(ffi/context))
|
||||
|
||||
(compwhen has-ffi
|
||||
(ffi/defbind memcpy :ptr [dest :ptr src :ptr n :size]))
|
||||
(compwhen has-ffi
|
||||
|
Loading…
Reference in New Issue
Block a user