当前位置: 首页 > news >正文

80、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:栈空间对齐

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除

背景

接之前 blog
【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:栈指针和帧指针(上)
【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:栈指针和帧指针(下)
【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:r7 寄存器

分析了栈指针和帧指针的一些概念,并演示了栈帧的操作,并解释了为什么选择 r7 寄存器作为帧指针,下面最后再补充点细节

栈空间对齐

首先来回顾下栈空间操作的主要流程
在这里插入图片描述

  • 调用 push {r7, lr} 保存当前的帧指针(R7)和链接寄存器(LR),进入新的函数(main)时,需要保存旧的帧指针和返回地址,方便函数执行完后可以正确恢复现场并返回到调用者
  • 通过 sub sp, sp, #8 指令来减少栈指针的值,实际上是向栈上申请了 8 个字节的空间,这个空间可以用来存储局部变量或者作为临时存储区域,这里的 8 字节是根据函数内部需要保留的数据量来决定,后面会详细讨论这个
  • 在函数结尾,通过 adds r7, r7, #8 和 mov sp, r7 来释放之前分配的栈空间,并通过 pop {r7, pc} 恢复先前保存的 r7 寄存器状态,返回控制权到调用者

这里面有个细节,就是 sub sp, sp, #8 指令,这条指令向栈空间上申请了 8 个字节,下面来看下源码
在这里插入图片描述
在 main 函数这里,只有一个局部变量 c,在 32 位系统中,理论上只需要 4 个字节的空间,但是却分配了 8 字节空间,这里就涉及到了栈空间对齐,下面看下 AAPCS32 中对 栈空间对齐的官方描述

在这里插入图片描述

  • Universal stack constraints:所有时间点都必须满足栈指针 4 字节对齐(SP mod 4 == 0)
  • Stack constraints at a public interface:在函数调用入口处,还必须额外满足 8 字节对齐(SP mod 8 == 0)

下面再回过头来看刚才的栈空间操作流程,从对齐的视角来分析
在这里插入图片描述

  • 首先将 r7,lr 进行压栈,r7 和 lr 分别占用两个 4 字节,所以 SP 这里减了一个 8 字节
  • 由于只有一个 int 类型的局部变量,本来申请一个 4 字节空间足矣,但是必须要进行 8 字节对齐,所以这里 sub sp, sp, #8 申请了 8 字节空间

同样的,从对齐的视角,再来看 add_func
在这里插入图片描述

  • 首先将 lr 进行压栈(r7 不用压栈,之前的 blog 【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:叶子函数 有分析原因),lr 占 4 字节,所以 SP 减了 4 字节空间
  • 申请栈空间时,首先 add_func 里面有两个局部变量 a 和 b 需要存储,a 和 b 都是 int 类型的,都占 4 字节,加起来 8 字节,本来申请 8 字节空间足矣,但是前面压栈时,只压了 4 字节,4 + 8 = 12 字节,还未对齐到 8 字节空间,所以这里需对齐到 12 字节,4 + 12 = 16,所以指令 sub sp, sp, #12 向栈空间上申请了 12 字节内存

先分析到这里,下篇 blog 继续

http://www.lryc.cn/news/593606.html

相关文章:

  • Input输入和Screen相关
  • 轻松学习C++:基本语法解析
  • 从丢包到恢复:TCP重传机制的底层逻辑全解
  • 将HTML+JS+CSS数独游戏包装为安卓App
  • 微服务学习(六)之分布式事务
  • 华为擎云L420安装LocalSend
  • Java大视界:Java大数据在智能医疗电子健康档案数据挖掘与健康服务创新>
  • kafka--基础知识点--6.1--LEO、HW、LW
  • LeetCode Hot100【7. 整数反转】
  • 创意 C++ 文本冒险战斗游戏代码
  • Uniapp之自定义图片预览
  • 下一场范式革命:Transformer架构≠最终解法
  • Spring IOC容器在Web环境中是如何启动的(源码级剖析)?
  • Java多线程进阶
  • Node.js net.Socket.destroy()深入解析
  • [spring6: AspectMetadata AspectInstanceFactory]-源码解析
  • 零基础学习性能测试第二章-监控体系
  • OllyDbg技巧学习
  • Redis 如何保证高并发与高可用
  • Python爬虫实战:研究pefile库相关技术
  • PCB 混合介质叠层:材料特性匹配与性能提升的技术解析
  • 1. Spring AI概述
  • OSPF高级特性之Overflow
  • 【c++】提升用户体验:问答系统的交互优化实践——关于我用AI编写了一个聊天机器人……(12)
  • Buildroot vs Yocto:SDK 构建机制的核心差异与实践案例
  • 多线程 示例
  • QT窗口(8)-QFileDiag
  • esp32 sd卡
  • Kubernetes常用命令总结
  • MySQL 深度性能优化配置实战指南