Recursion x86_64汇编中的递归阶乘问题
我不熟悉这种汇编语言,我试着自己编写以下代码。问题是,我的代码无法正确计算数字的阶乘,它总是在终端中显示1作为输出。我想知道它不起作用的原因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"
.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仍然优化了循环中的简单递归。