64位NASM DLL通过ctypes调用返回值触发访问违例问题求助
解决64位NASM DLL通过ctypes调用时的访问违例问题
你的问题核心是NASM编写的DLL函数存在关键指令缺失和代码位置错误,导致CPU执行流混乱,触发访问违例。下面是具体的修复方案和原因分析:
核心问题拆解
- 缺少函数返回指令
ret:你的lcm函数执行完寄存器操作后没有ret指令,CPU会继续执行内存中后续的随机代码,最终试图写入非法内存地址——这就是你看到access violation writing错误的根本原因,不管怎么设置rax的返回值,没有ret就无法正确回到Python调用点。 finit指令位置错误:finit是初始化浮点运算单元的指令,你把它放在了section .text的全局区域(函数外部),这会在DLL加载时就执行,不仅完全没必要(你的函数没用到浮点操作),还可能引发未知的初始化问题。- 冗余的内存访问(可选优化):你通过
.data段的return_val变量赋值rax,其实可以直接用mov rax, 2346完成返回值设置,不需要额外的内存读写。
修复后的NASM代码
[BITS 64] export lcm section .text lcm: ; Windows x64调用约定中,rdi是非易失性寄存器,需要保存(你已经做了这一步) push rdi push rbp ; 直接设置返回值到rax(64位Windows下返回值存在rax中) mov rax, 2346 ; 恢复保存的寄存器 pop rbp pop rdi ; 关键:函数返回指令,回到调用者 ret
优化后的Python代码
你的Python代码基本没问题,加上错误捕获会更健壮:
import ctypes def lcm_ctypes(): input_value = ctypes.c_int64(235) try: hDLL = ctypes.WinDLL(r"C:/NASM_Test_Projects/While_Loop_01/While_loops-01.dll") CallTest = hDLL.lcm CallTest.argtypes = [ctypes.c_int64] CallTest.restype = ctypes.c_int64 retvar = CallTest(input_value) print(f"返回值:{retvar}") return retvar except Exception as e: print(f"调用出错:{e}") if __name__ == "__main__": lcm_ctypes()
补充:Windows x64调用约定要点
- 64位Windows下只有一种调用约定:前4个整数参数依次放在
rcx、rdx、r8、r9中,你的函数只有一个参数,会被传入rcx,如果需要使用这个参数,可以直接读取rcx的值。 - 非易失性寄存器(
rbp、rbx、rdi、rsi、r12-r15)需要在函数中保存并恢复,你已经正确保存了rdi和rbp,这部分没问题。 - 返回值如果是64位整数,必须放在
rax寄存器中,修复后的代码已经满足这个要求。
内容的提问来源于stack exchange,提问作者RTC222
相关产品推荐
相关产品推荐

