函数调用过程分析

函数调用过程分析

  在分析C语言函数调用过程之前我们有必要理解一下程序内存结构。内存空间被划分为:栈区(heap)、堆区(stack)、静态全局区、文字常量区以及函数代码区。(此处只是内存区域的大致划分,已经能够支撑后文将要讨论的内容)其结构如下图所示:
这里写图片描述
  栈区主要用于系统自动进行分配局部变量,函数形参空间。它位于内存中相对较高的位置,地址由高向低增长。(此处的堆栈与数据结构中的堆栈并不是一回事,要注意区分。)
  现在我们可以通过一个简单的Add函数调用来对其调用过程进行分析:

include<stdio.h>

int Add (int a,int b)
{
    int z = 0;
    z = a+b;
    return z;
}
int main()
{
    int a = 10;
    int b = 20;
    int sum = Add(10,20);
    printf("sum = %d ",sum);
    return 0;
}

这里写图片描述
  通过观察函数调用时堆栈我们可以发现,Add函数由main函数调用,main函数被 __tmainCRTStartup调用, __tmainCRTStartup则又被 mainCRTStartup函数调用。研究前我们需明白每一个函数都有自己的栈帧空间,并在自己的栈帧空间内进行变量的分配, 且当前正在运行的函数的栈帧总是位于栈顶。同时系统提供了ESP,EBP这两个寄存器分别用于记录函数调用时栈顶和栈底的位置
  由此我们可以得出main函数调用Add函数的堆栈示意图:
这里写图片描述
接下来分别对main函数以及Add函数的汇编代码进行分析:
Main函数:
这里写图片描述
根据对汇编代码的分析可通过画图进行更加直观的展现:
这里写图片描述
Add函数:
这里写图片描述
Add函数调用分析图示:
这里写图片描述

  通过以上对汇编代码的分析以及对内存的分配分析,整个函数的调用过程可总结为三步:
1)在栈中申请参数及函数体内定义的变量的内存空间
2)根据调用的函数名找到函数入口;
3)函数执行完后,返回值并释放函数在栈中的审请的参数和变量的空间

  除此之外,在分析过程中我们还需了解一些其他的寄存器:

  • eax 是”累加器”(accumulator), 它是很多加法乘法指令的缺省寄存器。
  • ebx 是”基地址”(base)寄存器, 在内存寻址时存放基地址。
  • ecx 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
  • edx 则总是被用来放整数除法产生的余数。
  • esi/edi分别叫做”源/目标索引寄存器”(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

      在对函数调用过程进行分析时,一些汇编指令是少不了的,常用到的有以下几个,可供平时学习:

  • sub:减法指令
  • lea:取偏移地址
  • push:实现压入操作的指令是PUSH指令
  • pop:实现出栈弹出操作
  • call:用于保存当前指令的下一条指令并跳转到目标函数。
  • mov :数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址(寄存器间的数据传送本质上也是一样的)

      以上就是对本次学习函数调用的总结,凡有不足之处欢迎批评指正,谢谢!

猜你喜欢

转载自blog.csdn.net/erica_ou/article/details/81224796