函数的递归调用


#include<stdio.h>

int sum(int a,int b)
{
         int tmp = 0;
         tmp = a+b;
         return tmp;
}
int main()
{
          int a = 10;
          int b = 20;
          int ret = 0;
      
           ret = sum(a,b);
           printf("ret = %d\n",ret);

           return 0;
}


上面的代码很简单,但是这里有几个问题:

1、函数调用函数,其栈帧开辟及回退过程是什么?

2、跳到sum函数执行,中间是怎么做到的?

3、执行完sum函数后,如何知道回到main函数?回到mian函数哪里执行?


要想弄清楚这些问题,就需要看汇编语言,有inter x86 和AT&T (Unix)两种,大体是一样的,只是前者从右向左看,后者从左向右看。其大致过程如下:




用两个寄存器表示栈,esp保存main函数这个栈帧的栈顶的地址,ebp保存main函数这个栈帧的栈底的地址(内核调用main函数的地址)。也可以看成指针。我们画出栈示意图,下边是栈底,高地址。



局部变量通过下标访问,例如[ebp-4]、[ebp-8]等。首先从main函数开始,变量入栈。sum函数入栈参数从右向左入栈。因为C/C++支持可变参函数,从左向右看不到一共有多少个参数,必须得遍历,从右向左可以计数,知道共有多少个参数。


参数入栈时,eax和ecx分别记录形参,然后入栈。call指令第一步把下一行指令的地址先入栈,第二步jmp跳转到sum函数。


sum函数开始前的指令做什么?

先把调用方函数的栈底地址放在当前函数的栈底内存中,mov 是移值  ,lea是移地址, ebp指针从调用方main函数栈底放到被调用方sum函数栈底,系统给sum开辟栈帧,rep stos是循环拷贝,这里循环拷贝cccccccc,栈帧初始化。这也就是为什么我们写程序没有给局部变量初始化,打印出来为“烫烫烫”的原因。这里可以确定形参内存开辟在调用函数的栈帧上开辟。


那sum函数是如何返回值的呢?

在“tmp=a+b”下面可以看到首先是把[ebp+8]给eax,然后add(加等)[ebp+c],也就是10+20放到eax中,返回时用eax把返回值带出来。最后pop出栈,ebp又回到main函数栈底,这也就是中间保存0x100的原因(这里是假设栈底地址为0x100)。


sum函数执行完后,又怎么知道从那里接着执行?

ret 这里就是出栈下一行指令地址,然后放到pc寄存器,这样CPU就知道sum函数结束后从哪里接着执行。


这就是函数调用函数的过程。


接下来看一下函数的返回值:

内置类型:char  short int  long   float  double

结构体

union

enum


小于等于4个字节,通过eax寄存器带出;

大于4个字节小于等于8字节,通过eax和edx两个寄存器带出;

大于8字节,函数调用之前产生临时量内存,再把临时量地址入栈,被调用函数return处通过[ebp+8]访问临时量。


函数调用约定:

_cdecl                 c调用约定                              调用方开辟形参内存,调用方释放形参内存

_stdcall      Windows标准的调用约定                调用方开辟形参内存,被调用方自己释放形参内存

_fastcall              快速调用约定                        调用方开辟形参内存,但是把最左边(也就是最后8字节的实参)通过                                                                           寄存器带入被调用函数中,被调用方自己释放

_thiscall      C++的成员函数的调用约定            


函数调用约定主要影响函数调用的三个方面:

1、函数产生的符号名字不同;

2、函数参数入栈顺序不同;

3、谁来清理形参的内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值