汇编中esp和ebp在函数栈空间的保存和变化 call的参数和局部变量的关系详解

esp

call执行跳入子程序以后栈顶寄存器,一直指向栈顶

ebp

call执行过跳入子程序以后,一直指向栈底

看下面例子模拟一个有2个参数的函数.例如函数参数1是1, 参数2是2

push 2 //参数2
push 1 //参数1
call 子程序地址

在这里插入图片描述

//子程序开始以后的栈的内容操作如下图红框出是call的下一条语句的地址,这个地址会被首先压入栈顶,如下图
在这里插入图片描述
压入栈顶之后如下图
在这里插入图片描述

上面图栈顶显示是:"返回到"这个就是外面call的下一条语句的地址 ,这样当子程序结束的时候可以通过retn语句的时候 找到call下面的语句,.因为retn语句,等于pop eip,然后cpu就会执行eip里的语句

上一层ebp和本层ebp的保存方法

首先要明白为什么要保存上一层ebp
ebp是用来保存本层call的栈底位置的寄存器,每次进入call之后,会保存本层call子程序的栈底,加入不保存上一层的ebp,那么本层call执行结束以后。ebp因为保存了本层的栈底,就改变了,上一层的栈底在进入本层call之前是被保存到ebp里面的,但是结束本层靠以后就被改变了,那么回到上一层,通过ebp就找不到栈底了。所以上一层call的ebp必须在本层靠进来的时候就保存,保存方法就是在一进来call就push ebp, 当在返回之前的上一句,再pop ebp,这样上一层的ebp就被保存下来了,在call 内的子程序一般如下格式保存ebp .注意下图中的mov ebp, esp,是保存本层的栈底。因为一进来本层的call,压入之前ebp以后,栈顶往上移动一个元素,esp - 4,然后现在开始的栈顶被认为也是栈底。

push ebp //子程序外侧的ebp入栈,目的是保存外面的ebp,因为外面也有call,外层的call的栈底保存在ebp里面,出站
mov ebp,esp //因为此时的esp是栈顶,同时也是栈底,所以用ebp栈底寄存器保存栈底 
一直到遇到retnebp都不会变化,因为ebp就是用来保存本层call的栈底的

pop ebp 
retn 

保存本层和上一层ebp的过程在 od中的截图如下:
在这里插入图片描述
下图是retn时候,还原上一层ebp的执行结果截图:pop ebp以后,就把最开始进来就保存的上一层ebp还原了
在这里插入图片描述

call 函数的参数在栈中的位置

看下面图是cpu执行到call里面,然后执行完push ebp mov ebp,esp之后栈里面的情况

在这里插入图片描述
以内给本层ebp复制以后,ebp在本层不在改变,所以,call的参数位置也是固定的,位置如下:
ebp+4是返回到
ebp+8是参数1
ebp+c 是参数2
ebp +10 参数3
总结是 ebp+ 8是第一个参数,之后每次+4,按照十六进制表示
子程序里面的push是局部变量,如下图的2处push esi
在这里插入图片描述

下面图是 在栈空间通过sub esp改变了栈顶以后再分配局部变量,下面图让 sub esp 28,栈顶向上移动28再往栈顶push局部变量
在这里插入图片描述

总结函数参数和局部变量

esp在子程序头部

  • esp + 4, + 8 + c都是 函数参数,是在call外push进栈的.
  • esp - 4, - 8 等,只要是减的,可能是局部变量,不是局部变量的情况是,在申请局部变量之前,执行了push操作,让esp减少了.或者执行了 sub esp ,4等 操作,让esp减少了.

od中查看 栈空间的返回到子程序的情况

  • 在返回到子程序的上面,就是局部变量
  • 在返回到子程序的下面,是call外传进来的参数
    如下图:
    在这里插入图片描述
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值