• 函数调用堆栈详细过程


    以下面的程序为例:

    #include
    
    using namespace std;
    
    int  sum(int a,int b)
    {
    	int temp=0;
    	temp=a+b;
    	return temp;
    
    }
    int main()
    {
    	int a=10;
    	int b=20;
    	int ret=sum(a,b);
    	cout<<ret<<endl;
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    问题1:main函数调用sum,sum执行完后,怎么知道回到哪个函数中?
    问题2:sum函数执行完,回到main后,怎么知道从哪行指令开始运行。

    要描述一个栈,需要知道栈底和栈顶就可以了。其中esp来标识栈顶,ebp来标识栈底。(栈是从高地址向低地址增长的,所以ebp要比esp的地址大)

    1)假设mian函数的栈帧是:

    …esp
    ret
    b 10
    a 20
    …ebp0–0x0018ff40

    2)然后就是对sum函数的参数进行压栈:

    …esp
    10=》int a
    20=》int b
    ret
    b 10
    a 20
    …ebp0–0x0018ff40

    3)需要注意的是sum的参数的压栈顺序是从有向左压栈。

    上述压栈完毕后,进行call sum,call sum做的第一件事就是,将call的下一行指令的地址进行压栈(解决了上面的问题二)!然后第二件事情才是进入sum。这里假设call指令的下一行代码的地址是0x08124458。过程如下:

    …esp
    0x08124458
    10=》int a
    20=》int b
    ret
    b 10
    a 20
    …ebp0–0x0018ff40

    4)进入sum函数后,在执行sum中的代码之前,要进行一些前处理:就是要将mian函数的栈帧即main的ebp压栈,然后开辟新的栈也就是sum的栈:

    …esp

    …ebp
    0x0018ff40
    0x08124458
    10=》int a
    20=》int b
    ret
    b 10
    a 20

    5)然后开始执行sum中的代码:

    需要注意的是,temp=a+b的这一行代码,汇编指令中会有特殊的地址偏移,在栈上找到a和b的值。然后return temp这一行代码,是将temp的值放在了全局的eax寄存器上。
    只有定义局部变量或者函数调用的时候才会进行压栈操作,其余的计算过程和return操作是不会在栈上体现的。
    …esp

    temp 0
    …ebp
    0x0018ff40
    0x08124458
    10=》int a
    20=》int b
    ret
    b 10
    a 20

    6)执行完sum后,会进行栈帧的回退,首先,将esp的位置放到ebp的位置,然后执行栈的pop,pop出的地址值就是mian函数的ebp!将这个值赋给ebp,至此,就回到了mian的栈帧中:

    …esp
    0x08124458
    10=》int a
    20=》int b
    ret
    b 10
    a 20
    …ebp–0x0018ff40

    7)然后开始继续运行,首先要找到mian中继续运行执行,方式就是执行一次栈的pop,将这个地址放入CPU的PC寄存器中。完毕后,栈的内容大概是:

    …esp
    10=》int a
    20=》int b
    ret
    b 10
    a 20
    …ebp–0x0018ff40

    8)然后程序开始从0x08124458开始执行,0x08124458中往往会有一个 add esp ,8 ,然后再是其他的 。这就会把esp加8个字节,也就是出栈两次,将栈中压入的sum的参数出栈,此时:

    …esp
    ret
    b 10
    a 20
    …ebp–0x0018ff40

    9)之后就交给指令了,这些指令会将eax寄存器的值赋给ret。完成sum函数的调用!!

    …esp
    ret 30
    b 10
    a 20
    …ebp–0x0018ff40

    下面回答问题1:问题1:main函数调用sum,sum执行完后,怎么知道回到哪个函数中?
    就是通过压栈的顺序。

    (未完待续,见视频)

  • 相关阅读:
    IMX6ULL学习笔记(6)——通过USB OTG烧录U-Boot(MfgTool工具)
    JavaWeb----Ajax技术
    如何策划好一场商直播
    zabbix监控,zabbix部署
    游戏服务器频繁遭到攻击是什么原因?
    C语言力扣第43题之字符串相乘。优化竖式
    【Koltin Flow(五)】SharedFlow及StateFlow
    flask要点与坑
    [附源码]java毕业设计图书管理系统论文
    VR数字展厅在企业中应用的优势有哪些?
  • 原文地址:https://blog.csdn.net/luseysd/article/details/127601279