c语言函数栈帧的创建和销毁过程详解

目录
  • 1 相关知识介绍
    • 1.1 寄存器
    • 1.2 函数栈帧概述
  • 2 栈帧创建与销毁过程

1 相关知识介绍

1.1 寄存器

一般计算机内通用寄存器包括eax,ebx,ecx,edx,esi,edi,esp,edp,其中esp,ebp这两个寄存器是用来存放地址的,这两个地址就是用来维护函数栈帧的

1.2 函数栈帧概述

我们知道c语言中函数都是被调用的,main函数里面能调用其他函数,其实main函数也是被别的函数调用的。main函数是在 _tmainCRTSartup 函数中被调用的,_tmainCRTSartup函数又是在mainCRTSartup函数中被调用。
每一次函数调用都是一个函数调用过程,这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存、现场保护,也叫函数栈帧。栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。

push 压栈:给栈顶放上一个元素
pop 出栈:从栈顶删除一个元素

函数栈帧结构如下:
其中esp为栈顶指针,ebp为栈底指针,他们共同来维护函数栈帧。

2 栈帧创建与销毁过程

为了描述函数栈帧的创建和销毁我们以一个简单程序为例

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}
int main()
{
	int a = 20;
	int b = 10;
	int c = 0;
	c = add(a, b);
	printf("%d\n", c);
	return 0;
}

当进入main函数前,esp,ebp在如下位置

我们此时可以进入调试模式然后进入反汇编模式看下汇编代码从而观察main函数栈帧的创建


这里是将ebp压栈(用来记录上一个ebp方便函数销毁时找到上一个函数的位置),然后将esp的值传给ebp,在将esp的内容减去0E4h,从而为main函数创建了一个栈帧,并且将ebx,sei,edi的值进行压栈。效果如下


这里是将ebp-0E4h的值加载到edi里面,然后将39h放到ecx寄存器里,再将0CCCCCCCCh放到eax寄存器里,最后将edi这个地址下面的39h个字节数据的值全部置为CCCCCCCC.


这段汇编代码时将14h赋值到ebp-8的空间里面,将0Ah赋值到ebp-14h的空间里面,将0赋值到ebp-20h的空间里面.


然后进入c = add(a,b)语句,首先将ebp-14h的值放到eax寄存器中在将eax的值进行压栈操作,再将ebp-8的值放到ecx寄存器中在将ecx的值进行压栈操作。

下面图片中绿色框里eax应该是10,ecx是20,画图时写反了实在是抱歉


这里是跳转到add函数,并将下一条语句的地址压入栈内

000E17C0  push        ebp  //记录上一个ebp内容
000E17C1  mov         ebp,esp  //将esp的值赋给ebp
000E17C3  sub         esp,0CCh  //将0CCh赋给esp,为add创建栈帧
000E17C9  push        ebx
000E17CA  push        esi
000E17CB  push        edi
000E17CC  lea         edi,[ebp+FFFFFF34h]
000E17D2  mov         ecx,33h
000E17D7  mov         eax,0CCCCCCCCh
000E17DC  rep stos    dword ptr es:[edi]
000E17DE  mov         ecx,0EC003h  //与前面类似
000E17E3  call        000E1307  //进入add函数
     7: 	int z = 0;
000E17E8  mov         dword ptr [ebp-8],0  //将0赋给ebp-8的内容
     8: 	z = x + y;
000E17EF  mov         eax,dword ptr [ebp+8] //将a的值赋给eax寄存器
000E17F2  add         eax,dword ptr [ebp+0Ch]  //将b+a的值赋给eax
000E17F5  mov         dword ptr [ebp-8],eax  //将eax的值赋给ebp-8的内容里面
     9: 	return z;
000E17F8  mov         eax,dword ptr [ebp-8] //将ebp-8的内容里面赋给eax

至此add函数功能执行完成,接下来开始返回,也就是进行add函数栈帧销毁

首先分别将edi,esi,ebx进行出栈,然后将esp加上0CCh也就是回到ebp的位置,然后将ebp的值赋给esp,再将ebp进行出栈操作(这样就能回到原来的main函数的ebp位置从而将add的栈帧空间还给操作系统)


