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

88、【OS】【Nuttx】【启动】栈溢出保护:volatile 关键字(修饰内联汇编)

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

背景

接之前 blog
【OS】【Nuttx】【启动】栈溢出保护:volatile 关键字(修饰变量)
分析了 volatile 关键字对变量的修饰作用,下面再来看 volatile 关键字的下一个用法,也是之前分析栈溢出时语句的用法

volatile 关键字

还是回到这张图
在这里插入图片描述
上篇 blog 分析了 volatile 关键字修饰变量,表示这个寄存器变量的值可能会在任何时刻被意想不到的方式改变,在每次访问该变量时都要从内存中重新读取其值,而不是用存储在寄存器中的副本,那么上面这张图就是 volatile 关键字的另一个用法,修饰内联汇编语句

修饰内联汇编

来看下 gcc 官方文档对这块的描述
在这里插入图片描述
有几个点:

  • 扩展汇编语句的典型用途是对输入值进行处理,生成输出值,比如将 C 变量与汇编指令中的寄存器绑定
  • 但有些汇编语句也可能产生副作用,这些典型的副作用包括修改硬件状态,写入寄存器,改变内存,触发中断等,这些副作用是编译器感知不到,或者说判断不了是否有用的,此时编译器对这些汇编语句可能就会产生优化行为,比如删掉这段汇编代码
  • 此时就需要用 volatile 关键字来禁用掉编译器的某些优化,这些优化包括删除看起来没用的汇编语句,重排指令顺序,合并重复操作等等,尤其在汇编语句没有输出(但有副作用,比如写硬件寄存器)的情况下,编译器可能认为这条语句没用(注意这里是可能,不是一定,取决于编译器优化的保守程度),而把它优化掉,此时 volatile 关键字就会告诉编译器:这段汇编很重要,不要优化,一定要按顺序执行

下面对上面三个点再详细展开举例下

扩展汇编的典型用途

典型用途:将 C 变量与汇编指令中的寄存器绑定

这种用法比那种只有副作用的汇编语句相对来说更“安全”,因为编译器此时能感知到 C 变量在其中起作用了,但也只是相对的,取决于编译器的优化程度和保守程度,最佳的编程实践还是所有内联汇编语句都加上 volatile,明确告诉编译器不要优化

比如下面这段代码,就是 C 变量与内联汇编混用的典型场景

// main.c
#include <stdio.h>int main(void) {int src = 1;int dst;   __asm__ volatile("mov %1, %0\n\t" : "=r" (dst) : "r" (src));printf("%d\n", dst);
}

带有副作用的内联汇编

典型副作用:修改硬件状态,写入寄存器,改变内存,触发中断等

这些副作用对编译器来说相当于是未定义的,编译器对这些汇编语句可能产生优化行为,从用户使用角度来说,肯定是希望同一份代码能支持不同编译器,别编译器 A 编译后能保留这些汇编语句,换了编译器 B 这些汇编语句可能就被优化掉,所以最佳的实践还是都加上 volatile,明确告诉编译器不要优化

比如下面这段代码,不关联任何 C 变量,只对通用寄存器进行操作

// main.c
#include <stdio.h>int main(void) {__asm__ volatile ("sub r10, sp, %0" : :"r"(64) :);return 0;
}

在终端 bash 中输入命令(这里 --specs=nosys.specs 表示暂时不需要系统调用功能,告诉链接器忽略相关未定义的符号)

arm-none-eabi-gcc -mthumb -O3 -mcpu=cortex-m4 --specs=nosys.specs main.c -o main

再反汇编,终端输入

arm-none-eabi-objdump -d main > main.s

可以看到汇编语句中,可以看到最终的汇编语句明确保留了下来(不加 volatile 不是说一定会被优化,对 gcc 编译器来说,gcc 对 asm 处理比较保守,特别是当不能确定是否会有副作用时,对用户来说,加上 volatile 肯定是最佳的编程实践,就像家庭电气回路里的保险丝一样,你不知道它啥时候出现电流过载,加上是最保险的)
在这里插入图片描述

先到这里,下篇 blog 回到栈溢出继续

http://www.dtcms.com/a/310082.html

相关文章:

  • 15day-人工智学习-机器学习-介绍和定义
  • 【Linux】Linux下基本指令
  • 【暑期每日一题】洛谷 P9390 金盏花
  • SketchUp扩展工具分享:Ropefall v1.02插件轻松实现绳索模拟
  • 京东云轻量云服务器与腾讯云域名结合配置网站及申请SSL证书流程详解
  • 【Linux】磁盘存储+文件系统简介
  • android嵌套网页遇到的问题总结
  • mac系统自带终端崩溃修复
  • 使用自定义数据集训练 YOLOv12 以检测道路坑洞严重程度
  • 利用 AI 在 iPhone 上实现 App 文本情绪价值评估(上)
  • 基于Matlab的人眼虹膜识别门禁系统
  • 【Git 分支整合的艺术:岔路与归途的抉择 ——merge 与 rebase 深度解析】
  • Java函数式编程之【Stream终止操作】【下】【三】【收集操作collect()与分组分区和下游收集器】
  • 【MySQL】MySQL事务
  • 低空经济展 | 昂际智航携珑驭®系列产品亮相2025深圳eVTOL展
  • 向日葵软件提权
  • 第一篇:Linux 运维入门:虚拟机部署与基础环境配置
  • 《Java 程序设计》核心知识点梳理与深入探究
  • 工具Cursor(2)使用案例
  • 云函数编排深度解读:从概念到架构的全景指南
  • 计算声子谱
  • 详解K8s集群搭建:从环境准备到成功运行
  • 力扣面试150(46/150)
  • Spring AI MCP:解锁大模型应用开发新姿势
  • Idea快捷键
  • 从入仓到结算全自动化:易境通如何重构散货拼柜业务流程?
  • SpringBoot3.x入门到精通系列:1.3 创建第一个SpringBoot 3.x应用
  • LeetCode 刷题【24. 两两交换链表中的节点、25. K 个一组翻转链表】
  • Ubuntu 开启wifi 5G 热点
  • 数字孪生城市:以虚实映射为起点,开启城市全要素数字化转型新纪元