【问题标题】:Understanding recursive factorial function in NASM Assembly了解 NASM 装配中的递归阶乘函数
【发布时间】:2013-10-13 14:53:24
【问题描述】:

在 32 位 Ubuntu 上学习 NASM 汇编。我现在正在尝试学习递归函数,从阶乘开始(注意:这里我假设参数总是非负的)。

假设我有

push 3
call factorial

我想在EAX 中以6 结束。

这是我的尝试:

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。我怀疑可能因为EAX0MUL 总是会导致0,解释这一点。为了测试,我决定给EAX 一个值2,期望一些非零值,但它一直导致0

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

【问题讨论】:

  • 提示:用 C 语言编写函数,使用 gcc -Wall -O3 -m32 -S ... 编译,然后使用生成的编译器生成的 asm 源代码作为您自己函数的模板(或者甚至只是用于管理堆栈的一般指导,传递参数和函数结果等)。
  • @PaulR:谢谢你的建议。有人曾经告诉我一个将 C++ 翻译成汇编的网站 (assembly.ynh.io),你认为这对这个目的也有好处吗?
  • 由于您运行的是 Linux,因此您已经拥有了所需的所有工具(即 gcc),但是您永远不会拥有太多工具,如果该站点可以生成适合 NASM 的 Intel 格式的 asm,那么它可能在这种特殊情况下对您更有用。无论如何都尝试一下 - 这是学习东西的好方法。

标签: linux assembly recursion nasm 32-bit


【解决方案1】:

请注意,factorial(n-1) 将覆盖EBX 所做的第一件事的factorial(n)'s 值,从而使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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2017-03-17
    • 2015-04-16
    • 1970-01-01
    • 2014-04-13
    • 1970-01-01
    • 2018-05-16
    相关资源
    最近更新 更多