方法调用的原理(栈,汇编)
个人总结:其实就是先备份原来栈指针,然后将原返回地址入栈顶,然后用栈帧指针指向原栈指针,使用这个帧栈,比如pop.push等操作,然后恢复被调用者寄存器的值,然后释放这个帧栈,然后恢复调用者栈帧,这里执行的是leave指令,最后使用ret指令弹出栈顶的地址继续按照EIP指针执行
- 机器用栈来传递过程参数、存储返回信息、保存寄存器用于以后恢复,以及本地存储。而为单个过程分配的那部分栈称为帧栈;帧栈可以认为是程序栈的一段,它有两个端点,一个标识起始地址,一个标识着结束地址,两个指针结束地址指针esp,开始地址指针ebp;
- 由一系列栈帧构成,这些栈帧对应一个过程,而且每一个栈指针+4的位置存储函数返回地址;每一个栈帧都建立在调用者的下方,当被调用者执行完毕时,这一段栈帧会被释放。由于栈帧是向地址递减的方向延伸,因此如果我们将栈指针减去一定的值,就相当于给栈帧分配了一定空间的内存。如果将栈指针加上一定的值,也就是向上移动,那么就相当于压缩了栈帧的长度,也就是说内存被释放了。
过程实现
1.备份原来的帧指针,调整当前的栈帧指针到栈指针位置;
2.建立起来的栈帧就是为被调用者准备的,当被调用者使用栈帧时,需要给临时变量分配预留内存;
3.使用建立好的栈帧,比如读取和写入,一般使用mov,push以及pop指令等等。
4. 恢复被调用者寄存器当中的值,这一过程其实是从栈帧中将备份的值再恢复到寄存器,不过此时这些值可能已经不在栈顶了
5.释放被调用者的栈帧,释放就意味着将栈指针加大,而具体的做法一般是直接将栈指针指向帧指针,因此会采用类似下面的汇编代码处理。
6.恢复调用者的栈帧,恢复其实就是调整栈帧两端,使得当前栈帧的区域又回到了原始的位置。
7.弹出返回地址,跳出当前过程,继续执行调用者的代码。
过程调用和返回指令
① call指令 CALL指令的步骤:首先是将返回地址(也就是call指令要执行时EIP的值)压入栈顶,然后是将程序跳转到当前调用的方法的起始地址。执行push和jump指令。
② leave指令 LEAVE指令是将栈指针指向帧指针,然后POP备份的原帧指针到%EBP。
③ ret指令 RET指令则是将栈顶的返回地址弹出到EIP,然后按照EIP此时指示的指令地址继续执行程序。
指令内容转载博客
(EIP寄存器,用来存储CPU要读取指令的地址,CPU通过EIP寄存器读取即将要执行的指令。每次CPU执行完相应的汇编指令之后,EIP寄存器的值就会增加。)