Linux 汇编-NASM阶乘问题
您好,我正在使用NASM编写汇编中的阶乘函数。我的作业必须用俄语乘法代替mul。我使用的是32位linux 这是我的阶乘代码Linux 汇编-NASM阶乘问题,linux,assembly,x86,nasm,Linux,Assembly,X86,Nasm,您好,我正在使用NASM编写汇编中的阶乘函数。我的作业必须用俄语乘法代替mul。我使用的是32位linux 这是我的阶乘代码 section .text global factorial extern rpmult factorial: push ebp mov ebp, esp sub esp, 4 ;creates memory for local variable at ebp-4 mov esi, [ebp+8] ; put
section .text
global factorial
extern rpmult
factorial:
push ebp
mov ebp, esp
sub esp, 4 ;creates memory for local variable at ebp-4
mov esi, [ebp+8] ; put n in esi
cmp esi, 1 ; n <= 1
jbe .done ; if so jump to done
.try:
mov [ebp-4],esi ;adds n temporarily into ebp-4
dec esi ; n - 1
push esi ; push arugment
call factorial ;call factorial again stores result in esi
add esp, 4 ;gets rid of the argument
mov edi, esi ;copies n - 1 into edi
mov esi,[ebp+4] ;gets the original value back (n)
call rpmult ;multiply
jmp .done ;once it reaches here, finished the function
.done:
mov esp, ebp ;restores esp
pop ebp
ret ;return the value
我相信我的代码是正确的,但我不知道该怎么做。我需要让阶乘函数与rpmult函数一起工作,以获得最终结果。感谢您的帮助!
谢谢 (注意:在我清醒的时候再看一遍,并阅读了@lloydm的评论之后,我重写了这个答案。)
有三个问题领域:
1) 递归的基本情况
调试递归函数时,首先检查基本情况总是明智的
那么,当计算1时会发生什么呢代码>
factorial:
push ebp
mov ebp, esp
sub esp, 4 ;creates memory for local variable at ebp-4
mov esi, [ebp+8] ; put n in esi
cmp esi, 1 ; n <= 1
jbe .done ; if so jump to done
...
.done:
mov esp, ebp ;restores esp
pop ebp
ret ;return the value
edi
与esi
一样,是一个需要保留的寄存器,如上所述
行movedi,esi;将n-1复制到edi中是错误的。您不想将n-1
放入edi
-您正在尝试计算(n-1)*n
在这里,所以您要放置(n-1)
转换为edi
,即通过递归调用计算的答案。正如@lloydm指出的,它在eax
中返回。(我被我最初回答中的评论误导了,认为你真的想把n-1
放入edi
。这也行不通,因为esi
在调用阶乘后不再包含n-1
,因为你没有遵循调用约定。)
moviesi[ebp+4];返回原始值(n)
错误(正如我最初指出的)<代码>[ebp+4]
包含返回地址;这应该是[ebp-4]
3) 异常大的价值
4!=13803416593125867520
是一个比最初看起来更奇怪的答案:它对于32位值来说太大了。(十六进制:0xbf8f964200000000
,因此它是一个64位值,顶部32位有一个大数字,底部32位为零。)
考虑到其他bug,您可能希望得到一个完全随机的值作为答案,但是factorial
返回一个32位的随机值。那么,为什么要在这里打印64位值呢?(如果你不是故意这么做的,我想这可能与C代码做了一些奇怪的事情有关,因为你的代码没有保留esi
和edi
)
调试提示
不要一开始就试图找出
factorial(5)
不起作用的原因。尽可能简单地开始,使用factorial(1)
。然后逐步进行分解(2),等等。在GDB;下逐步完成程序)我已经尝试在ebp中将偏移量从4更改为8。在rpmult中,您在eax中返回值,而在factorial中,您在esi中期望它。在调用factorial后,将其返回eax并复制到edi。是的,我的意思是[edp-4]。好的,我会尝试使用调试器,看看它能帮我什么忙。我以前从未用过,我很可能会回来。感谢到目前为止的回复。从调试程序中我可以看出,esi和edi从未达到过这样的数字:13803416593125867520,但我不确定程序为什么返回这么高的数字。我试着用参数5调试程序,esi或edi达到的最高值是1280。但它不应该涨得那么高,是吗?5的阶乘是120。我甚至不知道我的调试是否正确:)
4! = 13803416593125867520
factorial:
push ebp
mov ebp, esp
sub esp, 4 ;creates memory for local variable at ebp-4
mov esi, [ebp+8] ; put n in esi
cmp esi, 1 ; n <= 1
jbe .done ; if so jump to done
...
.done:
mov esp, ebp ;restores esp
pop ebp
ret ;return the value
...
.try:
mov [ebp-4],esi ;adds n temporarily into ebp-4
dec esi ; n - 1
push esi ; push arugment
call factorial ;call factorial again stores result in esi
add esp, 4 ;gets rid of the argument
mov edi, esi ;copies n - 1 into edi
mov esi,[ebp+4] ;gets the original value back (n)
call rpmult ;multiply
jmp .done ;once it reaches here, finished the function
...