c语言之函数调用及栈帧分析(代码片段)

可爱的乐乐哥哥 可爱的乐乐哥哥     2022-12-23     642

关键词:

一.前言 

每一次函数调用都是一个过程。这个过程我们通常称之为:函数的调用过程。

这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存,现场保护。这块栈空间就是函数栈帧。

实验代码:

#include<stdio.h>
int add(int a, int b)

	return a + b;

int main()

	int a = 10;
	int b = 20;
	int c = 0;
	c = add(a, b);
	printf("%d", c);
	return 0;

二.实验调试

1.按F11进入单步调试,在窗口处进入反汇编。

 进入反汇编界面

 三、函数栈帧的创建与销毁

1.在调试的时候我们要明白两个寄存器ebp内部存储的是栈底指针,esp存储的是栈顶指针。

eip是程序计数器,存的是当前正在执行指令的下一条指令的地址

2.进入程序,一步一步进行调试

(1).先看前三条

 push        ebp  
 mov         ebp,esp  
 sub         esp,0E4h 

栈区是从下到上,由高地址到低地址,先将ebp入栈,在将esp移到和ebp相同的位置。在将esp的地址减掉0E4h

 (2).再看三条操作

 push        ebx  
 push        esi  
 push        edi

继续向 main()函数上方又压入ebx,esi,edi,且esp也随着压入的数据而地址降低,

 (3).继续执行操作

 lea         edi,[ebp-24h]  
 mov         ecx,9  
 mov         eax,0CCCCCCCCh  
 rep stos    dword ptr es:[edi]  

第一条指令是将[ebp-0E4h]的值加载到edi当中,该地址是228个字节的上方。
第二,三条指令分别是将9赋给到ecx,0CCCCCCCCh 赋给到eax。
第四条指令则是将从edi开始,向下的39hdword(就是39hdoubleword(两个字),一共是228个字节,就是最开始开辟的main函数栈帧大小)都赋值为0CCCCCCCCh,也就是将main函数内的所有值都变成了0CCCCCCCCh。现在的栈就成了:

 (4).现在开始代码段

	int a = 10;
 mov         dword ptr [ebp-8],0Ah  
	int b = 20;
 mov         dword ptr [ebp-14h],14h  
	int c = 0;
 mov         dword ptr [ebp-20h],0  

这就是正常的赋值操作,第一条创建a=10,第二条创建b=20,第三条创建c=0;

(5)add函数的调用

	c = add(a, b);
 mov         eax,dword ptr [ebp-14h]  
 push        eax  
 mov         ecx,dword ptr [ebp-8]  
 push        ecx  
 call        00961023  
 add         esp,8  
 mov         dword ptr [ebp-20h],eax

第一条是现将b的值放到eax中,第二条是讲a的值放在ecx中,然后将eax,ecx压栈,在执行call指令,将call指令的下一条语句地址压入栈顶,然后进入准备调用的函数

 (6)add函数内部:

int add(int a, int b)

009617A0  push        ebp  
009617A1  mov         ebp,esp  
009617A3  sub         esp,0C0h  
009617A9  push        ebx  
009617AA  push        esi  
009617AB  push        edi  
009617AC  mov         edi,ebp  
009617AE  xor         ecx,ecx  
009617B0  mov         eax,0CCCCCCCCh  
009617B5  rep stos    dword ptr es:[edi]  
009617B7  mov         ecx,96C003h  
009617BC  call        0096130C  
	return a + b;
009617C1  mov         eax,dword ptr [ebp+8]  
009617C4  add         eax,dword ptr [ebp+0Ch]  

这个和main函数开始的时候一样都是创建空间,但eax和ecx的值用于add函数的初始化,且在过程中被更改,但压入栈中的"eax"和"ecx"的值并不受影响,因为它们并不是我们所说的eax与ecx,留在栈中的只是将a,b赋给eax和ecx后所留下的一个值拷贝。

最后在将结果送到eax寄存器中,通过寄存器带回函数的返回值。

(7)add函数的返回,

前三句是出栈,然后将ebp的值赋给esp使得esp下移

倒数第二句从栈顶弹出一个元素到ebp中,此时栈顶放的正好是main函数的ebp,然后回到main函数的栈帧,ret指令会使得出栈一次,并将出栈的内容作为地址,将程序执行跳转到该地址

009617C7  pop         edi  
009617C8  pop         esi  
009617C9  pop         ebx  
009617CA  add         esp,0C0h  
009617D0  cmp         ebp,esp  
009617D2  call        00961235  
009617D7  mov         esp,ebp  
009617D9  pop         ebp  
009617DA  ret

最后打印并输出

	printf("%d", c);
009625BD  mov         eax,dword ptr [ebp-20h]  
009625C0  push        eax  
009625C1  push        967BCCh  
009625C6  call        009613A2  
009625CB  add         esp,8  
	return 0;

这就是完整的函数栈帧创建和销毁过程。

图解c/c++语言底层:函数调用过程之函数栈帧的创建和销毁(上)(代码片段)

...的创建和销毁通过前面的学习,我们了解到最基础的C语言程序的语法与使用,但你是否有疑问?比如:函数的作用域是怎么形成的呢?局部变量是如何创建的?为什么未初始化的局部变量的值是随机值或... 查看详情

