linux - 了解 NASM 程序集中的递归阶乘函数

标签 linux assembly recursion nasm 32-bit

在 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 .我怀疑可能是因为 EAX0 , MUL总是会导致 0 ,对此进行解释。为了测试,我决定给出 EAX 2 的值,期待一些非零值,但它一直导致 0 .

你能建议我如何做一个从堆栈中获取参数的递归阶乘函数吗?我相信已经看过一些示例,但是它们要么不是递归的,要么从其他地方获取参数,或者使用了一堆变量(当我认为只用寄存器就可以完成时)。

最佳答案

请注意,factorial(n-1) 将首先覆盖 EBXfactorial(n) 值,因此在 push 之后呈现 inc EBX 毫无意义。达到基本情况后,当您执行 mul 时,您会遇到 EBX 为 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

关于linux - 了解 NASM 程序集中的递归阶乘函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19217960/

相关文章:

c - socket编程中如何正确拒绝客户端连接?

assembly - 使用 x86 汇编计算 x*log_2(y)

c++ - 如何告诉 Inline ASM 变量是十六进制的

swift - Swift 中泛型的递归枚举

php - 查询中的递归求和

linux - 有没有办法将 kptr_restrict 设置为 0?

c - "sendmsg"是否释放缓冲区或消息的内存?

使用 Fetch 和分页的 Javascript,递归?

linux - 如何成为一名Linux设备驱动程序程序员?

assembly - PIC 汇编中的整数常量 : decimal vs.(十六进制)