后面是main函数的销毁过程,流程和add销毁一样,这里就不在过多赘述。

到此这篇关于c语言函数栈帧的创建和销毁的文章就介绍到这了,更多相关c语言函数栈帧内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言sqrt函数的实例用法讲解

    c语言sqrt函数的用法 sqrt函数用于计算一个非负实数的平方根. sqrt的函数原型: 在VC6.0中的math.h头文件的函数原型为double sqrt(double); 说明:sqrt即Square Root Calculations(平方根计算),通过这种运算可以考验CPU的浮点能力. 头文件:math.h 程序示例: #include <math.h> #include <stdio.h> int main(void) { double x = 4.0, result

  • C语言堆栈帧的介绍与创建

    什么是堆栈帧? 堆栈帧(stack frame)是一块堆栈保留区域,用于存放被传递的实际参数,子程序的返回值.局部变量以及被保存的寄存器. 堆栈帧的创建方法

  • Linux中使用C语言的fork()函数创建子进程的实例教程

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己.   我们来看一个例子: #include <unistd.h> #include &

  • 举例讲解C语言的fork()函数创建子进程的用法

    先来看这样一个例子,利用fork调用execlp()函数来在Linux下实现ps或ls命令: #include "sys/types.h" #include "unistd.h" #include "stdio.h" #include "stdlib.h" int main() { pid_t result; result=fork(); //报错处理 if(result==-1) { printf("Fork Er

  • c语言函数栈帧的创建和销毁过程详解

    目录 1 相关知识介绍 1.1 寄存器 1.2 函数栈帧概述 2 栈帧创建与销毁过程 1 相关知识介绍 1.1 寄存器 一般计算机内通用寄存器包括eax,ebx,ecx,edx,esi,edi,esp,edp,其中esp,ebp这两个寄存器是用来存放地址的,这两个地址就是用来维护函数栈帧的 1.2 函数栈帧概述 我们知道c语言中函数都是被调用的,main函数里面能调用其他函数,其实main函数也是被别的函数调用的.main函数是在 _tmainCRTSartup 函数中被调用的,_tmainCR

  • C语言函数栈帧的创建和销毁介绍

    在初学c语言中,很多时候要记的内容有点多,有时候并不能深入的了解它.关于函数的栈帧可以帮助我们深入了解函数传参的过程,让我们了解c语言. 以下是我们平时接触过,但不了解的问题: 1.为什么局部变量在未赋值前是随机的. 2.局部变量创建的过程. 3.函数传参,传参的顺序问题. 4.形参与实参的关系什么. 5.调用函数是怎么调用的,调用的过程是什么. 6.调用函数结束后,是怎样返回的. 这些问题我们在学校可能并不会接触,也不会出现在考试的试卷上,但是作为计算机专业的学生,做一些认识和了解是很有必要的

  • C语言函数栈帧的创建与销毁原理图解

    目录 什么是函数栈帧 什么是栈? 与函数栈帧有关的汇编语句 函数如何创建栈帧并销毁 main函数栈帧开辟 调用Add函数 返回主函数 什么是函数栈帧 我们在写C语言代码的时候,经常会把一个独立的功能抽象为函数,所以C程序是以函数为基本单位的. 那函数是如何调用的?函数的返回值又是如何待会的?函数参数是如何传递的?这些问题都和函数栈帧有关系. 函数栈帧(stack frame)就是函数调用过程中在程序的调用栈(call stack)所开辟的空间,这些空间是用来存放: 函数参数和函数返回值 临时变量

  • C语言函数栈帧的创建与销毁详解

    目录 前言 一.函数栈帧是什么? 1.寄存器 2.ebp与esp 二.函数栈帧的创建 1.代码块 2.调用堆栈 3.esp与ebp如何维护栈帧 总结 前言 大家在学习的时候一定有以下困惑: 局部变量是怎么创建的?为什么局部变量的值是随机值?函数是怎么传参?传参的顺序是怎样的?形参与实参是什么关系?函数调用是怎么做到的?函数调用完成不是销毁了吗,如何带回的返回值? 以上这些都可以通过了解函数栈帧的创建与销毁来理解.接下来我就带大家来了解函数栈帧的创建与销毁. 本次使用的编辑器是VS2013,因为越

  • C语言函数栈帧的创建和销毁详解

    目录 写在前面 Add函数的调用 函数传参 Add函数栈帧的创建 Add函数栈帧的销毁 main函数栈帧的销毁 总结 写在前面 我们知道,每一次函数调用都需要在栈区上为其开辟一块空间,这块空间就叫做这个函数的栈帧. 而栈是从高地址向低地址延伸的.每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息.寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址). 这样我们就了解了寄存器ebp和寄存器esp中存放的是地址,这两个地址是用来维护函数栈

  • C语言超详细讲解函数栈帧的创建和销毁

    目录 1.本节目标 2.相关寄存器 3.相关汇编指令 4.什么是函数栈帧 5.什么是调用堆栈 6.函数栈帧的创建和销毁 (1).main函数栈帧的创建与初始化 (2).main函数的核心代码 (3).Add函数的调用过程 (4).Add函数栈帧的销毁 (5).调用完成 7.对开篇问题的解答 1.本节目标 C语言绝命七连问,你能回答出几个? 局部变量是如何创建的?为什么局部变量不初始化其内容是随机的?有些时候屏幕上输出的"烫烫烫"是怎么来的?函数调用时参数时如何传递的?传参的顺序是怎样的

  • C语言中函数栈帧的创建和销毁的深层分析

    目录 一.本文目标 二.基础知识 1.寄存器 2.代码案例 3.总体栈帧概况 4.所需反汇编代码总览 三.函数栈帧创建销毁过程 1._tmainCRTStartup函数(调用main函数)栈帧的创建 2.main函数栈帧的创建 3.main函数内执行有效代码(变量) 4.Add函数栈帧的创建 5.Add函数内执行有效代码 6.Add函数栈帧的销毁 7.main函数栈帧的销毁 四.总结 一.本文目标 1.局部变量是怎么创建的? 2.为什么局部变量的值是随机值? 3.函数是怎么传参的?传参的顺序是怎

  • C语言详尽图解函数栈帧的创建和销毁实现

    目录 常见寄存器 基本的汇编语言知识 具体实现 关于栈帧创建与销毁的问答题 注:本文章所使用的编译器是VS2010,由于不同编译器的函数栈帧与销毁略有差异,所以具体细节请读者自行实践! 常见寄存器 寄存器有:eax.ebx.ecx.edx.edi.esi.ebp.esp 其中 ebp 和 esp 是用来维护函数栈帧的,他们里面存放的是地址. 他们维护的是某个正在被调用的函数.通常我们又称 ebp 为栈底指针,称 esp 为栈顶指针 基本的汇编语言知识 push:压栈 pop:出栈 mov:若有变

  • C语言函数栈帧详解

    目录 前言 一.函数栈帧是什么? 二.栈帧准备知识 1.内存分区 2.什么是栈? 三.详解栈帧创建与销毁全过程 调用函数之前: 将传入函数的值放入栈中 函数执行: 1.保护当前ebp 2.创建所需调用函数的栈帧空间 3.保存局部变量 4.参数运算 函数返回: 1.存储返回值 2.销毁空间 3.ebp回上一栈帧栈底 4.销毁形参 5.main函数拿到返回值 总结 前言 在c语言中我们会将一些功能单独写成一个函数,以供主函数调用,在表面来看调用的过程就是写出一个函数后,只需要在调用时中通过函数名将实

  • C语言函数栈帧解析

    目录 一.什么是函数栈帧 1.寄存器: 2.函数栈帧 3.栈帧的作用和维护 4.栈帧结构 二.函数栈帧的创建 1.汇编代码 2.main函数 2.栈帧创建: 3.步骤 4.ADD函数栈帧的创建 三.函数栈帧的销毁 1.汇编语言 四.了解 1.函数传参 2.函数返回值如何返回 3.函数中变量如何初始化和赋值 总结 一.什么是函数栈帧 1.寄存器: eax, ebx, ecx ... ebp - 存放了指向函数栈帧栈底的地址 esp - 存放了指向函数栈帧栈顶的地址 2.函数栈帧 函数被调用时,系统

随机推荐