函数栈帧的创建和销毁
1.寄存器的认知
函数栈帧的创建和销毁离不开寄存器,了解函数栈帧之前先了解一下cpu中的寄存器
cpu中供应用程序员使用的寄存器主要有:通用寄存器(EAX、EBX、ECX、EDX、ESP、EBP、ESI、EDI),段寄存器(CS、DS、SS、ES、FS、GS),标志和控制寄存器(EIP、EFLAGS)
其中EBP一般用作基址指针,ESP一般用作堆栈指针—ebp作为栈底指针,esp作为栈顶指针
对于内存的认知:栈区、堆区、全局静态区、常量区、代码区
—实际存储是从高地址往低地址方向存储
—这也说明了为什么int a=0x11223344在查看内存监视器的时候,地址内容显示是44 33 22 11
对于esp和ebp的认知:
举例代码:
#include <stdio.h> int ADD(int x, int y) { int z = 0; z = x + y; return z; } int main() { int a = 10; int b = 20; int c = 0; c = ADD(a, b); printf("%d", c); return 0; }
通过反汇编有了如下图的结果:
2.栈帧的创建
通过上面的举例代码,我们剖析这个栈帧创建过程:首先是main函数创建栈帧,然后是ADD函数创建栈帧
main函数创建栈帧过程:
main函数栈帧创建的详细步骤:
1.main函数创建栈帧之前:
2.ebp压栈,esp指向开辟空间的顶端并赋值给ebp指针
3.esp-e4h即main函数栈帧大小为e4h字节,esp指向main函数栈顶
4.ebx、esi、edi压栈并给edi加载有效地址ebp-24h,将edi和ebp之间的9个地址赋值为cc cc cc cc
5.给ebp-8,ebp-14,ebp-20h赋初值exa压栈,并将ebp-14h的值传给eax,ecx压栈,并把ebp-8的值传给ecx,这个过程就是函数传参的过程。调用函数ADD之前把call下一句地址压栈
至此main函数的函数栈帧的创建和数据初始化就完成了
ADD函数栈帧的创建:
add函数栈帧的创建和main函数栈帧创建是一样的,需要注意的是,ADD函数执行结束后的返回值保存在了寄存器eax中,就是避免ADD函数栈帧销毁时,主函数无法访问ADD返回值。由此可见函数返回值是如何返回的。
ADD函数栈帧的创建详细过程:
3.栈帧的销毁
以ADD函数函数栈帧的销毁为例
ADD函数栈帧销毁详细步骤:
4.基于函数传参、返回值、初始化赋值、调用、执行结束问题的思考
函数如何传参:
函数返回值如何返回:
函数中变量如何初始化和赋值:
函数如何调用如何返回:
函数执行结束后系统进行了什么操作: