我以前问过这个问题,没有人回答。我又问了一遍,这次简化了很多。在
我有一个pythonctypes调用的dll,它有一个回调函数。回调在整个过程中都能正常工作(如果我在visualstudio中单步执行程序,我可以看到它正在运行),但是在退出visualstudio时抛出一个“访问冲突”异常。但是如果我从dll中删除对回调的调用,它会正常退出,而不会出现访问冲突。在
我还需要做些什么来退出带有回调的dll吗?我已经研究了好几个小时了,但是我在网上还没有找到任何可以解决这个问题的东西。在
这是ctypes代码。我省略了dll代码来保持这个简短(它是用NASM编写的),但是如果需要的话,我也可以发布它。在
def SimpleTestFunction_asm(X):
Input_Length_Array = []
Input_Length_Array.append(len(X)*8)
CA_X = (ctypes.c_double * len(X))(*X)
length_array_out = (ctypes.c_double * len(Input_Length_Array))(*Input_Length_Array)
hDLL = ctypes.WinDLL("C:/Test_Projects/SimpleTestFunction/SimpleTestFunction.dll")
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_longlong)]
CallName.restype = ctypes.POINTER(ctypes.c_int64)
#__________
#The callback function
LibraryCB = ctypes.WINFUNCTYPE(ctypes.c_double, ctypes.c_double)
def LibraryCall(ax):
bx = math.ceil(ax)
return (bx)
lib_call = LibraryCB(LibraryCall)
lib_call = ctypes.cast(lib_call,ctypes.POINTER(ctypes.c_longlong))
#__________
ret_ptr = CallName(CA_X,length_array_out,lib_call)
我真的很感激有什么办法解决这个问题。我希望这个简化的帖子能有所帮助。在
非常感谢。在
@Mark Tolonen,非常感谢您的详细分析。我将此作为答案发布,因为代码的格式在注释中无法正确显示,但我选择了您的答案作为最佳答案。在
我怀疑堆栈对齐可能是问题所在,并且您消除了ctypes作为源代码,所以我将重点放在堆栈上。这是我所做的。在
在NASM代码中,我在进入时按rbp和rdi,然后在退出时恢复它们。在这里,在调用之前,我通过从堆栈中弹出rbp和rdi来设置堆栈状态。然后从rsp中减去32个字节(不是40个)。调用完成后,我将恢复堆栈状态:
对于一个外部函数调用(比如C库函数),我必须减去40个字节,但是对于这个回调,我只需要32个字节。在你回答之前,我试过用40个字节,但没用。我想原因是因为它不是调用外部库,而是对首先调用dll的ctypes代码的回调。在
还有一件事。调用发送一个浮点值(xmm0)并返回一个整数值,但是整数值返回到xmm0寄存器中,而不是rax。将ctypes中的原型设置为整数返回值并不能做到这一点。它必须保持这样:
^{pr2}$再次感谢你的答复。你带我去哪里找。在
p.S.length_array_out将输入数组的长度传递给NASM。如果我传递了多个数组,则长度_array_out将更长,每个长度有一个qword;目前我在输入时将qword转换为整数。在
我对您的代码做了一些小的修改,使实际运行(导入),并添加了一个打印来查看传递的对象的地址和返回值,另外还创建了一个等效的C DLL来确保指针正确传递和回调正常工作。在
Python:
在测试.DLL资料来源:
^{pr2}$输出:
您可以看到指针是相同的,回调返回值和函数返回值是正确的。在
很可能您的NASM代码没有正确实现调用约定,或者破坏了访问数组的堆栈。我只是做了最起码的工作来让你的Python代码正常工作。我确实觉得奇怪,
length_array_out
总是一个长度为1的双数组,其值是输入数组X
长度的8倍。NASM代码如何知道数组的长度?在{and可以声明一个回调函数来代替cd3}类型转换:
相关问题 更多 >
编程相关推荐