对栈的一些理解

本文通过具体的示例分析了基于ESP和EBP的栈帧实现方式,并详细阐述了函数调用过程中栈帧的开辟及维护过程。作者在文中探讨了栈顶地址的变化以及寄存器的作用,为读者提供了深入理解栈帧机制的途径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前总结过一篇有关函数栈帧的博客:
函数栈帧以及调用约定相关的一些总结
但是感觉自己还是有一点知识点没有弄懂,今天中午跟郭哥吃过饭一起探讨有关壳的问题的时候,顺便把这个问题请教了一下郭哥,终于弄明白了,在此要特地感谢他,这里把一些心得体会写出来;
先看一幅图(选自IDA权威指南):
这里写图片描述
注意图中是基于esp的栈帧!!!
下面是对demo_stack frame函数中bar的调用代码为例:

push dword [esp+4];//push y,1th
push dword [esp+4];//push z,2th
call bar
add esp,8
栈中数据对应地址
。。。。。。
。。。。。。
data1Addr1
data2Addr2
data3Addr3
。。。。。。

举例分析

结合上面这幅图讲讲:
esp和ebp都是寄存器,esp始终指向栈顶的意思是:esp这个寄存器里面始终存放的是栈顶的地址,只不过这个栈顶地址很有可能是经常变化的,栈顶所对应的一个”容器”里面存放了一个数据,这个数据就是被压入栈的数据(其实栈中其他数据也类似,就是说一个数据对应一个地址),同理EBP也是这样去理解!
对上面那段代码(这段代码是与基于esp的栈帧对应的)的解释:
根据上面那副图的偏移量,1处的push准确的将局部变量y压入栈中;初看起来,似乎2处的push错误地再次引用了局部变量y,然而,这里是基于esp的栈帧!结合上表来理解,假设执行完push y之后,此时栈顶为addr2,即esp这个寄存器里面存放的是Addr2的地址,而在这一步之前栈顶为addr3(esp这个寄存器里面存放的是Addr3的地址),即进行了一次push y操作之后,栈顶被抬高了,栈顶是变化的!此时esp中存的是Addr2,再压一次栈push z,其所对应的指令为push [esp + 4] (这里指令中的esp指的是addr2),这一步之后,栈顶又会变成addr1.

分步解析一下:假设原来栈是这样的:
esp指向1000这个地址这里:

栈中数据对应地址
。。。。。。
。。。。。。
z1000
y1004
buffer1008
。。。。。。

执行push y之后:esp指向996了,esp变化了,此时此时Z所对应的地址仍然为1000,但是用esp表示的话则为esp+4,而Z则就用[esp+4]表示,所以图中push Z的时候写为 push dword [esp+4]:

栈中数据对应地址
。。。。。。
y996
z1000
y1004
buffer1008
。。。。。。

小结:

esp是一个寄存器,这个寄存器里面存放的是一个地址,同时这个地址可能是不断变化的.

对开辟栈帧的理解

看几条指令(基于ebp的栈帧):

push ebp;//把ebp里面的地址压入栈中保存了起来;这一步作用:保存上一个栈帧的底部
mov ebp,esp;//把esp里面的地址放入ebp寄存器里面;此时esp和ebp指向同一个地址,即栈顶和栈底重合;这一步作用:设置新栈帧的底部
sub esp,0x50;//设置新栈帧的顶部,为新栈帧开辟空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值