【发布时间】:2018-01-05 22:34:04
【问题描述】:
我将两个数组从 Python 程序(使用 ctypes)传递给 NASM 64 位 DLL。在 Windows 调用约定中,指针在 rcx 和 rdx 中传递。这两个数组都是 Int64。数组在 Python 中创建并以这种方式传递给 DLL:
PassArrayType = ctypes.c_int64 * 10
PVarrNew = PassArrayType()
OutputArrayType = ctypes.c_int64 * 1000
arrNew = OutputArrayType()
retvar = SimpleTest(ctypes.byref(PVarrNew), ctypes.byref(arrNew))
在 DLL 中,我可以读取 rcx 中的数组指针,但无法写入数组。
例如,从 rcx 指向的数组中读取一个值就可以了:
push qword [rcx+32]
pop qword [tempvar]
但是向 rcx 指向的数组写入一个值是不行的:
mov rax,1235
push rax
pop qword [rcx+32]
将相同的值写入变量时有效:
mov rax,1235
push rax
pop qword [tempvar]
我无法读取或写入 rdx 指向的数组。
所以我的问题是:
- 为什么我可以从 rcx 指向的数组中读取,但不能写入?
- 为什么我不能读取或写入 rdx 指向的数组?
迈克尔,感谢您的回复。我误解了最小的意思只是有问题的代码行。我对 Stack Overflow 还很陌生,但现在我知道要发布多少代码了。这是完整的 Python 代码和完整的 NASM 代码。 Python 是 3.6.2。 NASM 是 64 位的。
Python 代码:
OutputArrayType = ctypes.c_int64 * 1000
arrNew = OutputArrayType()
PassArrayType = ctypes.c_int64 * 10
PVarrNew = PassArrayType()
PVarrNew[0] = id(PVarrNew)
PVarrNew[1] = 2
PVarrNew[2] = len(PVarrNew)
ThisDll = ctypes.WinDLL(r"C:/Temp2/Std_Math_Formulas.dll")
SimpleTest = ThisDll.SimpleTest
SimpleTest.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
SimpleTest.restype = ctypes.c_int64
retvar = SimpleTest(ctypes.byref(PVarrNew), ctypes.byref(arrNew))
NASM 代码:
; Header Section
[BITS 64]
export SimpleTest
section .data
tempvar: dq 0
section .text
finit
SimpleTest:
push rdi
push rbp
mov rdi,rcx
mov rbp,rdx
push qword [rcx+32]
pop qword [tempvar]
; this works with rcx, but not rdx
mov rdi,rcx
push qword [rdi+32]
pop qword [tempvar]
; this works with rcx, but not rdx
mov rax,1235
push rax
pop qword [rcx+32]
mov rax,[tempvar]
pop rbp
pop rdi
ret
我将我的 DLL 组装并链接到:
nasm -Z myfile.err -f Win64 C:\Temp2\Std_Math_Formulas.asm -l myfile.lst -F cv8 -g -o C:\Temp2\Std_Math_Formulas.obj
GoLink Std_Math_Formulas.obj /dll /entry SimpleTest msvcrt.dll
【问题讨论】:
-
迈克尔,感谢您的回复。我在上面的原始问题下方添加了两组代码(Python 和 NASM)。
-
对编译器使用 NASM,对链接器使用 GoLink:编译:nasm -Z myfile.err -f Win64 C:\Temp2\Std_Math_Formulas.asm -l myfile.lst -F cv8 -g -o C: \Temp2\Std_Math_Formulas.obj 链接:GoLink Std_Math_Formulas.obj /dll /entry SimpleTest msvcrt.dll
-
现在我们正在取得进展。 /entry 是为 DLL 初始化而存在的 special entry point。它是一个特殊的函数,有自己的参数。通过指定 /entry SimpleTest,您可以告诉 Windows 让 Windows 通过调用该函数来初始化 DLL。这可能会导致严重的问题。删除
/entry SimpleTest,这样就没有DLL 入口点。因为你还没有使用 C 运行时,所以你也不需要msvcrt.dll。试试GoLink Std_Math_Formulas.obj /dll -
我很好奇。您在此处显示的代码。 正是您使用的是什么。或者你正在组装不同的代码?您是否尝试过使用您在问题中发布的确切代码(无需更改)?我有一个标准的 Python 3.6.4 安装、NASM 和 GOLINK,除了必须在你展示的 python 代码中添加一行
import ctypes之外它可以工作如果/entry被省略.如果我将 RCX 更改为 RDX,它也可以工作。在那种情况下,arrNew[4]返回后的值为 1235(返回值为 0,但这是因为数组中以 0 开头) -
Michael,你是对的——它是 GoLink 命令。我刚刚在下面发布了这个解决方案作为答案。
标签: python assembly dll nasm ctypes