diff --git a/examples/loader.nim b/examples/loader.nim index 537914e..20f824f 100644 --- a/examples/loader.nim +++ b/examples/loader.nim @@ -16,13 +16,16 @@ if dll == nil: # Now let's try and get a symbol from it var procSym = dll.symAddr("hello") +if procSym == nil: + echo "Could not get symbol for hello" + quit 1 # We need to set up our call first. This procedure takes one int argument var cif: Tcif params: ParamList # The argument the procedure takes -params[0] = type_sint64.addr +params[0] = type_sint32.addr # Prepare the call, with the aforementioned params, and no return type if OK != prep_cif(cif, DEFAULT_ABI, 1, type_void.addr, params): echo "Something went wrong with preparing the statement" @@ -30,14 +33,16 @@ if OK != prep_cif(cif, DEFAULT_ABI, 1, type_void.addr, params): # Now let's set up a list of arguments var args: ArgList -var i = 100 +var i: int32 = 100 args[0] = i.addr # And call the symbol with our argument call(cif, procSym, nil, args) + + # Let's do another one. This time without arguments, but with a return type -if OK != prep_cif(cif, DEFAULT_ABI, 0, type_sint64.addr, params): +if OK != prep_cif(cif, DEFAULT_ABI, 0, type_sint32.addr, params): echo "Something went wrong with preparing the statement" quit 1 @@ -45,7 +50,57 @@ if OK != prep_cif(cif, DEFAULT_ABI, 0, type_sint64.addr, params): var highFiveSym = dll.symAddr("highFive") # Set up the position of our return value and call the procedure -var theFive = 0 +var theFive: int32 = 0 call(cif, highFiveSym, theFive.addr, args) echo theFive + + + +# And yet another example. This one with a simple function argument +params[0] = type_pointer.addr +if OK != prep_cif(cif, DEFAULT_ABI, 1, type_void.addr, params): + echo "Something went wrong with preparing the statement" + quit 1 + +var helloFancySym = dll.symAddr("helloFancy") +if helloFancySym == nil: + echo "Could not get symbol for helloFancy" + quit 1 + +# This is the function that will be called +proc fancyTen(x: int32): int32 {.cdecl.} = + result = 10 + echo "It was given, ", x + +var fancyTenPointer: pointer = fancyTen +args[0] = fancyTenPointer.addr +call(cif, helloFancySym, nil, args) + + + +# Now, let's build a function at runtime with the closure API + +proc uglyEleven(cif: var TCif, ret: pointer, args: UncheckedArray[pointer], user_data: pointer) {.cdecl.} = + #long int x = *(long int*)args[0]; + var x = cast[ptr int32](args[0])[] + var c = cast[ptr int](user_data)[] + echo "Given: ", x, ", Context: ", c + cast[ptr int32](ret)[] = 11 + +var bound: pointer = nil +var closure: ptr Closure = closure_alloc(bound) + +# Initialize the cif +if OK != prep_cif(cif, DEFAULT_ABI, 1, type_sint32.addr, params): + echo "Something went wrong with preparing the statement" + quit 1 + +var user_data = 17 + +if OK != prep_closure_loc(closure, cif, uglyEleven, user_data.addr, bound): + echo "Something went wrong initializing the closure" + quit 1 + +var r = cast[proc (x: int32): int32 {.cdecl.}](bound)(15) +echo "Result, ", r \ No newline at end of file diff --git a/examples/plugin.nim b/examples/plugin.nim index 12688f2..715f6ae 100644 --- a/examples/plugin.nim +++ b/examples/plugin.nim @@ -1,7 +1,10 @@ # Compile with: nim c --noMain --app:lib plugin.nim -proc hello(x: int) {.exportc.} = +proc hello(x: int32) {.cdecl, exportc, dynlib.} = echo "Hello world, ", x -proc highFive(): int {.exportc.} = +proc highFive(): int32 {.cdecl, exportc, dynlib.} = result = 5 echo "Here you go!" + +proc helloFancy(f: proc (n: int32): int32 {.cdecl.}) {.exportc.} = + echo "Such fancyness, ", f(42) diff --git a/libffi.nim b/libffi.nim index 0e9b69e..c586006 100644 --- a/libffi.nim +++ b/libffi.nim @@ -161,5 +161,30 @@ proc prep_cif*(cif: var TCif; abi: TABI; nargs: cuint; rtype: ptr Type; proc call*(cif: var TCif; fn, rvalue: pointer; avalue: ArgList) {.cdecl, importc: "ffi_call", mylib.} + +when defined(x8664): + const TRAMPOLINE_SIZE = 24 +elif defined(windows) and defined(x86): + const TRAMPOLINE_SIZE = 52 +elif defined(amd64) and defined(windows): + const TRAMPOLINE_SIZE = 29 +else: + const TRAMPOLINE_SIZE = 10 + +type + ClosureProc = proc (cif: var TCif, ret: pointer, args: UncheckedArray[pointer], user_data: pointer) {.cdecl.} + Closure* {.pure, final.} = object + tramp: array[0..TRAMPOLINE_SIZE, uint8] + cif: ptr TCif + fun: ClosureProc + user_data: pointer + +proc closure_alloc*(size: int, code: var pointer): ptr Closure {.cdecl, importc: "ffi_closure_alloc", mylib.} +# same but taking care of the size +template closure_alloc*(code: var pointer): ptr Closure = + closure_alloc(sizeof(ClosureProc), code) +proc closure_free*(closure: ptr Closure) {.cdecl, importc: "ffi_closure_free", mylib.} +proc prep_closure_loc*(closure: ptr Closure, cif: var TCif, fun: ClosureProc, user_data: pointer, codeloc: pointer): Status {.cdecl, importc: "ffi_prep_closure_loc", mylib.} + # Useful for eliminating compiler warnings ##define FFI_FN(f) ((void (*)(void))f) diff --git a/libffi.nimble b/libffi.nimble index f0d24e8..29fd725 100644 --- a/libffi.nimble +++ b/libffi.nimble @@ -1,5 +1,5 @@ # Package -version = "1.0.1" +version = "1.0.2" author = "Andreas Rumpf" description = "libffi wrapper for Nim." license = "MIT"