函数调用中esp ebp寄存器的变化

ebp(extended base pointer)寄存器存放当前栈帧的栈底,一般在函数内不会对ebp寄存器做变动
esp(extended stack pointer)寄存器存放当前栈帧的栈顶,会随着当前函数内栈空间的开辟而变动
首先我们要明确,push pop就是对esp的操作。
因为栈是从高地址向低地址出增长的,所以push是对esp进行减法,然后将操作数写到上述寄存器里的指针所指向的内存中。
pop是对esp进行加法:它先从栈指针指向的内存中读取数据,用以备用(通常是写到其他寄存器里),然后再将栈指针的数值加上4或8.

比如push %eax前esp=0x115fc68 那么push后esp=0x115fc64:原来的值减去4

void test(){
	int a = 0;
}
int main(){
	int a = 0;
	test();
}

在上面这段代码的执行中,ebp esp的变动是这样的
首先进入main函数后,push %ebp,保存上一个函数即_start函数的栈底。
此时esp就指向保存ebp的栈顶。如图
在这里插入图片描述
然后将esp赋值给ebp做为当前函数新的栈底.此时ebp和esp指向同一个地址
此时执行int a=0; 那么将esp减去4,同时将0赋值给esp指向的地址。
如果调用test时有参数要传递,那么参数是保存在调用者,在这里是main函数的栈帧中的。返回地址也是保存在调用者main函数的栈帧中。压栈顺序是这样:先将最后一个参数入栈,然后倒数第二个,倒数第三个… 参数压栈完毕后将返回地址压栈。返回地址也指示了main函数栈帧的结束处。(见linux内核完全剖析0.12P55页)
进入test函数后,一样的,要压入ebp,将esp赋值给ebp,而且分配内存给a。
执行完后,内存布局如图
在这里插入图片描述
执行完test函数后,函数返回。恢复main函数的栈底和栈顶,即将esp 和ebp恢复。函数返回后内存布局如图
在这里插入图片描述
自然,在test函数内部的a被随后的执行所覆盖。
小结:
在做操作系统实验时,对其中ebp esp寄存器的处理十分疑惑,网上查资料后有了大概的框架。这里只是简单介绍了下函数调用中esp ebp的变化,对参数的压栈返回地址的压栈没有详细的介绍,其实,在被调用函数内使用参数时,是通过对ebp寄存器执行加法得到的,详细可见linux内核完全剖析0.12中对c和汇编相互调用的论述,图文并茂,写的十分精彩。
总之,函数调用是一个在当前内存开辟栈帧,然后在当前栈帧开辟空间,然后执行完当前函数后返回上一个栈帧,然后覆盖当前栈帧的一个重复过程。
这些在

参考:
linux内核完全剖析0.12
https://zhuanlan.zhihu.com/p/77663680

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值