栈以及栈帧

默认读者有一定编程经验

栈的特点:

先入后出

栈的相关寄存器:

ESP   栈顶指针寄存器

EBP   栈底指针寄存器

栈的相关指令

PUSH 将数据压入栈中

POP  将数据弹出栈

那么什么是栈帧?

栈帧在程序中用于声明局部变量,调用函数。利用EBP(栈顶指针)寄存器,访问栈内局部变量,参数,函数的返回地址等等。

那么为什么是利用EBP而不是ESP呢?

因为栈的特点是先进后出,所以栈底指针不会改变只有栈顶指针会改变

所以在一个函数中以栈底指针为基址就不会找错值

下面我们以一个例子研究栈帧的生成

使用编译器为vc6++

我们先记录一下没有开始执行的寄存器和内存以及栈的值

非常地道

我们先执行到0x401063的sub esp,48

sub esp,48这条指令就是给栈开辟一个新的空间用于存放这个函数可能使用到的局部变量

接着执行下面的三条push指令

我们发现这三个寄存器的值被存储到栈中

lea     edi, dword ptr [ebp-48]

这个指令是将ebp-48的地址存放到edi寄存器中

 

这个mov ecx 12 是用来为下面的循环做准备的

但是下面这个mov就是用来填充eax寄存器的值

00401076  |.  F3:AB         rep     stos dword ptr es:[edi]

现在我们马上要执行这个指令了

Rep指令是重复字符串操作的指令

在这里ECX寄存器用来计数

EDI为目标寄存器指针

当我们执行之后发现

这段代码就是填充原来栈中可能存在的垃圾数据

下面执行两条mov指令

这四条指令就是将刚才填入的1和2再放入eax和ecx寄存器中

下一条指令就是进入add函数

这都是一一对应的关系

其中可以看到push和pop的寄存器的顺序变了,这就是因为栈的特点

我们直接执行到

0040D4C8  |.  C745 FC 00000>mov     dword ptr [ebp-4], 0

调用printf函数

在调用完函数之后

我们可以看见栈顶指针加上了8

因为上面push进了两个参数

这两个参数的字节都是4

这样正好清除栈里面的垃圾数据   这个属于是cdecl调用约定   由调用者清理栈

将最后的结果存入eax

(x86寄存器都是将函数的返回值传入EAX寄存器)

然后我们一路来到主函数

这个也是cdecl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值