Recursion x86_64汇编中的递归阶乘问题

Recursion x86_64汇编中的递归阶乘问题,recursion,assembly,x86-64,att,Recursion,Assembly,X86 64,Att,我不熟悉这种汇编语言,我试着自己编写以下代码。问题是,我的代码无法正确计算数字的阶乘,它总是在终端中显示1作为输出。我想知道它不起作用的原因 .text mystring1: .asciz "Assignment 4: recursion\nType any number to calculate the factorial of that number:\n" # string for printing message formatstr: .asciz "%ld"

我不熟悉这种汇编语言,我试着自己编写以下代码。问题是,我的代码无法正确计算数字的阶乘,它总是在终端中显示1作为输出。我想知道它不起作用的原因

.text

mystring1: .asciz "Assignment 4: recursion\nType any number to calculate the factorial of that number:\n"  # string for printing message
formatstr: .asciz "%ld"                   # format string for printing number
mystring2: .asciz "\n"                    # string for printing a new line

.global main  # make the main label visible  

main:

    pushq %rbp            # store the caller's base pointer
    movq %rsp, %rbp       # initialise the base pointer
    movq $0, %rax         # no vector registers in use for printf
    movq $mystring1, %rdi # load address of a string
    call printf           # call the printf subroutine
    call inout            # call the inout subroutine
    movq $0, %rax         # no vector registers in use for printf
    movq $mystring2, %rdi # load address of a string
    call printf
    jmp end

inout:

    pushq %rbp                  # push the base pointer
    movq %rsp, %rbp             # copy the stack pointer to rbp
    subq $16, %rsp              # reserve stack space for variable
    leaq -8(%rbp), %rsi         # load address of stack variable in rsi
    movq $formatstr, %rdi       # load first argument of scanf
    movq $0, %rax               # no vector registers in use for scanf
    call scanf                  # call scanf routine
    movq -8(%rbp), %rsi         # move the address of the variable to rsi
    call factorial
    movq $0, %rax               # no vector registers in use for printf
    movq $formatstr, %rdi       # move the address formatstring to rdi
    call printf                 # print the result
    movq %rbp, %rsp             # copy rbp to rsp
    popq %rbp                   # pop rbp from the stack
    ret                         # return from the subroutine

factorial:

    cmpq $1, %rsi
    jle factend
    pushq %rbx
    movq %rsi, %rbx
    subq $1, %rsi
    call factorial
    mulq %rbx
    popq %rbx
    ret

factend:

    movq $1, %rax
    ret

end:
    mov $0, %rdi # load program exit code
    call exit    # exit the program
我的代码的伪代码:

long rfact(long n)
{
     long result;
     if (n < = 1)
     {
        result = 1;
     }
     else
     {
        result = n * rfact(n - 1);
        return result;
     }
}
long-rfact(长n)
{
长期结果;
如果(n<=1)
{
结果=1;
}
其他的
{
结果=n*rfact(n-1);
返回结果;
}
}

您在
rax
中返回阶乘结果,但调用者假设它在
rsi
中。调用方应该在调用
factorial
返回后立即将结果从
rax
移动到需要它的地方(
rsi
)。使用更高效的2操作数
imul%rbx,%rax
。顺便说一句,x86-64 System V调用约定传递RDI中的第一个整数/指针arg。你已经在为args-to-printf和scanf做这些了,所以你选择RSI作为你自己的函数是很奇怪的。坦率地说,我还有很多东西要学,我只是随机使用了RSI,但感谢你提供的信息是的,这就是为什么我要教你:好吧,既然你问了,哦,如果你关心效率的话,那么很多事情。xor归零、RIP相对LEA(谷歌搜索或搜索),以及
mov$1,%eax
zero隐式扩展到RAX;不需要在64位操作数大小上浪费代码大小。(地址也一样;如果您正在优化位置相关的Linux可执行文件,当您不需要RIP相对LEA将静态地址放入寄存器时,请使用
mov$formatstr,%edi
,而不是
%rdi
movq$sign\u extended\u 32位\u immediate,%rdi
占用更多空间,而GAS不会进行此优化。)n,即使对于数值常量也是如此。)但就正确性和良好风格而言,您在这里做得相当好。e、 g.在调用程序中使用堆栈空间作为scanf暂存空间。跨
factorial
保存/恢复RBX并使用它保存局部变量是编译器要做的事情。哦,把你的字符串文字放在
.section.rodata
中,把代码放在
.text
中。如果您感到好奇,请将您的C放入并查看它是如何使用
-O1
-O2
编译的。。。现在我很好奇:这表明GCC-O1与您所做的非常接近。clang-O1仍然优化了循环中的简单递归。