我正在尝试编写从用户获取输入并在程序集x64中显示阶乘的代码。每次运行代码时,它都会在finalProjectAssembly.exe中给出0x00007FF64B910B11处的未处理异常:0xC00000FD:堆栈溢出(参数:0x0000000000000001,0x00000019F1603FF8)。但我不明白堆栈是如何溢出的。我错过了什么?
INCLUDELIB libcmt.lib
INCLUDELIB legacy_stdio_definitions.lib
EXTERN printf:PROC
EXTERN scanf:PROC
.DATA
prompt BYTE "Enter a number: ", 0
inFmt BYTE "%d", 0
prompt3 BYTE "The factorial is: %d",10,0
cont QWORD ?
disp BYTE "You Entered %d", 10,0
num QWORD ?
num2 REAL8 1.5
.CODE
main PROC C
sub rsp, 24
lea rcx, prompt
call printf
lea rdx, num
lea rcx, inFmt
call scanf
push num
mov rdx,num
lea rcx, disp
call printf
call factorial
mov rdx, rax
lea rcx, prompt3
call printf
lea rcx, prompt2
call printf
lea rdx, cont
lea rcx, inFmt
call scanf
add rsp,24
mov rax,0
ret
main ENDP
factorial PROC
push rbp
mov rbp,rsp
mov rax, [rbp + 16]
cmp rax, 1
jle quit
dec rax
push rax
call factorial
mov rbx, [rbp+16]
imul rbx
quit:
mov rsp, rbp
pop rbp
ret
factorial ENDP
答案 0 :(得分:0)
如果您拨打外国函数(printf
,scanf
),必须遵守其调用约定。适当的Microsoft x64 software convention确定在调用函数之前必须在堆栈空间中保留堆栈中的四个qwords(= 32字节)。该功能可以自由使用“阴影空间”。此外,ESP必须与可被16整除的地址对齐。
更改
sub rsp, 24
到
sub rsp, 32
and spl, -16 ; Align to 16
add rsp,24
函数末尾不需要main
。正确的序言(push rbp; mov rsp, rbp
)和正确的结尾(leave
)将由汇编程序ML64自动插入。
阴影空间必须在call
指令推送的函数返回地址前面笔直。将push num
移近call factorial
,不要忘记清理堆栈:
push num
call factorial
add rsp, 8
不要忘记清理堆栈:
push rax
call factorial
add rsp, 8
我没有按照David Wohlferd的建议检查格式说明符%d
。该程序基本上适用于上述变化。