函数的调用过程(栈帧)

本文详细解析了C语言中函数调用的过程,包括栈帧的创建与维护、寄存器的作用及局部变量的处理等内容,并通过具体示例加深理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随着c语言学习的深入,慢慢的对函数的调用有了些了解,为了更深层次的理解函数的调用,特此写了一篇博客,希望与大家交流学习,弥补自己的不足。

我们知道每一次的函数调用都是一个过程,而我们讲这个过程称之为(函数的调用过程
这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存、现场保护。我们将这块栈空间称之为(函数栈帧
*注意*:由于使用的编译器不同,产生的效果有所差异。我使用的是VS2013
下面我们来看一段代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}
int main()
{
    int a = 10;
    int b = 20;
    int ret = Add(a, b);
    printf("ret=%d\n", ret);
    system("pause");
    return 0;
}

在栈帧的维护我们要了解ebp和esp两个寄存器。在函数调用的过程中这两个寄存器存放了维护这个栈的栈底和栈顶指针
这里写图片描述

首先我们来看main函数栈帧的创建


    int main()
{
000E1410  push        ebp                  1
000E1411  mov         ebp,esp              2
000E1413  sub         esp,0E4h             3
000E1419  push        ebx                  5
000E141A  push        esi                  .
000E141B  push        edi                  .
000E141C  lea         edi,[ebp-0E4h]       6
000E1422  mov         ecx,39h              .
000E1427  mov         eax,0CCCCCCCCh       .
000E142C  rep stos    dword ptr es:[edi]   .
    int a = 10;                            6
000E142E  mov         dword ptr [a],0Ah    .
    int b = 20;                            .
000E1435  mov         dword ptr [b],14h    .
    int ret = Add(a, b);                   7
000E143C  mov         eax,dword ptr [b]    .
000E143F  push        eax                  .
000E1440  mov         ecx,dword ptr [a]    .
000E1443  push        ecx                  .
000E1444  call        _Add (0E10E1h)       8
000E1449  add         esp,8                .
000E144C  mov         dword ptr [ret],eax  9
printf("ret=%d\n", ret);

1、
000E1410 push ebp
//将ebp压栈处理,ebp储存指向栈底的地址,方便函数返回的恢复
2、
000E1411 mov ebp,esp
//将esp的值赋给ebp,产生新的ebp
3、
000E1413 sub esp,0E4h
//给esp减去一个16进制数字0E4h
4、
000E1419 push ebx
000E141A push esi
000E141B push edi
// ebx esi edi 依次进栈,esp的位置随之依次上升
5、
000E141C lea edi,[ebp-0E4h]
000E1422 mov ecx,39h
000E1427 mov eax,0CCCCCCCCh
000E142C rep stos dword ptr es:[edi]
//这四条指令是将栈帧预开辟空间全部初始化为0CCCCCCCCh
6、
int a = 10;
000E142E mov dword ptr [a],0Ah
int b = 20;
000E1435 mov dword ptr [b],14h
//处理局部变量a,b的创建
7、
int ret = Add(a, b);
000E143C mov eax,dword ptr [b]
000E143F push eax
//将传给Add函数的参数b赋给eax,然后再压栈
000E1440 mov ecx,dword ptr [a]
000E1443 push ecx
//将传给Add函数的参数b赋给ecx,然后再压栈
8、
000E1444 call _Add (0E10E1h)
//call指令的调用,要先进行压栈
000E1449 add esp,8
//call指令下一条指令的地址,然后跳转到ADD函数的地址,调用完函数又要返回到这个地址
9、
000E144C mov dword ptr [ret],eax
//将返回的值赋给ret
printf(“ret=%d\n”, ret);

000E1455 push 0E5858h
这里写图片描述
以上介绍了函数的赋值,函数的初始化,调用的新的函数的过程
.
.
.
.
.
下面介绍Add函数栈帧的创建


int Add(int x, int y)
{
000E13C0  push        ebp             1
000E13C1  mov         ebp,esp  
000E13C3  sub         esp,0CCh  
000E13C9  push        ebx  
000E13CA  push        esi  
000E13CB  push        edi  
000E13CC  lea         edi,[ebp-0CCh]  
000E13D2  mov         ecx,33h  
000E13D7  mov         eax,0CCCCCCCCh  
000E13DC  rep stos    dword ptr es:[edi]  2
    int z = 0;
000E13DE  mov         dword ptr [z],0     3
    z = x + y;
000E13E5  mov         eax,dword ptr [x]   4
000E13E8  add         eax,dword ptr [y]   .
000E13EB  mov         dword ptr [z],eax   5
    return z;
000E13EE  mov         eax,dword ptr [z]   6
}
000E13F1  pop         edi  
000E13F2  pop         esi  
000E13F3  pop         ebx  

1—>2过程类似,在此不在重复、
3、
000E13DE mov dword ptr [z],0
//创建变量z
4、
000E13E5 mov eax,dword ptr [x]
000E13E8 add eax,dword ptr [y]
//获取形参的a和b,并相加
5、
000E13EB mov dword ptr [z],eax
//将结果储存到z中

6、
000E13EE mov eax,dword ptr [z]
//将结果存储到eax寄存器,通过寄存器待会函数的返回值
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值