栈结构
注意,ebp到esp位置的是如今栈针,而上方是父栈帧的内容。该图是32的栈帧,紧邻栈帧的stack frame pointer是上一个栈帧的栈顶,记录栈底指针的值,方便可以回去调用。variables是存储局部变量的区域。子栈帧的参数是保存在父栈帧的arguments区域。
esp用于存储栈顶位置,在push和pop时产生变化。ebp用于存储基地址,可以用来索引确定函数参数或者局部变量的位置。eip是用于存储即将执行的程序指令的地址。
如右图蓝色所示,caller是父栈帧,callee是当前栈帧,callee的参数被存储在caller的argument区域,父栈帧在被调用参数时,将参数倒序压入栈中,先将arg1压入栈顶。最后会将父函数地址的返回值压入栈中。
int sum(int x,int y){
return x+y;
}
int main(){
sum(1,2);
return 0;
}
拿以上的代码作为例子,main是父函数,会将两个参数1,2压入自己的arguments区域。且在调用了sum函数后还要回到主函数,所有如右图所示,还需要将基地址压入栈。
同时ebp现在指向的位置存储的是该栈帧的基地址,在pop ebp时,ebp存储的内容就是基地址,该栈帧的指针会移到该栈的初始位置。在pop之后,栈顶esp也要发生改变,减少一个字节。
注意call指令和jump指令不同,call指令会将下一条命令即23命令存入return address的位置,再调用到callee函数中。而jump直接跳转,不存储地址。
关注callee函数和caller函数的不同,caller函数直接leave,而callee函数需要将ebp的位置返回到父栈帧中去。
标签:存储,函数,压入,父栈,ebp,callee,结构 From: https://www.cnblogs.com/carol-YeXiao/p/17752234.html