From b613920f1fdf530d09274a16a86a91249755fd14 Mon Sep 17 00:00:00 2001 From: Arnaud Castellanos Galea Date: Mon, 5 Oct 2020 10:22:56 +0800 Subject: [PATCH 01/10] Add support for closure api --- libffi.nim | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) 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) From 4c880db828242064a347413953ffe310357726e6 Mon Sep 17 00:00:00 2001 From: Arnaud Castellanos Galea Date: Mon, 5 Oct 2020 10:23:43 +0800 Subject: [PATCH 02/10] Update Examples --- examples/loader.nim | 63 ++++++++++++++++++++++++++++++++++++++++++--- examples/plugin.nim | 7 +++-- 2 files changed, 64 insertions(+), 6 deletions(-) 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) From e9c9c5c465101bf8cf0661d45a1a4e723a01cd2d Mon Sep 17 00:00:00 2001 From: Arnaud Castellanos Galea Date: Mon, 5 Oct 2020 11:33:00 +0800 Subject: [PATCH 03/10] Increase library version number --- libffi.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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" From 88401f510fb978818fe0167c5e4c6582ff515a38 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 6 Oct 2020 15:08:05 +0200 Subject: [PATCH 04/10] 1.0.3 --- libffi.nimble | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libffi.nimble b/libffi.nimble index 29fd725..ed4d639 100644 --- a/libffi.nimble +++ b/libffi.nimble @@ -1,11 +1,11 @@ -# Package -version = "1.0.2" -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.3" +author = "Andreas Rumpf" +description = "libffi wrapper for Nim." +license = "MIT" + +when defined(windows): + installExt = @["nim", "c", "h", "s"] + +# Dependencies +requires "nim >= 0.10.0" From e3c08b54b895783759277429fd4f3328f76cbd2a Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 6 Oct 2020 15:32:25 +0200 Subject: [PATCH 05/10] added styleChecks:off --- libffi.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libffi.nim b/libffi.nim index c586006..6d8e3a1 100644 --- a/libffi.nim +++ b/libffi.nim @@ -8,6 +8,8 @@ # {.deadCodeElim: on.} +when defined(nimHasStyleChecks): + {.push styleChecks: off.} when defined(windows): import os @@ -188,3 +190,5 @@ proc prep_closure_loc*(closure: ptr Closure, cif: var TCif, fun: ClosureProc, us # Useful for eliminating compiler warnings ##define FFI_FN(f) ((void (*)(void))f) +when defined(nimHasStyleChecks): + {.pop.} # {.push styleChecks: off.} From d5b23c440584f1569b8a5c8469ad6dcc95141c4d Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 6 Oct 2020 15:32:34 +0200 Subject: [PATCH 06/10] 1.0.4 --- libffi.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libffi.nimble b/libffi.nimble index ed4d639..670c088 100644 --- a/libffi.nimble +++ b/libffi.nimble @@ -1,5 +1,5 @@ # Package -version = "1.0.3" +version = "1.0.4" author = "Andreas Rumpf" description = "libffi wrapper for Nim." license = "MIT" From 3c93bfdedcb063a2d1d91ab2aa918cf440cb2acb Mon Sep 17 00:00:00 2001 From: Arnaud Castellanos Galea Date: Mon, 30 Nov 2020 17:25:28 +0800 Subject: [PATCH 07/10] Fix wrong alllocation size for closure api --- libffi.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libffi.nim b/libffi.nim index 6d8e3a1..32931ed 100644 --- a/libffi.nim +++ b/libffi.nim @@ -184,7 +184,7 @@ type 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) + 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.} From 4bb54e221eaa7a399f04e6bb3f58ceae184d4a54 Mon Sep 17 00:00:00 2001 From: Arnaud Castellanos Galea Date: Mon, 30 Nov 2020 17:25:36 +0800 Subject: [PATCH 08/10] 1.0.5 --- libffi.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libffi.nimble b/libffi.nimble index 670c088..13cacfd 100644 --- a/libffi.nimble +++ b/libffi.nimble @@ -1,5 +1,5 @@ # Package -version = "1.0.4" +version = "1.0.5" author = "Andreas Rumpf" description = "libffi wrapper for Nim." license = "MIT" From ea5f1f2b8e47f5ce10cd183d9496ffdec85d863f Mon Sep 17 00:00:00 2001 From: SolitudeSF Date: Mon, 1 Mar 2021 16:16:16 +0200 Subject: [PATCH 09/10] Correctly match dynlib --- libffi.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libffi.nim b/libffi.nim index 32931ed..410253d 100644 --- a/libffi.nim +++ b/libffi.nim @@ -46,7 +46,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 From 994262b3cb6b78261ee3ab0d83e85fc74389692b Mon Sep 17 00:00:00 2001 From: Joey Date: Mon, 22 Aug 2022 10:09:23 -0600 Subject: [PATCH 10/10] Update libffi to work with latest version Libffi made some changes to their dll api. They no longer expose `ffi_type_longdouble`, but instead, offer it in a header like so: ```c #define ffi_type_longdouble ffi_type_double ``` Also, `elements` is listed as a `ptr ptr` in the `ffi.h` file, but when used, it is apparent that it's supposed to be a pointer to an array of pointers. --- libffi.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libffi.nim b/libffi.nim index 89e8317..416d801 100644 --- a/libffi.nim +++ b/libffi.nim @@ -80,7 +80,7 @@ type size*: int alignment*: uint16 typ*: uint16 - elements*: ptr ptr Type + elements*: ptr UncheckedArray[ptr Type] {.deprecated: [TType: Type].} var @@ -96,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