【发布时间】: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。我怀疑可能因为EAX 是0,MUL 总是会导致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