C语言的栈帧

简介: C语言的栈帧

有如下函数,其中有函数的并行调用和嵌套调用:

include

int g = 1;
double a(double x,double p){ p = x;
return x;
}
int d(int x){
return x;
}
int c(int x,int p){ p = x;
return d(3)+x;
}
int b(int x){
int a,b;
b = c(4,&a);
printf("%d\n",a);
return b+x;
}//代码效果参考:http://www.zidongmutanji.com/bxxx/393430.html

typedef struct Point_t{
double x,y;
}Point;

Point e(Point a){
return a;
}

main()
{
Point pt;
pt.x = 1.25;
pt.y = 2.75;
int s = a(1.25,&(pt.x));
s += b(5);
s+= g;
printf("%d %lf\n",s,pt.x);
e(pt);
getchar();
}
1 全局变量已在程序执行前加载(加载阶段)

2 系统调用main函数

main函数调用前EBP与ESP的初始值:

3 EBP压栈并更新,抬高esp

0x12FF48-0x78 = 12FED0

4 保存寄存器状态

(寄存器值压栈,栈顶操作,78h以外)

push时,esp抬高(址值减小);

5 栈帧(这里安排了78h个字节)的初始化(调试模式下)

6 main函数的数据在此栈帧上操作

ebp-x,也就是从栈底操作。

7 调用函数前参数压栈

(栈顶操作,78h以外)

注意传址时,压的地址还是ebp-x。也就是主调函数的局部变量地址。

8 main()调用a()

对参数的引用:ebp+x

返回double的汇编指令:

fld qword ptr [ebp+8]

函数返回,通过以下几个汇编指令,esp、ebp回退:

00401079 pop edi
0040107A pop esi
0040107B pop ebx
0040107C mov esp,ebp
0040107E pop ebp
0040107F ret
通过以下汇编,esp降到压参前的位置:

004011E4 add esp,0Ch

函数返回值类型转换,值返回:

004011E7 call __ftol (0040176c)

004011EC mov dword ptr [ebp-14h],eax

9 main()调用b()

main()调用完a(),再调用b(),a()与b()之间是并行调用关系(都由main调用),并行调用关系的函数的栈帧是相互叠加关系,后面调用的函数覆盖在前面函数的栈帧上。

10 b()调用c()

11 c()调用d()

函数嵌套调用时,栈帧上下叠加。

12 函数d()、c()、b()返回

函数d()返回后,剩下main()、b()、c()的栈帧;

函数c()返回后,剩下main()、b()的栈帧;

函数b()返回后,剩下main()的栈帧;

13 main()函数调用e()

13.1 ebp、esp初始值

esp: 0012FEC4
……
ebp: 0012FF42
图示:

pt两个分量对应的16进制值:

1.25 3F F4 00 00 00 00 00 00

2.75 40 06 00 00 00 00 00 00

13.2 压参

13.3 当返回值不是整型或浮点型时

当被调函数的返回值不是整形或浮点型的复合类型时,用寄存器保存不了,需要将返回值保存到主调函数的栈帧空间。

对应以下内存映像:

13.4 返回值保存到被调函数栈空间并赋值函数保存返回值的临时空间

14 总结

函数并行被调用:栈帧相互叠加(重叠);

函数嵌套调用:栈帧上下叠加(不重叠);

函数的递归调用也是一种嵌套调用,所以栈内存的增长会很快!

函数调用时建立栈帧,但栈帧并不只限于栈的push、pop操作esp,且也可以通过ebp进行偏移,也可以将主调函数的栈帧上的局部变量的地址通过通过参数压到栈上,被调函数通过间接寻址来访问主调函数的局部变量空间(如传址和值返回一个复合类型的值)。

相关文章
|
17天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
91 9
|
6月前
|
C语言
链栈的初始化以及用C语言表示进栈、出栈和判断栈空
链栈的初始化以及用C语言表示进栈、出栈和判断栈空
71 3
|
6月前
|
机器学习/深度学习 存储 算法
C语言栈与递归的实现讲解
C语言栈与递归的实现讲解
105 0
|
6月前
|
C语言
C语言栈的行编辑程序讲解
C语言栈的行编辑程序讲解
114 0
|
6月前
|
C语言
C语言栈的括号匹配的检验讲解及相关代码
C语言栈的括号匹配的检验讲解及相关代码
146 0
|
1月前
|
C语言
数组栈的实现(C语言描述)
本文介绍了如何在C语言中使用数组来实现栈的数据结构,包括栈的创建、入栈、出栈、获取栈顶元素、检查栈是否为空、获取栈的大小以及销毁栈等操作,并提供了相应的函数实现。
27 1
|
2月前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
391 8
|
2月前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
374 3
|
6月前
|
存储 C语言
C语言栈的表示和实现的定义讲解
C语言栈的表示和实现的定义讲解
98 0
|
5月前
|
C语言 C++
【数据结构】C语言实现:栈(Stack)与队列(Queue)
【数据结构】C语言实现:栈(Stack)与队列(Queue)