Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 汇编-NASM阶乘问题_Linux_Assembly_X86_Nasm - Fatal编程技术网

Linux 汇编-NASM阶乘问题

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

您好,我正在使用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 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
    ...