x64汇编参数传递异常:为何参数通过RDI/R10/R11而非栈传递?
问题分析与解决
首先明确:Windows x64平台下只有一种官方调用约定(Microsoft x64 Calling Convention),不存在前4个参数用寄存器、剩余参数用RDI/R10/R11传递的规则。你遇到的问题是汇编代码的栈帧处理和参数偏移计算错误导致的,而非调用约定变更。
核心规则回顾(Windows x64调用约定)
对于整型/指针类型参数:
- 前4个参数依次通过
RCX(第1个)、RDX(第2个)、R8(第3个)、R9(第4个)寄存器传递 - 第5个及以后的参数,由调用者压入栈中,被调用者通过栈帧指针(
RBP)的正偏移访问 - 调用者会为前4个寄存器参数分配32字节的阴影空间(Shadow Space),位于栈上返回地址的下方
你的汇编代码错误点
栈帧初始化错误
你用sub rbp, 16分配局部变量空间是错误的。正确的做法是在mov rbp, rsp之后,通过sub rsp, 16来分配局部变量(栈向下增长,需要将栈指针下移)。sub rbp,16会破坏栈帧的偏移计算逻辑,导致后续无法正确定位栈上的参数。参数偏移计算错误
进入函数后,栈帧相对于RBP的布局(十进制偏移):rbp+0:保存的旧RBPrbp+8:返回地址rbp+16~rbp+47:32字节阴影空间rbp+48:第5个参数(resY)rbp+56:第6个参数(alignment)rbp+64:第7个参数(iterCount)
你写的[rbp+50o]是八进制的40,对应阴影空间的位置,并非参数所在的栈地址,读取到的是无效数据。
修正后的汇编代码示例
.code generateMandelMASM PROC ; 标准栈帧序言 push rbp mov rbp, rsp ; 分配局部变量空间:2个变量(DWORD+QWORD)共12字节,对齐到16字节,所以sub rsp,16 sub rsp, 16 ; 读取参数示例 ; 参数1: RCX → bmp数组指针 ; 参数2: EDX → rowCount ; 参数3: R8D → rowNum ; 参数4: R9D → resX mov eax, dword ptr [rbp+48] ; 读取第5个参数resY mov ecx, dword ptr [rbp+56] ; 读取第6个参数alignment mov edx, dword ptr [rbp+64] ; 读取第7个参数iterCount ; 保存到局部变量 mov dword ptr [rbp-4], ecx ; alignment(DWORD,占rbp-4到rbp-1) mov qword ptr [rbp-16], rdx ; rowCount(QWORD,占rbp-16到rbp-9) ; 你的曼德博集合生成逻辑... ; 栈帧尾声 mov rsp, rbp pop rbp ret generateMandelMASM ENDP
额外说明
- C#的
DllImport在Windows x64下默认使用的就是官方调用约定,显式指定调用约定不会改变参数传递规则(x64平台不区分StdCall/Cdecl)。 - 你调试时看到
RDI/R10/R11中有参数值,是巧合或者调试环境的临时数据,并非调用约定的一部分。
内容的提问来源于stack exchange,提问作者mc jazda
相关产品推荐
相关产品推荐

