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 1284774..416d801 100644 --- a/libffi.nim +++ b/libffi.nim @@ -8,6 +8,8 @@ # {.deadCodeElim: on.} +when defined(nimHasStyleChecks): + {.push styleChecks: off.} when defined(windows): import os @@ -23,7 +25,7 @@ when defined(windows): elif defined(macosx): {.pragma: mylib, dynlib: "libffi.dylib".} else: - {.pragma: mylib, dynlib: "libffi.so".} + {.pragma: mylib, dynlib: "libffi.so(.7|)".} type Arg* = int @@ -78,7 +80,7 @@ type size*: int alignment*: uint16 typ*: uint16 - elements*: ptr ptr Type + elements*: ptr UncheckedArray[ptr Type] {.deprecated: [TType: Type].} var @@ -94,7 +96,7 @@ var type_float* {.importc: "ffi_type_float", mylib.}: Type type_double* {.importc: "ffi_type_double", mylib.}: Type type_pointer* {.importc: "ffi_type_pointer", mylib.}: Type - type_longdouble* {.importc: "ffi_type_longdouble", mylib.}: Type + type_longdouble* {.importc: "ffi_type_double", mylib.}: Type type Status* {.size: sizeof(cint).} = enum @@ -140,5 +142,32 @@ 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(Closure), 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) +when defined(nimHasStyleChecks): + {.pop.} # {.push styleChecks: off.} diff --git a/libffi.nimble b/libffi.nimble index f0d24e8..13cacfd 100644 --- a/libffi.nimble +++ b/libffi.nimble @@ -1,11 +1,11 @@ -# Package -version = "1.0.1" -author = "Andreas Rumpf" -description = "libffi wrapper for Nim." -license = "MIT" - -when defined(windows): - installExt = @["nim", "c", "h", "s"] - -# Dependencies -requires "nim >= 0.10.0" +# Package +version = "1.0.5" +author = "Andreas Rumpf" +description = "libffi wrapper for Nim." +license = "MIT" + +when defined(windows): + installExt = @["nim", "c", "h", "s"] + +# Dependencies +requires "nim >= 0.10.0"