在32位Ubuntu上学习NASM程序集。我现在正在尝试学习递归函数,从阶乘开始(注意:这里我假设参数总是非负的)。
假设我有
push 3
call factorial
我想在6
中结束EAX
。
这是我的尝试:
SECTION .text
global main
main:
; -----------------------------------------------------------
; Main
; -----------------------------------------------------------
push 3
call factorial
; -----------------------------------------------------------
; Exit
; -----------------------------------------------------------
mov EAX,1
int 0x80
; -----------------------------------------------------------
; Recursive Factorial: n! = n * (n - 1)!
; -----------------------------------------------------------
factorial:
push EBP ; Retrieve parameter and put it
mov EBP,ESP ; into EBX register
add EBP,8 ;
mov EBX,[EBP] ; EBX = Param
cmp EBX,0 ; Check for base case
je base ; It is base if (n == 0)
dec EBX ; Decrement EBX to put it in the stack
push EBX ; Put (EBX - 1) in stack
inc EBX ; Restore EBX
call factorial ; Calculate factorial for (EBX - 1)
mul EBX ; EAX = (EAX * EBX) = (EBX - 1)! * EBX
pop EBX ; Retrieve EBX from the stack
jmp end
base: ; Base case
mov EAX,1 ; The result would be 1
end:
pop EBP ; Release EBP
ret
至少它适用于基本情况,哈...但是对于我推动的任何其他值,它总是返回0
。我怀疑可能EAX
0
MUL
,0
总会产生EAX
,这解释了这一点。为了测试,我决定给2
一个0
的值,期望一些非零值,但它会导致{{1}}。
你能告诉我如何做一个从堆栈中获取参数的递归因子函数吗?我相信已经看过一些例子,但要么它们不是递归的,要么是从其他地方获取参数,或者它们使用了一堆变量(当我认为可以用寄存器完成时)。
答案 0 :(得分:3)
请注意factorial(n-1)
将覆盖factorial(n)'s
EBX
的第一件事,从而在inc EBX
无效后呈现push
。在您到达基本案例后,当您执行EBX
时,您将遇到mul
为0的情况,当然还有* 0 == 0。
最简单的解决方法是将序言更改为:
push EBP ; Retrieve parameter and put it
push EBX ; save previous param
mov EBP,ESP ; into EBX register
add EBP,12 ;
mov EBX,[EBP] ; EBX = Param
结语:
pop EBX ; restore previous param
pop EBP ; Release EBP
ret