引言
CPU执行指令依据
函数调用流程
![[100] [100]](/2018/04/19/探索函数调用得本质之旅/1.jpg)
如果函数内可能会使用到其他寄存器,特别是一些寄存器数量不是很多的平台,这里需要做保护处理,将要用的寄存器之前的值PUSH入栈;在真正实现本函数功能之前还有一个有关安全的操作需要处理,就是讲预留出来的局部变量空间统一填充指定的数据(这里使用CC填充,原因是CC有在系统层面代表着暂定,至少没有意外的危险),因为不确定这段栈段空间之前存过什么数据,可能会有风险。填充的方法就是利用寄存器ES配合着寄存器DI指定这段空间的地址,使用stosw命令反复执行;到此为止,准备工作算是基本完成了,接着就是实现函数功能体部分了,而这部分准备工作实际工作中往往由对应的编译器来完成。执行完业务逻辑代码后,沿着准备阶段相反的流程恢复栈段空间;POP出栈之前受保护的寄存器值;将BP的值赋值给SP来恢复“栈顶指针”SP预留空间之前的值;此时栈顶元素是BP之前存放进来的数值,需要POP出栈给BP寄存器;执行ret命令将函数的返回地址出栈,此时通过修改SP的值至栈底,方法就是增加SP的值(此数值就是之前PUSH进栈参数的字节数)达到恢复栈平衡。假若此函数中又调用了其他函数,从内存角度看的话是继续向内存地址减小的方向叠加数据,操作流程同以上过程,栈段剩余内存空间也会随之相应减少。所以程序如果出现死循环情况,栈段空间迟早会被耗完,所以在使用递归调用函数的时候一定要注意结束条件。
![[100] [100]](/2018/04/19/探索函数调用得本质之旅/2.png)
汇编语言描述函数调用流程
1 | push 参数 |
参考文献:
第二章 寄存器;第四章 第一个程序;第十章 CALL和RET指令


