函数调用原理—栈帧

本文介绍了栈帧的背景知识,包括栈的生长方向、寄存器ebp和esp的作用。函数调用通过call指令保存当前指令地址并跳转,return指令恢复调用状态。以一个例子阐述了栈帧的开辟和恢复过程,以及函数调用时栈帧如何覆盖及恢复,最后提到了函数调用过程中的栈帧结构图。

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

         关于栈帧的背景知识

       栈在地址空间中是向下生长,向下生长是指是从内存高地址到低地址的路径延伸,栈有栈顶和栈底,所以栈顶的地址要比栈底的地址低,对于x86体系的CPU而言,其中寄存器ebp可称为“帧指针”或“基底指针”,通常指向栈底,寄存器esp可称为“栈指针”,通常指向栈顶。

       ebp在未受改变之前始终指向栈帧的开始,也就是栈底。所以ebp的用途是在C堆栈中寻址用的。esp是会随着数据的入栈和出栈移动的,也就是说,esp始终指向栈顶。

       在CPU内部还存在一种寄存器——PC指针,它指向正在执行指令的下一条指令的地址。CPU工作时,通过调用的函数分别完成三个步骤取指令,分析指令,执行指令。PC指针又称程序计数器,指向正在执行指令的下一条指令。

       call:1.保存当前执行指令的下一条指令的地址。2.跳转到目标函数。

       return:当调用函数时,保留PC,ebp,esp指针,调用完毕后,恢复PC,ebp,esp指针。    

       下面我将举个例子来对栈帧进行讲解:

define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>


int fun(int x, int y)
{
    int c = 0xcccccccc;
    return c;
}

int main()
{
    int a = 0xaaaaaaaa;
    int b = 0xbbbbbbbb;
    int ret = fun(a, b);
    printf("you should running here!\n");
    system("pause");
    return 0;
}
(1)在main函数中调用fun函数,先将main函数的堆栈的栈底指针ebp入栈,保存之前任务的信息。
(2)然后将main函数的栈顶指针esp的值赋给ebp,作为新的基址,也就是fun函数的栈底。

(3)在这个基址(被调用fun函数的栈底)上开辟相应的空间用作被调用fun函数的栈空间,开辟时一般用sub指令。

(4)fun函数返回后,从当前栈帧的ebp即恢复为main函数的栈顶(esp),使栈顶恢复fun函数被调用前的位置,然后main函数再从恢复后的栈顶可弹出之前的ebp值,可以这么做是因为在调用fun函数之前保存了main函数的ebp,使得ebp恢复为调用fun函数之前main函数的栈底。这样,ebp和esp就都恢复了调用fun函数前的位置,也就是栈恢复fun函数调用前的状态。

函数调用过程栈帧结构图:


注意:这里当fun函数栈帧结构形成时,就会覆盖main函数的栈帧,当调用完成后,main函数的栈帧结构又会恢复。

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值