从ctypes回调返回NASM的指针类型是什么?

时间:2018-05-21 17:21:03

标签: pointers nasm ctypes

我从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的指针?

1 个答案:

答案 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的循环中重新分配,这很慢。这里只有两个值,将它们分配给返回指针是微不足道的。