0


c语言函数栈帧的创建和销毁

在学习C语言时,我们难免有许多疑问
(1)局部变量是怎么创建的?
(2)为什么局部变量的值是随机的?
(3)函数是怎么传参的?传参的顺序如何?
(4)形参和实参是什么关系?
(5)函数调用是怎么做的?
(6)函数调用结束后是怎么返回的?

接下来带你学习函数栈帧。

在vs底下各个版本略有差异,而今天带你学习的是vs2013

寄存器

一般计算机内

通用寄存器

包括eax,ebx,ecx,edx,esi,edi,esp,edp,其中

esp,ebp

这两个寄存器是用来存放地址的,这两个地址就是用来维护函数栈帧的

函数栈帧介绍

写一个简单的代码来详细介绍

int Add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}

int main()
{
    int a = 10;
    int b = 20;
    int c = 0;

    c=Add(a, b);

    printf("%d", c);
    return 0;
}

每一个函数调用,都要在栈区创建一个空间

而esp和ebp是来维护函数栈帧的

esp:栈顶指针

ebp:栈底指针

调试:

mainCRTStartup 函数调用 _tmainCRTStartup函数,

而 __tmainCRTStartup 函数调用 main 函数。

右击鼠标可以看到反汇编,就可以看到C语言的汇编代码:

push 压栈:给栈顶放上一个元素
pop 出栈:从栈顶删除一个元素

首先给__tmainCRTStartup开辟一块内存空间

然后mov,把esp给ebp。sub 给 esp 减去0E4h,而这块空间就是给mian函数开辟的空间。


接下来push压栈 ebx,esi,edi。

然后lea:load effective address(加载的意思)。把ebp-0E4h地址给edi。

然后mov,把39h给ecx,然后把ecx改成0CCCCCCCCh。

rep stos的39h个dword(4个字节)全部初始化0CCCCCCCCh。


到 int a=10;就是把0Ah(10的十六进制就是a)放到[ebp-8]

int b=20;把14h放到[ebp-14h]

int c=0;把0放到[ebp-20h]


Add(a,b);

mov,把ebp-14h给eax。然后push(压栈)eax。

mov,把ebp-8给ecx。然后push(压栈)ecx。

call指令调用函数(call指令的下一条指令进行压栈(记住),等调用完函数就会回来找到这个地址)


int Add(int x,int y);

为Add函数准备


z=x+y;

mov,把[ebp+8]给eax(值是10,前面已经传过来了)。

add,把[ebp+0Ch]的值(20)加给eax。

mov,把eax的值给ebp-8

从而可以知道形参根本不是函数内部创建的,而是call指令回来找到push的eax和ecx。

所以形参是实参的一份临时拷贝。


return z;

把[ebp-8]给eax寄存器,最后把edi,esi,ebx pop(弹出)。

空间回收,把ebp给esp。pop(弹出) ebp


ret

结束找回call指令的下一条指令,然后[esp+8]指向edi,形参销毁。eax给ebp-20h

标签:

本文转载自: https://blog.csdn.net/qq_57241128/article/details/119736966
版权归原作者 strbug 所有, 如有侵权,请联系我们删除。

“c语言函数栈帧的创建和销毁”的评论:

还没有评论