c语言的函数栈帧究竟是什么?你知道吗?(代码片段)

内容导读1.寄存器2.函数栈帧2.1函数栈帧的概述2.2函数栈帧创建过程2.2.1被调用的main函数2.2.2函数栈帧创建与销毁的过程前面的话:作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!博主的... 查看详情

深入理解c语言从函数栈帧角度理解return关键字(代码片段)

初识函数栈帧如上图可见,函数在被调用的时候会现在栈上开辟一个空间,我们称之为栈帧,之后函数内部的变量在这块区域进行空间开辟。但是函数在调用的时候,怎么知道需要开辟多大空间呢??࿱... 查看详情

c语言函数的栈帧

非静态局部变量如何在栈上分配?c语言中的函数是如何传参数?如何调用?如何返回的?(1)、sum01.c生成32位汇编程序,进行静态分析;(2)、将sum01.c编译连接成32位的可执行文件sum01.exe,然后拖入OD软件,在main函数入口出设置断... 查看详情

c语言深入逐汇编详解函数栈帧的创建和销毁过程(代码片段)

【C语言深入】逐汇编详解函数栈帧的创建和销毁过程一、图解大概过程二、函数栈帧的创建过程1、简介一些需要用到的汇编指令和寄存器2、调用main函数的函数3、局部变量的初始化4、形成临时拷贝5、函数调用6、形成栈帧7、提... 查看详情

c语言函数栈帧的创建和销毁,以简单函数的调用来进行详细刨析(代码片段)

...个寄存器和函数栈帧的创建和销毁密切相关。3、以汇编语言为例进行刨析我们以如下一个简单的加法实现代码的汇编语言为例来对问题展开分析,为使过程更加的清晰,我将代码的每一步都写的非常的细腻。代码如下... 查看详情

jvm内存区域之虚拟机栈(代码片段)

...的代码合来看下栈帧的出入栈过程。下面代码,在Main函数中调用methodA,执行完之后返回。publicclassTestpublicstaticvoidmain(String[]args)Testtest=newTest();test.methodA();publicvoidmethodA(intx,inty)inta=1;intb=a+x;intc=b+y;returnc;1... 查看详情

c语言进阶顶级神功!函数栈帧的创建和销毁(代码片段)

本章目录温馨提示开篇介绍学前疑惑学前准备1.环境选择2.知识铺垫正文开始1.大致轮廓了解(源代码及反汇编)2.函数栈帧的创建和销毁总流程3.函数栈帧的创建3.1main函数的创建(分解)3.2Add函数的创建(分解... 查看详情

c语言学习--函数栈帧的创建和销毁(代码片段)

前言在学习C语言的过程中,大家是否会存在一些困惑?比如:局部变量是如何创建的?为什么说局部变量未初始化时,其中存储的时随机值?函数到底时如何传参的?实参传递的顺序又是怎样的?... 查看详情

栈帧(代码片段)

C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。首先,栈是从高地址向低地址延伸的。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶... 查看详情

函数栈帧的创建与销毁(代码片段)

栈帧的创建与销毁什么是栈帧C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。首先应该明白,栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一... 查看详情

c语言函数调用模型(代码片段)

函数调用模型1.函数调用流程函数调用流程分析函数参数调用代码分析自右向左入栈顺序的优点2.调用惯例函数参数的传递顺序和方式栈的维护方式调用管理表3.函数变量传递分析分析图1.函数调用流程    栈(stack)是现代计算机... 查看详情

c语言函数调用模型(代码片段)

函数调用模型1.函数调用流程函数调用流程分析函数参数调用代码分析自右向左入栈顺序的优点2.调用惯例函数参数的传递顺序和方式栈的维护方式调用管理表3.函数变量传递分析分析图1.函数调用流程    栈(stack)是现代计算机... 查看详情

jvm内存区域之虚拟机栈(代码片段)

...的代码合来看下栈帧的出入栈过程。下面代码,在Main函数中调用methodAÿ 查看详情

c语言之main函数(代码片段)

一、概述一个c程序只有一个且必须有一个main函数,c程序的执行是从main函数开始的。main函数可以调用其他函数,包括本程序中定义的函数和标准库中的函数,但其他函数不能反过来调用main函数,main函数也不能调... 查看详情

学好c语言,还需要掌握这个内功——函数栈帧的创建与销毁(代码片段)

学习本篇文章之前,你或许还有这些疑问:局部变量是怎么创建的?为什么局部变量的值是随机值?函数是怎么传参的?传参的顺序是什么?形参和实参是什么关系?函数调用结束后怎么返回?看... 查看详情

函数栈帧详解(代码片段)

本文从汇编角度观察函数栈帧发生调用中的变化本文使用vs2013来讲述,并不建议使用vs2019等新版本,越新的版本函数栈帧相关越复杂什么是函数栈帧首先来了解一下:什么是函数栈帧?栈帧是指为一个函数调用单... 查看详情

c语言之函数详解(代码片段)

C语言函数!=数学函数在C语言当中,我们会经常用到函数,但是C语言当中的函数是一段代码块,也叫子程序。可以被其它函数调用,增加代码的复用性。C语言的函数分为库函数和自定义函数库函数库函数就是C... 查看详情