函数的调用--栈帧

对于函数的调用过程的了解层面你是否还停留在仅仅如下图所示的程度:
这里写图片描述

只知道大致过程而对于具体过程还不够了解,没有关系通过这篇博客,希望我们彼此都可以更深一层的了解函数具体的调用过程。

一. 什么是栈帧?

C语言中,每个栈帧对应着一个未运行完的函数,栈帧中保存了该函数的返回地址和局部变量。栈帧也叫过程活动记录,是编译器用来实现函数调用的一种数据结构。从逻辑上讲,栈帧就是一个函数执行的环境。
栈是从高地址向低地址延伸的。每个函数的调用的每一次调用,都有它自己独立的一个栈帧,这个栈帧保存着调用过程中所需要的各种信息。寄存器ebp指向当前栈帧的底部(高地址),寄存器esp指向当前栈帧的顶部(低地址)。

二. 我们用一个简单函数的调用来说明调用的过程

#include<stdio.h>
#include<stdlib.h>
int ADD(int x, int y)
{

    int z = 0;
    z = x + y;
    return z;

}
int main()
{
    int a = 10;
    int b = 15;
    int ret = 0;
    ret=ADD(a, b);
    printf("%d\n", ret);
    system("pause");
    return 0;
}

1.每一次函数的调用都要开辟空间,这块空间是由esp和ebp这两个寄存器来维护的。
2.push ebp
将ebp的值压到栈中,并且esp减小4个字节
3.mov ebp,esp
将esp的值给ebp
sub esp,0E4h
4. 用esp的值减去0E4h,esp变小,为main函数预开辟空间,用来存储函数内部定义的局部变量
5. push ebx
push esi
push edi
在栈顶压进去ebx、esi和edi,esp向上移动
6.lea edi,[ebp-0E4h]
mov ecx,39h
rep stos dword ptres:[edi]
从ebp-0E4h开始的位置向下拷贝eax中的内容0cccccccch ,39h次,每次拷贝4个字节
7.mov dword ptr [a],0Ah
mov dword ptr [b],0Fh
mov dword ptr [ret],0
将a、b和ret的值从栈底往上分别存储起来
8. mov eax,dword ptr [b]
push eax
mov ecx,dword ptr [a]
push ecx
call _ADD (0104112Ch)
add esp,8
mov dword ptr [ret],ea
将b的值给eax,将a的值给ecx,这里的a和b与main中的值虽然相同但是存储空间不一样,所以说函数调用过程中的形参是实参的临时拷贝。然后存储call指令下一条指令的地址,再将main函数的ebp存起来,以便函数调用完可以返回到main函数的栈空间。
9.push ebp
mov ebp,,0CCh
push esi
lea edi,[ebp-0CCh]
mov ecx,33h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
跳转到ADD函数,同之前main函数执行之前一样为ADD函数开辟空间并且进行初始化
10. mov dword ptr [z],0
将z的值存储起来
11.mov eax,dword ptr [x]
add eax,dword ptr [y]
mov dword ptr [z],eax
计算z=x+y;这里的x和y调用的是之前存储的形参,然后将25赋给z
11. pop edi
pop esi
pop ebx
函数调用完对自己所创建的栈空间进行销毁
12. mov esp,ebp
13.pop ebp
将刚才存储的ebp给esp,回到main函数的ebp,调用完ADD函数后回到main函数中调用ADD函数的位置继续执行下一条指令
如下图所示
这里写图片描述

猜你喜欢

转载自blog.csdn.net/liuwenjuan_cherry/article/details/79959144