• 函数栈的变化过程


    C++调用函数在内存管理中的过程就是新建一个函数栈,里面保存了函数返回值,寄存器的备份(rbp),局部变量,函数参数。调用结束后栈空间销毁,回到调用的函数继续执行下面的代码。

    在这里插入图片描述

    下面说几个要点。
    首先要了解寄存器的作用。
    rbp保存函数栈底指针,rsp保存函数栈顶指针,
    rdi、rsi、rdx、rcx、r8、r9:调用函数时依次存放第1到第6个参数,若多于6个的参数则会被压入栈。
    rip保存返回地址。
    rax保存返回值。

    我们从调用开始到调用结束一步步分析一下:(假设main函数调用add函数)
    当我们调用函数时,栈的变化如下:
    1、首先,会将原函数main函数的返回地址压入栈中,返回地址就是add函数下一条指令的地址,因为函数返回后就要执行这个指令了。
    2、将原函数main的rbp栈底指针入栈,因为函数返回后还要维护main函数的栈底指针,main函数并没有执行完成。
    3、将栈顶指针rsp的值赋给rbp,然后将栈顶指针减去一定的数值,为新的函数开辟空间。这里要注意,栈顶指针永远指向栈顶,所以当把rsp赋给rbp时,rbp已经指向原来main的栈顶+返回地址+main的rbp了那个位置了。

    4、上面都是准备工作,接下来就是在那段空间进行一系列操作。比如存储函数参数的值(movl $1 %rbp-4就是将参数1放到栈底的上一个位置,栈是高地址向低地址增长的,所以要减),将值赋给寄存器等。如果有返回值,返回值会放到eax寄存器中。
    5、栈中弹出main函数栈的rbp地址,赋值给rbp寄存器,即恢复main函数的rbp.
    6、leave,RET退出调用。ret指令则是将栈顶的返回地址弹出到EIP,然后按照EIP此时指示的指令地址继续执行程序。leave指令相当于将rbp赋给rsp,并把rbp出栈,将里面的值赋给rbp寄存器(相当于步骤5)
    可以看到5,6和2,1是配对的,因为栈是后进先出。
    7.最后还可能有返回值,从eax取出赋给main函数的局部变量处,将eax置零。

  • 相关阅读:
    YOLOv8改进实战 | 更换主干网络Backbone之2023最新模型LSKNet,旋转目标检测SOTA
    高频:spring知识
    [刷题记录]牛客面试笔刷TOP101(二)
    【Spring Boot项目】个人在线音乐播放器
    Hudi 在 vivo 湖仓一体的落地实践
    vuex和pinia
    墨西哥FBA海运头程货代,墨西哥海运几天到?
    【测试开发】用例篇 · 熟悉黑盒测试用例设计方法(1)等价类划分法、边界值法、判定表法
    Socks5代理、IP代理的关键作用
    【联邦学习】联邦学习的量化传输仿真(一)
  • 原文地址:https://blog.csdn.net/weixin_53344209/article/details/126720487