C函数调用原理----栈帧

函数调用原理----栈帧


1.关于栈
首先必须明确一点也是非常重要的一点,栈是向下生长的,所谓向下生长是指从内存高地址->低地址的路径延伸,那么就很明显了,栈有栈底和栈顶,那么栈顶的地址要比栈底低。对x86体系的CPU而言,其中
---> 寄存器ebp(base pointer )可称为“帧指针”或“基址指针”,其实语意是相同的。
---> 寄存器esp(stack pointer)可称为“ 栈指针”。
要知道的是:
---> ebp 在未受改变之前始终指向栈帧的开始,也就是栈底,所以ebp的用途是在堆栈中寻址用的。
---> esp是会随着数据的入栈和出栈移动的,也就是说,esp始终指向栈顶。
见下图,假设函数A调用函数B,我们称A函数为"调用者",B函数为“被调用者”则函数调用过程可以这么描述:
(1)先将调用者(A)的堆栈的基址(ebp)入栈,以保存之前任务的信息。
(2)然后将调用者(A)的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者B的栈底)。
(3)然后在这个基址(被调用者B的栈底)上开辟(一般用sub指令)相应的空间用作被调用者B的栈空间。
(4)函数B返回后,从当前栈帧的ebp即恢复为调用者A的栈顶(esp),使栈顶恢复函数B被调用前的位置;然后调用者A再从恢复后的栈顶可弹出之前的ebp值(可以这么做是因为这个值在函数调用前一步被压入堆栈)。这样,ebp和esp就都恢复了调用函数B前的位置,也就是栈恢复函数B调用前的状态。
这个过程在AT&T汇编中通过两条指令完成,即:
leave
ret
这两条指令更直白点就相当于:
mov %ebp , %esp
pop %ebp


1.对一个简单的c程序的函数调用过程的分析:
在main函数中调用fun函数:
1).先将main函数的ebp入栈,以保存之前任务的信息。
2).然后将main函数的esp的值赋给ebp,即就是让ebp指向esp指向的空间,让ebp做为fun函数的栈底
3).然后将esp的值sub某个值,也就是为fun函数开辟新的栈空间。
4).fun函数调用结束后,将esp指向ebp的地址,使当前栈帧的ebp恢复为main函数的栈顶。
5)然后从main函数的栈顶弹出main函数的ebp(因为在调用fun 函数之前保存了main函数的ebp),使得ebp恢复为调用fun函数之前main函数的栈底,接着弹出esp的内容–保存的call指令的下一条指令的地址,然后 esp指向指向这个地址。则这时esp和ebp都恢复为调用fun函数之前的位置。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int fun(intx, inty)
{ 
   int c = 0xcccccccc;
   returnc;
}
int main()
{ 
   int a = 0xaaaaaaaa;
   int b = 0xbbbbbbbb; 
   int ret = fun(a, b);
   printf("you should running here!\n");
   system("pause"); 
   return0;
}




对main函数栈帧的分析:
loading...
loading...
loading...
loading...
loading...
调用fun函数时:
loading...
返回main函数后:
loading...
main函数和fun函数的栈帧示意图:
loading...

2.从内存的角度详细的分析C语言中的函数调用过程:

首先写一个测试用的代码:

#include <stdio.h>

int add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}

int main()
{
	int a = 1, b = 2;
	int c = 0;

	c = add(a, b);

	return 0;
}
这仅仅是一个简单的的求和函数。

其次,让我们确定一下,程序是从哪里开始运行的:

调试程序,按一下F10(博主用的VS2013),

进入main函数:


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值