内存与寄存器
函数栈帧
常用寄存器
Name | Description |
---|---|
ESP | 指向栈帧的栈顶地址(内存较低位),会随着程序的执行向低位移动 |
EBP | 指向栈帧的基地址(内存较高位) |
EIP | 指令指针寄存器,保存着 CPU 要执行的指令地址,永远指向 CPU 将要执行的下一条指令的地址 |
ESI | 源变址寄存器,保存着要处理的数据的内存地址 |
EDI | 目的变址寄存器,保存着处理后的数据的内存地址 |
程序执行过程中内存和寄存器的变化
给 a 赋值后
程序运行到 fun 函数时,ESP 减少了 12,即往内存低位移动了 3 个内存单元,也就是有 3 * 4 字节数据被压入了栈帧,查看 ESP 指向的内存区域,0x12FF20 处 4 字节为主调函数 main 的返回地址,可以看到 8 字节为形参的值已经被压入了栈帧,形参的值先被寄存器 EAX,ECX 保存,再写入到内存中
继续执行,进入了 fun 函数的栈帧,EBP,ESP 的值都改变了,新 EBP 指向原 ESP-4 的值,也就是 EBP 移动到了原 ESP 的上方,而新 EBP 指向的内存中储存的值是原 EBP 的值
fun 函数最后的加法运算,值也是先保存到寄存器中,再写入到 fun 函数的栈帧中
当 fun 函数执行完毕,fun 函数的栈帧将被 OS 回收,EBP 将重新指向原 EBP 指向的内存,而 ESP 指向了原 ESP+4 的内存地址,说明发生了 POP 操作,弹出了返回地址 0x401093,原 ESP 的值是当前 EIP 的值,这个地址被存入了 EIP 中,也就是被 CPU 执行了,以便继续执行 main 函数。 最后可看到 ESP 指向了 0x12FF2C,即程序一开始时 ESP 的值,说明传递给 fun 的形参都被弹出, 恢复到调用 fun 之前的栈帧状态。return 0 程序正常结束。
源代码
一个简单的加法函数和主函数,主函数中调用 fun() 实现两个变量的加法运算
#include <stdio.h> void fun(int _m, int _n) { int i_local; i_local = _m + _n; } int main(int argc, char const *argv[]) { int a = 0x1111; int b = 0x2222; fun(a, b); return 0; }