我从ctypes调用NASM 64 dll;它包括对SciPy函数integrate.dblquad的回调。回调接收指向两个双精度数组的指针,并返回指向两个双精度数组的指针。回调函数正确执行并在Python中显示正确的结果,但我无法将指针返回给NASM。
我在5月12日将这个问题发布为What is the correct pointer type to return from a ctypes callback?的ctypes问题。我收到了一个基于C语言的答案以及我在NASM中无法使用的解决方案。我希望有人可以帮助解决这个问题在NASM中的作用,而不是C.
以下是调用dll并执行回调的ctypes代码的一部分:
CA_data1 = (ctypes.c_double * len(data1))(*data1)
CA_data2 = (ctypes.c_double * len(data2))(*data2)
hDLL = ctypes.WinDLL("C:/NASM_Test_Projects/SciPy_Test/SciPy_Test.dll")
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_longlong)]
CallName.restype = ctypes.c_double
ret_ptr = CallName(CA_data1,CA_data2,length_array_out,lib_call)
这是回调代码:
from scipy.integrate import dblquad
import ctypes
def LibraryCall(ptr):
n = ctypes.cast(ptr,ctypes.POINTER(ctypes.c_double))
x = n[0]
y = n[1]
area = dblquad(lambda x, y: x*y, 0, 0.5, lambda x: 0, lambda x: 1-2*x)
return_val = area[0], area[1]
r_val = (ctypes.c_double * len(return_val))(*return_val)
rv = ctypes.cast(r_val,ctypes.POINTER(ctypes.c_double))
#All three of these return the same data:
return (r_val)
#return (rv)
#return (return_val)
lib_call = LibraryCB(LibraryCall)
lib_call = ctypes.cast(lib_call,ctypes.POINTER(ctypes.c_longlong))
我也尝试过使用这些声明,但没有区别:
LibraryCB = ctypes.WINFUNCTYPE(None, ctypes.POINTER(ctypes.c_double))
LibraryCB = ctypes.PYFUNCTYPE(None,ctypes.POINTER(ctypes.c_double))
以下是调用回调并从变量[dblquad_Pointer]中的回调接收指针的NASM代码的一部分):
pop rbp
pop rdi
sub rsp,32
call [scipy.integrate_dblquad_Pointer]
add rsp,32
push rdi
push rbp
mov [dblquad_Pointer],rax
; check the values returned
lea rdi,[rel dblquad_Pointer]
mov rbp,qword [rdi] ; Return Pointer
movsd xmm0,qword[rbp]
ret
我尝试了三次单独的调用来返回指向dll的指针:
return (r_val)
return (rv)
return (return_val)
他们三个都将同样不正确的结果从dll返回到ctypes。
我最后发布的建议解决方案是更改DLL代码以使用输入/输出参数,在C中有一个示例,但我知道在NASM中没有等效的。
总而言之,我的问题是,如果我有来自NASM dll发送和接收指针的回调,我该如何处理返回到dll的指针?
答案 0 :(得分:0)
Mark Tolonen上面的回答是有效的,如果我这样做,就像我在这里展示的那样。
在ctypes中:
def LibraryCall(ptr):
x = ptr[0]
y = ptr[1]
area = dblquad(lambda x, y: x*y, 0, 0.5, lambda x: 0, lambda x: 1-2*x)
ptr[0] = area[0] #new
ptr[1] = area[1] #new
return (ptr)
最重要的部分是,在返回到dll时,我已经这样做以检查返回值:
mov [dblquad_Pointer],rax
lea rdi,[rel dblquad_Pointer]
mov rbp,qword [rdi] ; Return Pointer
movsd xmm0,qword[rbp]
那是错的。在进入回调时,我将值放入本地数组callback_data_vals并将其传递给回调函数:
mov rdi,callback_data_vals
movsd [rdi],xmm0
movsd [rdi+8],xmm1
mov rcx,callback_data_vals
[make the call to the callback]
返回时,返回的值位于同一位置(callback_data_vals)。像这样访问它们:
mov rdi,callback_data_vals
movsd xmm0,[rdi]
movsd xmm1,[rdi+8]
对于一个不太实用的更长的数组,因为新的值必须在Python的循环中重新分配,这很慢。这里只有两个值,将它们分配给返回指针是微不足道的。