【转】C/C++函数调用过程分析

转自:here

这里以一个简单的C语言代码为例,来分析函数调用过程

代码:

#include <stdio.h>

int func(int param1 ,int param2,int param3)
{
        int var1 = param1;
        int var2 = param2;
        int var3 = param3;

        printf("var1=%d,var2=%d,var3=%d",var1,var2,var3);
        return var1;
}

int main(int argc, char* argv[])
{
        int result = func(1,2,3);

        return 0;
}

首先说明,在堆栈中变量分布是从高地址到低地址分布,EBP是指向栈底的指针,在过程调用中不变,又称为帧指针。ESP指向栈顶,程序执行时移动,ESP减小分配空间,ESP增大释放空间,ESP又称为栈指针。

下面来逐步分析函数的调用过程

1.函数main执行,main各个参数从右向左逐步压入栈中,最后压入返回地址

2.执行第15行,3个参数以从左向右的顺序压入堆栈,及从param3到param1,栈内分布如下图:

 3.然后是返回地址入栈:此时的栈内分布如下:

4.第3行函数调用时,通过跳转指令进入函数后,函数地址入栈后,EBP入栈,然后把当前ESP的值给EBP,对应的汇编指令

push ebp
mov ebp esp

此时栈顶和栈底指向同一位置,栈内分布如下:

5.第5行开始执行, int var1 = param1; int var2 = param2; int var3 = param3;按申明顺序依次存储。对应的汇编:

mov 0x8(%ebp),%eax
mov %eax,-0x4(%ebp)

其中将[EBP+0x8]地址里的内容赋给EAX,即把param的值赋给EAX,然后把EAX的中的值放到[EBP-4]这个地址里,即把EAX值赋给var1,完成C代码 int var1 = param1,其他变量雷同。

6.第9行,输出结果,第10行执行 对应的汇编代码:

mov  -0x4(%ebp),%eax

最后通过eax寄存器保存函数的返回值;

7.调用执行函数完毕,局部变量var3,var2,var1一次出栈,EBP恢复原值,返回地址出栈,找到原执行地址,param1,param2,param3依次出栈,函数调用执行完毕。图略

时间: 2024-10-07 20:07:33

【转】C/C++函数调用过程分析的相关文章

ARM函数调用过程分析

1.  ARM的栈帧    先来看看ARM的栈帧布局图:        上图描述的是ARM的栈帧布局方式,main stack frame为调用函数的栈帧,func1 stack frame为当前函数(被调用者)的栈帧,栈底在高地址,栈向下增长.图中FP就是栈基址,它指向函数的栈帧起始地址:SP则是函数的栈指针,它指向栈顶的位置.ARM压栈的顺序很是规矩,依次为当前函数指针PC.返回指针LR.栈指针SP.栈基址FP.传入参数个数及指针.本地变量和临时变量.如果函数准备调用另一个函数,跳转之前临时

【汇编总结3】函数调用

这块儿的知识长时间不用老是忘掉,本文依据<0Day安全:软件漏洞分析技术>第二章部分内容做个总结. 1. 函数调用约定 TODO 2. 函数调用过程分析 2.1 函数调用大致包括以下几个步骤 >1. 参数入栈: 根据函数调用约定将参数按照一定顺序依次压入系统栈中,最常用的就是从 右 往 左 压入栈中.这里可以思考下为什么要从右往左? 因为从右往左压入栈的话,被调函数里面取参数使用的时候,就是从左往右的顺序,一般而言 [EBP + 8] 就是第一个参数,[EBP+0xC]是第二个参数,比较

SSDT表详解

SSDT(system service dispatch table) 系统服务分派表 SSPT(system service parameter table) 系统服务参数表 #pragma pack(1)     //SSDT表的结构 typedef struct ServiceDescriptorEntry {     unsigned int *ServiceTableBase;     unsigned int *ServiceCounterTableBase; //Used only

8、C语言之函数

一.函数浅析 1.函数 函数是一个可以反复使用的程序段,从其它的程序段中均可以通过调用语句来使用这个程序段,完成既定的工作 说明: (1)建立函数称为"函数定义",使用函数称为"函数调用" (2)调用其它函数的函数称为"主调函数",而被调用的函数称为"被调函数" 一个实用的C语言源程序总是由许多函数组成,这些函数都是根据实际任务,由用户自己来编写,在这些函数中可以调用C提供的库函数,也可以调用由用户自己或他人编写的函数. 但是

linux-2.6.38poll机制简析(以tiny6410按键中断程序为基础)

一.应用程序 /* struct pollfd { int fd; //文件描述符 short events; //表示请求检测的事件 short revents; //表示检测之后返回的事件 }; */ int fd; struct pollfd fds[1]; // 只用poll函数来检测一个描述符 fd = open("/dev/tiny6410_button", 0); fds[0].fd = fd; //存放文件描述符 fds[0].events = POLLIN; //有数

从Spark-Shell到SparkContext的函数调用路径过程分析(源码)

 不急,循序渐进,先打好基础 Spark shell的原理 首先,我们清晰定位找到这几个. 1.spark-shell 2. spark-submit 3.spark-class  4.SparkSubmit.scala  5.SparkILoop.scala initializeSpark的源码 def initializeSpark() { intp.beQuietDuring { command(""" @transient val sc = { val _sc = o

S5PV210-kernel-内核启动过程分析

1.1.内核启动过程分析前的准备 1.拿到一个内核源码时,先目录下的无用文件删除 2.建立SI工程 3.makefile (1)makefile中不详细的去分析,几个关键的地方,makefile开始部分是kernel的版本号,这个版本号比较重要,因为在模块化驱动安装时会需要用到,要注意会查,会改,版本号在makefile中,改直接改的就行 (2)kernel顶层的makefile中定义的两个变量很重要,一个是ARCH,一个CROSS,ARCH表示我们当前的配置编译路径,如果我们的ARCH =AR

Android运行时ART执行类方法的过程分析

在前面一篇文章中,我们分析了ART运行时加载类以及查找其方法的过程.一旦找到了目标类方法,我们就可以获得它的DEX字节码或者本地机器指令,这样就可以对它进行执行了.在ART运行时中,类方法的执行方式有两种.一种是像Dalvik虚拟机一样,将其DEX字节码交给解释器执行:另一种则是直接将其本地机器指令交给CPU执行.在本文中,我们就将通过分析ART运行时执行类方法的过程来理解ART运行时的运行原理. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! 我们先来看

Android运行时ART加载OAT文件的过程分析

在前面一文中,我们介绍了Android运行时ART,它的核心是OAT文件.OAT文件是一种Android私有ELF文件格式,它不仅包含有从DEX文件翻译而来的本地机器指令,还包含有原来的DEX文件内容.这使得我们无需重新编译原有的APK就可以让它正常地在ART里面运行,也就是我们不需要改变原来的APK编程接口.本文我们通过OAT文件的加载过程分析OAT文件的结构,为后面分析ART的工作原理打基础. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! OAT文件