MASM x64编写BMI计算器时printf_s与pow调用触发访问违规
问题分析与修复方案
你的MASM x64代码出现访问违规的核心原因是未遵守x64调用约定,包括栈对齐、参数传递规则,同时存在计算逻辑错误,以下是具体修复:
核心错误点
栈对齐与Shadow Space未正确分配
x64 Microsoft调用约定要求:- 调用任何C函数前,RSP必须是16字节对齐
- 必须为被调用函数分配32字节的shadow space(用于保存前4个寄存器参数)
进入main时,RSP因返回地址压栈处于RSP%16=8的状态,你之前用sub rsp,100h未补充8字节对齐空间,导致RSP未对齐,触发访问违规。
printf_s参数传递错误
- 对于
%lf格式的double参数,必须放入XMM寄存器(第一个浮点参数放XMM0),而非通用寄存器(RDX),你之前的movq rdx, xmm1完全不符合可变参数函数的浮点参数传递规则。 - 调用printf_s这类可变参数函数时,必须在RAX中声明通过XMM寄存器传递的浮点参数数量,否则函数无法正确解析参数,引发内存错误。
- 对于
BMI计算逻辑倒置
原代码中divsd xmm0, xmm1执行的是height² / mass,而正确的BMI公式是mass / height²,操作数顺序完全颠倒。
修复后的完整代码
includelib legacy_stdio_definitions.lib extern printf_s:proc extern scanf_s:proc extern pow:proc .data height real8 1.73 mass real8 70.0 square real8 2.0 scanfGetDouble db "%lf", 0 printfPrintDouble db "%lf", 0 promptHeight db "Enter height (m): ", 0 promptMass db "Enter mass (kg): ", 0 resultBMI db "BMI: %lf", 0ah, 0dh, 0 ; 添加换行提升可读性 .code main proc ; 分配32字节shadow space + 8字节对齐,总计40字节(28h),保证RSP16字节对齐 sub rsp, 28h ; 提示输入身高 lea rcx, promptHeight xor rax, rax ; 无浮点参数,RAX设为0 call printf_s ; 读取身高 lea rcx, scanfGetDouble lea rdx, height xor rax, rax call scanf_s ; 提示输入体重 lea rcx, promptMass xor rax, rax call printf_s ; 读取体重 lea rcx, scanfGetDouble lea rdx, mass xor rax, rax call scanf_s ; 打印身高 lea rcx, printfPrintDouble movsd xmm0, height ; 将double值放入XMM0 mov rax, 1 ; 声明1个浮点参数在XMM寄存器 call printf_s ; 打印体重 lea rcx, printfPrintDouble movsd xmm0, mass mov rax, 1 call printf_s ; 计算height²:pow(height, 2.0) movsd xmm0, height ; pow的第一个参数(base)放入XMM0 movsd xmm1, square ; pow的第二个参数(exp)放入XMM1 call pow ; 返回值(height²)存于XMM0 ; 计算BMI = mass / height² movsd xmm1, xmm0 ; 暂存height²到XMM1 movsd xmm0, mass ; 将mass放入XMM0 divsd xmm0, xmm1 ; XMM0 = mass / height² ; 打印BMI结果 lea rcx, resultBMI mov rax, 1 call printf_s xor rax, rax ; 返回0表示程序正常结束 add rsp, 28h ret main endp end
测试说明
使用初始值height=1.73、mass=70.0时,计算结果为70/(1.73²)≈23.4,与预期一致。测试pow函数时,需保证sub rsp的取值为8 + 16*N(如28h),确保栈对齐,避免访问违规。
内容的提问来源于stack exchange,提问作者Forward-Fax3
相关产品推荐
相关产品推荐

