堆栈相关学习
堆栈的基本概念
栈:由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆: 一般由程序员分配释放, 在C语言中使用malloc函数分配的内存会被操作系统会智能的释放,但如果程序一直运行则会造成内存泄露。
ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
堆栈空间从栈顶开始使用
相关指令
PUSH指令
PUSH指令将源操作数压入堆栈,可以是寄存器的值或者立即数或者内存中的值,并且减少ESP的值,数值相当于数据的长度
例如
1 | PUSH AX |
以上命令将AX寄存器中的值压入栈中,并且ESP减2,相当于以下两条指令,PUSH指令会自动调整ESP的值
1 | MOV WORD PTR DS:[ESP],AX |
POP指令
数据压入栈后要弹出可以对ESP加上需要弹出的长度
例如
1 | PUSH ECX |
以上指令可以直接简化成POP ECX,此指令将栈顶4字节内存数据储存到ECX,并且ESP+4
堆栈平衡
如果要返回父程序,在堆栈进行堆栈的操作的时候,要保证
RET这条指令之前,ESP指向的是压入栈中的地址
例如:
1 | CALL 0X0041009C |
以上代码在返回时栈顶内存为1,RET指令将1写入到EIP寄存器,导致下一步指令找不到了
如果通过堆栈传递参数了,那么在函数执行完毕后,要平衡参数导致的堆栈变化
对于传参之后的堆栈平衡有两种方法,例如有如下代码
1 | PUSH 1 |
以上代码在函数调用完毕后,压入堆栈的2个立即数没有释放,有两种平衡方法:
外平栈:在函数调用后将
ESP寄存器 + 8内平栈:在函数内部平衡堆栈,直接使用
RET 8指令,这条指令会在返回后将ESP额外+8,一共+12,还有函数地址占用的4字节
EBP寻址
使用ESP寻址的缺点:在函数中如果要使用堆栈的话ESP会发生变化,此时使用参数和局部变量会收到影响,EBP寻址可以拟补此缺点
例如:
1 | PUSH 1 |
在跳转后将EBP的值压入栈中,将ESP的值存放到EBP,然后将ESP-10,相当于一个新的堆栈空间,原有的EBP储存在栈中,ESP储存在EBP中

要寻找参数时只需要以EBP为基准寻址即可,EBP相当于修改前的ESP,但要注意的是调用函数后除了函数地址,还把EBP压栈了,所有第一个参数的偏移量应该是0X8
返回时只需要将两个堆栈指针寄存器还原即可,先还原ESP,因为EBP保存着以前ESP的值
调用完毕后ESP和EBP的值保持不变

