commit
633cfb5b43
4 changed files with 90 additions and 7 deletions
|
|
@ -16,13 +16,16 @@ if dll == nil:
|
||||||
|
|
||||||
# Now let's try and get a symbol from it
|
# Now let's try and get a symbol from it
|
||||||
var procSym = dll.symAddr("hello")
|
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
|
# We need to set up our call first. This procedure takes one int argument
|
||||||
var
|
var
|
||||||
cif: Tcif
|
cif: Tcif
|
||||||
params: ParamList
|
params: ParamList
|
||||||
# The argument the procedure takes
|
# 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
|
# Prepare the call, with the aforementioned params, and no return type
|
||||||
if OK != prep_cif(cif, DEFAULT_ABI, 1, type_void.addr, params):
|
if OK != prep_cif(cif, DEFAULT_ABI, 1, type_void.addr, params):
|
||||||
echo "Something went wrong with preparing the statement"
|
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
|
# Now let's set up a list of arguments
|
||||||
var args: ArgList
|
var args: ArgList
|
||||||
var i = 100
|
var i: int32 = 100
|
||||||
args[0] = i.addr
|
args[0] = i.addr
|
||||||
|
|
||||||
# And call the symbol with our argument
|
# And call the symbol with our argument
|
||||||
call(cif, procSym, nil, args)
|
call(cif, procSym, nil, args)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Let's do another one. This time without arguments, but with a return type
|
# 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"
|
echo "Something went wrong with preparing the statement"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
|
|
@ -45,7 +50,57 @@ if OK != prep_cif(cif, DEFAULT_ABI, 0, type_sint64.addr, params):
|
||||||
var highFiveSym = dll.symAddr("highFive")
|
var highFiveSym = dll.symAddr("highFive")
|
||||||
|
|
||||||
# Set up the position of our return value and call the procedure
|
# 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)
|
call(cif, highFiveSym, theFive.addr, args)
|
||||||
echo theFive
|
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
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
# Compile with: nim c --noMain --app:lib plugin.nim
|
# 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
|
echo "Hello world, ", x
|
||||||
|
|
||||||
proc highFive(): int {.exportc.} =
|
proc highFive(): int32 {.cdecl, exportc, dynlib.} =
|
||||||
result = 5
|
result = 5
|
||||||
echo "Here you go!"
|
echo "Here you go!"
|
||||||
|
|
||||||
|
proc helloFancy(f: proc (n: int32): int32 {.cdecl.}) {.exportc.} =
|
||||||
|
echo "Such fancyness, ", f(42)
|
||||||
|
|
|
||||||
25
libffi.nim
25
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;
|
proc call*(cif: var TCif; fn, rvalue: pointer;
|
||||||
avalue: ArgList) {.cdecl, importc: "ffi_call", mylib.}
|
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
|
# Useful for eliminating compiler warnings
|
||||||
##define FFI_FN(f) ((void (*)(void))f)
|
##define FFI_FN(f) ((void (*)(void))f)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Package
|
# Package
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
author = "Andreas Rumpf"
|
author = "Andreas Rumpf"
|
||||||
description = "libffi wrapper for Nim."
|
description = "libffi wrapper for Nim."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue