函数调用过程中产生的栈帧

在c语言中编译的程序占用的内存分为一下几个部分:

  1、栈区(stack)2、堆区(heap)3、全局区(静态区)(static)4、字符常量区 5、代码区(code)

如图所示:  

 


这篇博客主要描述其中的栈区。

在函数的调用过程中,要为函数开辟空间,用于本次函数的调用中临时变量保存、现场保护。这块栈空间我们称之为函数的栈帧。

先要了解 几个寄存器  :  ESP  栈顶寄存器      EBP栈底寄存器(基址寄存器) EIP 程序计数器:放当前正在执行指令的下一条指令的内容

以一个简单的程序来描述函数的栈帧。

#include <stdio.h>
#include <windows.h>
int Add(int x,int y)
{
   int z=0;
   z=x+y;
   return z;
}
int main()

{
   int a=0xaaaaaaaa;
   int b=0xbbbbbbbb;
   int ret=Add(a,b);
   printf("ret=%d\n",ret);
   system("pause");
   return 0;
}

分段转入此程序的汇编代码中:


在此段代码中,栈结构如图所示。    在此图中,我们发现函数形参实例化是从右向左的。

将ecx中内容入栈,接来下就是call命令,call命令有两个作用:

      ①将当前汇编地址的下一条地址保存在栈上,便于恢复。

      ②跳转至目标函数的入口地址处。

   

call命令后,由汇编代码可以看到,跳到了  目标地址 00401005。


此段汇编代码,则是函数内部的调用过程。  

对应栈上的图,相对比较好理解。



此时函数的栈帧已经形成,就是  粗体EIP,ESP所指向的内容。


接下来就是ret指令,有两个功能:

      ①  将之前保存的函数值的返回地址进行出栈,即00401093出栈

      ② 将弹出的地址放入EIP。

按下F11后,我们跳转至了  00401093,如图:


也就是  此时ESP指向红线处:




经过此代码,函数调用过程中产生的临时变量全部清空,即临时变量随用随丢,由图可证。



函数调用完成,返回值也附给main函数。

进过函数调用产生的栈帧,亦可以得出两个结论。

一、函数形参形成是随用随丢的。

二、函数形参调用是从右至左形成的。


仅以个人理解作此文章,难免有遗漏或不足之处,欢迎随时指出问题!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在程序执行过程,每个函数都会有一个对应的栈帧(stack frame),用于存储函数的参数、局部变量、返回地址等信息。当函数调用时,一个新的栈帧被压入,当函数返回时,该栈帧被弹出。 下面是一个简单的示例程序和对应的栈帧变化过程: ``` int add(int a, int b) { int sum = a + b; return sum; } int main() { int x = 1; int y = 2; int z = add(x, y); return 0; } ``` 在执行 `main()` 函数时,首先会创建一个 `main()` 函数栈帧,并将其压入: ``` |-----------------| | return address | <--- 顶 |-----------------| | z (0) | |-----------------| | y (2) | |-----------------| | x (1) | |-----------------| ``` 接下来,调用 `add()` 函数,会创建一个新的栈帧,并将其压入: ``` |-----------------| | return address | <--- 顶 |-----------------| | z (0) | |-----------------| | y (2) | |-----------------| | x (1) | |-----------------| | return address | |-----------------| | saved %ebp | |-----------------| | b (2) | |-----------------| | a (1) | |-----------------| ``` 在 `add()` 函数,首先会保存当前函数的 `%ebp` 寄存器的值,然后将当前栈帧的 `%ebp` 寄存器设置为当前顶的地址。这样可以在函数执行过程,通过 `%ebp` 寄存器访问当前栈帧的参数和局部变量。接下来,函数会将参数 `a` 和 `b` 压入。最后,函数执行完毕后,会将返回值存放在 `%eax` 寄存器,并将栈帧弹出。 回到 `main()` 函数,在调用 `add()` 函数后,栈帧变化如下: ``` |-----------------| | return address | <--- 顶 |-----------------| | z (3) | |-----------------| | y (2) | |-----------------| | x (1) | |-----------------| ``` 最后,`main()` 函数执行完毕,将栈帧弹出,程序结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值