您的位置:首页 > 运维架构

汇编指令push,mov,call,pop,leave,ret建立与释放栈的过程

2017-05-28 18:41 281 查看
相比高级语言中的栈结构,在汇编指令层面栈的任务更加复杂—生命周期必须与汇编指令行的切换正确对应。



大图

图片说明:内存地址,汇编指令都为简写,用的十进制,栈空间1个格子大小是4*8=32位(对应32位操作系统),指令行长度都简化为1字节。为了突出建栈与撤栈的过程示意,函数都没有参数。栈空间也简化了,局部变量和参数都没有在其中。 实际执行顺序一列中对汇编指令行作用的进一步解释,左边为寄存器或栈空间地址,右边为其中的值。

寄存器%esp既是栈指针,总是指向最下方第一个空着的栈空间地址。当栈栈指针向上移动后,下方的栈空间就相当于被释放掉了。

%ebp寄存器在此机制中相当重要,它存储着当前函数在栈中所被分配的局部空间的起始地址。在释放栈的过程中,leave指令将会移动栈指针至%ebp存储的内存地址的位置,再反过来将此起始位置中存储的值,既上一层调用函数的起始地址,存到%ebp中,为下一次进一步释放做准备,并进一步向上移动栈指针,为ret命令做准备。在此机制中,当前函数在栈中所被分配的局部空间的起始地址的前一格内存(既是+32bit)中存储的是上一层调用函数指令call的下一行指令的内存位置,leave之后的ret指令将会控制指令行流水线跳到此处。

一些指令的简单说明:

push为入栈命令。

pop为出栈命令。

栈命令都跟伴随栈指针的移动。

mov在此过程中将一个寄存器中的值移到另一个寄存器。

call可以理解为goto。并将它的下一行指令地址存到栈中。

leave为mov+pop。为退出栈机制的重要一环。

ret也可以理解为goto。并移动栈指针。

汇编指令行对应的源码应为:

void main(){
//一些计算
f1();
//继续计算
}
void f1(){
//一些计算
f2();
//继续计算
return;
}
void f2(){
//一些计算
return;
}


感觉这东西有点烧脑,花了一下午时间终于整个捋顺了整个流程。

想理解好此过程,理解每个指令的作用,必须结合指令行地址,栈地址和寄存器一起来分析,否则很容易被绕晕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  汇编 内存