c语言代码和汇编后的汇编代码分别如下图所示:
在main函数中返回值f(2)+1,所以首先调用f(2)函数,在调用f(2)函数之前要先保存main函数目前的状态,栈基址指针,栈指针 之间的内容是main函数运行存放在栈中的内容,保护这两个寄存器之间的内容可以保证返回main函数后可以使栈中的内容不被破坏。
pushl %ebp ,movl %esp,%ebp ,subl $4,%esp
以上两条指令将ebp压栈,将esp作为新的ebp,通过subl $4,%esp 将esp地址下移以为,在ebp之上重新构造一个新函数的栈空间,esp指向新的栈顶。
movl $2,(%esp) , call f
将f函数的参数2放入esp所指向的地址空间,传入f函数中,跳转到f中。
f:
pushl %ebp movl %esp ,%ebp subl $4,%esp movl 8(%ebp),%eax movl %eax,(%esp) call g
进入f函数后,由于要调用g函数,所以和在main函数中调用f函数相同,将ebp压栈,esp作为新的栈低,重新构造一个堆栈,先将main函数中调用f函数传送的参数取出送往eax中,然后将要传入g函数的参数传入(%esp) 中,然后跳转到新的函数g中。
g:
pushl %ebp movl %esp,%ebp movl 8(%ebp),%eax addl $2,%eax popl %ebp ret
如前函数构造一个新的堆栈,将调用g函数传送的参数取出送往eax中,完成函数调用后,还是将传回的参数放在eax中,退出的在g函数所创建的堆栈,将之前压入栈中的上一个堆栈的ebp弹出,恢复上一个堆栈,返回到上一层函数。
f:
leave ret
在f函数中无函数运行,传回的参数仍然在eax中,保持不动,恢复上一级main函数的堆栈,返回上一级函数main()。
main:
addl $1,%eax leave ret
沿着被调用后的函数后运行,返回的参数仍然存放在eax中,运行完main函数中代码后,将所建立的堆栈退回之前的状态。