关键词:
一.前言
每一次函数调用都是一个过程。这个过程我们通常称之为:函数的调用过程。
这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存,现场保护。这块栈空间就是函数栈帧。
实验代码:
#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... 查看详情