函数调用过程-函数栈帧

函数栈帧

  • 函数是程序中必不可少的一个部分,整个程序的运行几乎都是由一个个函数之间互相调用来完成的,我们的main函数,printf函数,还有编程时我们自己写的函数,它们时我们的程序简介高效。

那么一个函数在内存中到底是如何调用的?如何实现函数的种种功能的?

深度解析

看这样一段代码

#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 ret = Add(a, b); 
    printf("ret = %d\n", ret); 
    return 0;
}

这段简单代码实现加法,其中Add函数实现加法,参数为两个整型变量,Add函数被main函数调用。

铺垫

1.
解析前做这样一个铺垫:
我们的main函数其实也是被其他函数调用的

以vs2008为例,代码写好后按F10开始逐过程可以看到上方有一个堆栈帧点开后如图
这里写图片描述
- main函数是被__tmainCRTStartup(void)函数调用的,而这个函数又是被mainCRTStartup(void)函数调用的。点击可进入查看源代码。

2.
内存中的地址是由寄存器来维护的,主要的寄存器有

  • eax , ebx , ecx , edx 还有这次最主要用到的 ebp(开辟空间的低地址) , esp(开辟空间的高地址)。
  • 当在内存中为函数开辟空寂后,ebp 存这块空间的高地址, esp 存这块空间的低地址。
  • 函数和局部变量在栈空间中开辟,栈孔吉娜由高地址向低地址使用。

这里写图片描述

反汇编剖析

现在我们开始研究函数的调用过程,即刚才按F10后逐过程停留在main函数,如第一幅图。

鼠标放在main函数旁边右击转到反汇编,然后在主工具栏找到-> 调试-窗口-点击监视和内存。

在监视栏找到ebp和esp的地址,同样在内存中找到以便后面观察。

  • 看图体会

这里写图片描述

继续按F10逐步执行

  • push为压栈向顶端压入一个地址,mov移动,sub开辟空间。
  • 按F10向下执行,这几步看图解析。

这里写图片描述

  • 继续连续三次压站三个寄存器
  • lea寻找有效地址
  • rep重复,将开辟的空间全部初始化为 cc cc cc cc
    这里写图片描述

  • 这里地址统一发生了变化,因为刚才调试中断了,但效果是一样的大家注意

这里写图片描述

  • 紧接着就为 a 和 b 初始化了
    这里写图片描述

-在call前的两次push是将a,b形参压入栈中
- 继续向下,遇到call是按F11,call是调用call函数
- 紧接着可以看到将ebp压入了栈顶,这里的ebp是main的起始地址,为函数调用完返回main使用。

这里写图片描述

这里写图片描述

  • 这后面与之前main过程类似

这里写图片描述

  • 后面相加完成后将z的值放入eax中,为带回到main函数ret中
  • Add函数的空间就会被释放
    -后面的pop是出栈到相应的寄存器中

  • 最后pop ebp就是将之前main函数的地址又返回到ebp从而使寄存器维护的区域回到main函数

随后执行printf函数最终结束main函数程序结束,函数在内存中的调用过程就是这样

作用

了解了函数在内存中的调用过程之后,一个程序在我们眼前是不是就显得很透明了呢?
那明白这些有什么作用,他的重要性又在哪里呢?
我们通过这样一段代码来体会。

void fun()
{
int tmp = 10;
int *p = (int *)(*(&tmp+1)); 
*(p-1) = 20;
}
int main() {
int a =0;
fun();
printf("a = %d\n",a); return 0;
}
  • 试判断输出结果是什么?
  • 答案是20(可以猜到)但我们要知晓他的原理

请参考倒数第三幅图理解

int *p = (int *)(*(&tmp+1));  
//tmp的地址加一指向了压入的ebp(main的地址),将这个地址给指针p,p就指向了main的开始。
*(p-1) = 20;
//p的地址减1,指向了为a开辟的空间从而改变了a的值。

从而可见函数栈帧的重要性

谢谢阅读欢迎留言~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值