我是编程新手,我开始阅读一本关于它的书来理解基础知识。我无法理解以下汇编代码的工作原理:它计算数字的阶乘。我已经对我能理解的说明添加了评论 - 显然我错过了一些东西。
.section .data
.section .text
.globl _start
.globl factorial
_start:
pushl $4
call factorial
popl %ebx
movl %eax, %ebx
movl $1, %eax
int $0x80
factorial:
pushl %ebp # push the base pointer
movl %esp, %ebp # copy the stack pointer to the base pointer
movl 8(%ebp), %eax # move the value 4 to %eax
cmpl $1, %eax # compare it to 1
je end_factorial # jump to end_factorial if it's equal
decl %eax # else decrease the value by 1
pushl %eax # push the decreased value in the stack
call factorial # this means that it should start again (?)
popl %ebx # that's the part that i don't understand
incl %ebx # when are these lines excuted? since it
imul %ebx, %eax # keeps starting from the top, until the value
# of %eax is 1 then, it jumps to end_factorial
end_factorial:
movl %ebp, %esp
popl %ebp
ret`
答案 0 :(得分:0)
不要以文字方式评论,而是将评论放在上下文中。
不要写将值4移动到%eax ,而是找到含义:将 n 移动到eax 。
不要跟踪寄存器值,跟踪变量:否则将值减1 更好 eax = n - 1
如果您再次尝试评论该程序,则应该达到以下内容。
.section .data
.section .text
.globl _start
.globl factorial
_start:
pushl $4
call factorial # eax = 4!
popl %ebx # Remove the parameter from the stack
movl %eax, %ebx
movl $1, %eax
int $0x80 # sys_exit(4!)
factorial:
pushl %ebp
movl %esp, %ebp # Prolog
movl 8(%ebp), %eax # eax = n
cmpl $1, %eax # n == 1?
je end_factorial # If yes, since 1! = 1, just return
decl %eax # eax = n - 1
pushl %eax
call factorial # eax = (n - 1)!
popl %ebx # ebx = (n - 1)
incl %ebx # ebx = n
imul %ebx, %eax # eax = n * (n - 1)! = n!
end_factorial:
movl %ebp, %esp # Prolog
popl %ebp
ret
通过这些评论,功能正在运行 - 它是一个非常标准的,非尾递归,因子实现。
int fact(int n)
{
if (n == 1)
return 1;
return n * fact(n-1);
}
有关执行流程的问题,特别是在递归关闭后执行的代码,可以在使用铅笔和橡胶后回答。
最后,您将看到要查找的重要部分是终止条件(终止案例) - 它是不会跨越任何递归调用的输入。
在此示例中 n = 1 。
充分理解函数所需的另一个支柱是函数如何实际工作 - 每个调用都是一个唯一的实例,并且函数返回执行后,调用者继续使用调用者的状态 (恢复调用者调用) 从而创建已保存/恢复状态的(抽象)堆栈。
该实现的唯一特殊方面是用于清理函数参数堆栈的指令
如果上面的句子让你失望,我建议你阅读calling conventions
通常使用addl $4, %esp
,代码中使用popl %ebx
代替 - 虽然它在factorial
正文中有意义,因为在递归调用之后需要再次n
,使用在_start
函数中很奇怪。