使用 volatile 破坏系统代码的九种方法

2023-05-16

首先怼上:
It’s hard to overstate how bad an idea it is for a compiler to use strange heuristics about code structure to guess the developer’s intent.
编译器使用奇怪的试探法来猜测开发人员的意图,这个想法有多糟糕,怎么强调都不为过。

 
 

1 两个典型用法

(1)

#define TCNT1 (*(volatile uint16_t *)(0x4C))
signed char a, b, c;
uint16_t time_mul (void) {
  uint16_t first = TCNT1;
  c = a * b;
  uint16_t second = TCNT1;
  return second - first;
}

(2)

volatile int done;
__attribute((signal)) void __vector_4 (void) {
  done = 1;
}
void wait_for_done (void) {
  while (!done) ;
}

这个attribute signal我搜了一下,他要求两点:
1.中断退出时,必须恢复使用过的寄存器。
2.使用RETI退出中断,而不是RET。AVR单片机进入中断会关闭中断,退出时使用RETI重新开启中断。

 
 

2 volatile使用的太多了

(1)volatile可能会隐藏bug,比如并发问题。
(2)用的太多会导致编译器优化效率下降。
(3)它引入的开销很难被追踪到,因为已经分散在系统各个位置了。
(4)不写文档说明,别人很难意会你用volatile的用意。。。

建议,只有在你非常明确要使用volatile时才使用,别瞎鸡儿用。

 
 

3 限定符放错位置

volatile限定符遵守的规则和const类型。
那么就有如下情况:

int *p;                              // pointer to int
volatile int *p_to_vol;              // pointer to volatile int
int *volatile vol_p;                 // volatile pointer to int
volatile int *volatile vol_p_to_vol; // volatile pointer to volatile int

注意区分指针是volatile的,还是目标地址是volatile的。
如果是目标地址volatile,我们可以进行typedef如
typedef volatile int vint
进而使用它定义变量,就不易混淆了(???)
vint *REG = 0xFEED;

struct/unio也可以是volatile的,则它所有的成员也都是volatile的。

这种情况非常特殊:
const volatile int *p
const代表我不会store to it而不是它不会改变。
所以这种使用方法很有用,比如定义一个会自动变化的timer时,我们不会向他存储,但是需要每次得到更新后的数据。这个定义在C标准中是明确指出的。

 
 

4 不一致的限定符

1、
c文件中使用定义如下
volatile unsigned long ipi_count;
但是在头文件中却这样声明,
extern unsigned long ipi_count;
最新版本的GCC对这样的情况会报错。
但是一些嵌入式编译器不会。

 
2、
隐式类型转换,把一个volatile指针,传递给一个函数,但它的参数并没有volatile限定符。
这会导致编译器警告。
显式类型转换,不会警告,在C语言标准中,这是未定义行为。

Summary: Never use inconsistent qualification.
If a variable is declared as volatile, then all accesses to it, direct or indirect, must be through volatiles and pointers-to-volatile.

 
 

5 volatile变量和非volatile变量在一起时,必须强调访问顺序

volatile int ready;
int message[100];
void foo (int i) {
  message[i/10] = 42;
  // asm volatile ("" : : : "memory");
  ready = 1;
}

编译器会把ready的赋值搞到message赋值之前,这就会导致bug。(大多数编译器都会这样做!)
有一个方法可以避免这样情况,就是给message也加上volatile。但是在整个程序当中,这会减少很多优化。

我们需要的是一个编译器屏障compiler barrier
C标准没有定义这个,但是很多编译器都有定义。
asm volatile ("" : : : "memory");
这条指令之前的内存读写,不会搞到这条指令之后。
这条指令之后的内存读写,不会搞到这条指令之前。
编译器屏障是对编译器读写指令重排序而言的,内存屏障是对处理器指令重排序而言的。

 
 

6 volatile不能保证原子性,应该用锁

A volatile read or write of a 32-bit int is atomic on most modern hardware, but volatile has nothing to do with it.
32位对齐的访问在现代处理器上,是原子性的,但是跟volatile没有关系。
 
锁也要阻止编译器重排序,(那两行内联汇编)
这是AVR单片机中TinyOS里的例子,用于获取、释放全局的中断锁,

char__nesc_atomic_start(void) {
  char result = SREG;
  __nesc_disable_interrupt();
  asm volatile("" : : : "memory");
  return result;
}
void __nesc_atomic_end(char save) {
  asm volatile("" : : : "memory");
  SREG = save;
}

因为这俩函数通常是inline的,可能出现在任何位置。

 
 

7 volatile多处理器情况下,作用有限

volatile对于指令重排序、多处理器的情况,作用是有限的。
它只规定要去内存读写数据,而没有限定硬件的具体行为。

ARM Linux里的自旋锁:

static inline void arch_spin_unlock(arch_spinlock_t *lock) {
  smp_mb();
  __asm__ __volatile__("str %1, [%0]\n" : : "r" (&lock->lock), "r" (0) : "cc");
}
在解锁之前,smp_mb先执行。

多处理器内存屏障smp_mb可以简单描述为
__asm__ __volatile__ ("dmb" : : : "memory");
它即是编译器优化的屏障,也是内存屏障。

Summary: Without help from properly designed synchronization libraries, writing correct concurrent code on an out-of-order machine or multiprocessor is extremely hard, and volatile is of little help.
不使用同步库代码,直接在乱序CPU和多处理器上解决并发问题,非常难,volatile作用很小。

 
 

8 多线程中的volatile没有任何卵用

乱用,只会导致编译器无法优化代码,使程序变慢。

Arch Robison says that volatile is almost useless for multi-threaded programming.
这哥们儿好像是《结构化并行程序设计》这本书的作者。

 
 

9 编译器无视volatile的情况

volatile int x;
void foo (void) {
  x = x;
}
我想load这个x然后存回到它自己。
MSP430编译器说滚:
$ msp430-gcc -O vol.c -S -o -
foo:
  ret

GCC 4.0之后的版本会修正这个问题,但是之前的版本都会说滚。

 
 

原文地址: Nine ways to break your systems code using volatile

 
 

Linus祖师爷说

原文地址: volatile considered evil

The only acceptable uses for “volatile” are:

  • in -code-, i.e., for things like the definition of “readb()” etc, where we use it to force a particular access.
  • with inline asm
  • on “jiffies”, for stupid legacy reasons(it’s like a random number)
     

The only thing they do is(使用volatile的人)

  • potentially make the compiler generate worse code for no reason (the “no reason” being that if there aren’t any barriers in between, the compiler -should- merge accesses合并内存访问)
  • make some people -believe- that that compiler does something “right”.
     
I suspect we should just face up to the fact that:1"volatile" on kernel data is basically always a bug, and you should 
     use locking. "volatile" doesn't help anything at all with memory
     ordering and friends, so it's insane to think it "solves" anything on
     its own.
     在内核中别用volatile2)on "iomem" pointers it does make sense, but those need special
     accessor functions -anyway-, so things like test_bit() wouldn't work
     on them.
     人家test_bit确实需要每次都访问内存,但是人家依赖的是原子操作。
     
(3if you spin on a value [that's] changing, you should use "cpu_relax()" or
     "barrier()" anyway, which will force gcc to re-load any values from
     memory over the loop.
     如果你在用自旋锁,你反正是要用cpu_relax()或者barrier()它们都会强制GCC做一次对内存的重新加载。
     跟volatile更没关系。

 
 
 
完。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 volatile 破坏系统代码的九种方法 的相关文章

  • (ROS)差分轮式机械臂机器人(二)六轴机械臂Moveit配置&深度相机kinect配置

    上一次搭建出了差分式移动底盘和六轴机械臂 这一次总结机械臂的Moveit配置和底盘kinect深度相机配置 文章目录 项目源码机械臂Moveit配置Moveit具体是什么可以参考 古月居的视频教程 https www bilibili co
  • 操作系统--线程

    线程 什么是是线程 进程中的一条执行流程 线程的优点 一个进程可以同时存在多个线程各个线程之间并发执行各个线程之间共享地址空间和文件等资源 线程的缺点 一个线程崩溃将导致其余所有线程崩溃 线程所需的资源 进程与线程的比较 线程的实现 用户线
  • ros底盘驱动包存在scan跟不上车体运行的错误调试过程

    现象描述 一个和底盘通讯的代码和ros包 总是发现当控制车体运行一段距离 rviz里面scan的数据更新会过一秒才能跟着运动走 同时发现tf的base link也是过一秒才更新 调试过程 起初 以为是串口堵塞 没有及时的接受和处理底盘上行发
  • 变频器电路原理详解经典

    要想做好变频器维修 xff0c 当然了解变频器基础知识是相当重要的 xff0c 也是迫不及待的 下面我们就来分享一下变频器维修基础知识 大家看完后 xff0c 如果有不正确地方 xff0c 望您指正 xff0c 如果觉得还行支持一下 xff
  • UART模块验证-面试总结

    前言 本篇博客依旧针对UART模块的验证项目进行面试总结 xff0c 也是笔者面试过众多公司所总结整理的 关于UART深挖的可问的知识点还是非常多 xff0c 本篇博文可以说基本上涵盖大部分可问到的点 关于下列有一些问题我并没有列出答案 x
  • 你所不知道的C语言——链表内是否有环(龟兔赛跑算法)

    判断链表中是否有环 xff0c 这也是力扣的题 xff1a 141 Linked List Cycle 142 Linked List Cycle II 146 LRU缓存 不多比比 xff0c 直接上代码 xff1a 变量 mu 指的是
  • 古诗文本自动生成唐诗文本生成(算例代码)

    首先准备好一个本地文件 xff0c 在此我命名为唐诗三百首 txt如下图 https img blog csdnimg 图片 代码如下 span class token keyword import span numpy span clas
  • __attribute__ 你知多少?

    GNU C 的一大特色就是 attribute 机制 attribute 可以设置函数属性 xff08 Function Attribute xff09 变量属性 xff08 Variable Attribute xff09 和类型属性 x
  • ChatGPT被淘汰了?Auto-GPT到底有多强

    大家好 xff0c 我是可夫小子 xff0c 关注AIGC 读书和自媒体 解锁更多ChatGPT AI绘画玩法 说Auto GPT淘汰了ChatGPT了 xff0c 显然是营销文案里面的标题党 毕竟它还是基于ChatGPT的API xff0
  • Word+ChatGPT,一分钟完成周报总结作文

    大家好 xff0c 我是可夫小子 xff0c 关注AIGC 读书和自媒体 解锁更多ChatGPT AI绘画玩法 加 xff1a keeepdance xff0c 备注 xff1a chatgpt xff0c 拉你进群 Office 的办公软
  • 两分钟速览谷歌2023IO大会:AI军备竞争,全线出击

    大家好 xff0c 我是可夫小子 xff0c 关注AIGC 读书和自媒体 解锁更多ChatGPT AI绘画玩法 加 xff1a keeepdance xff0c 备注 xff1a chatgpt xff0c 拉你进群 5月10日周三 xff
  • 科大讯飞星火认知大模型:诚意满满、全村希望

    近日 xff0c 科大讯飞召开了星火认知大模型成果发布会 xff0c 会上表示讯飞星火大模型将突破开放式问答 xff0c 对标ChatGPT xff0c 在中文能力上超过ChatGPT xff0c 在英文能力上与ChatGPT相当 对此 x
  • Android NDK tombstone分析工具

    Android NDK tombstone分析工具 在Andoird Native库发生异常的时候 xff0c Linux会发生不同级别的sig xff0c 来结构相关进程的运行 xff0c 同时会产生tombstone trace文件用于
  • 关于UEFI

    最近在Thinkpad上安装Ubuntu12 04的时候 xff0c 经历了几个问题 xff0c 发现BOIS里多了很多选项 xff0c 而且安装双系统也有UEFI有关 xff0c 在网站上找了一篇文章 xff0c 发现这还是一个新概念 x
  • 怎样在github上协同开发

    描述 xff1a How to co work wither parter via github Github协同开发情景模拟 Github不仅有很多开源的项目可以参考 xff0c 同样也是协同开发的最佳工具 xff0c 接下来的就模拟一下
  • Android libdvm.so 与 libart.so

    Android libdvm so 与 libart so 系统升级到5 1之后 xff0c 发现system lib 下面没有libdvm so了 xff0c 只剩下了libart so 对于libart模式 xff0c 从4 4就在De
  • 链表快速排序quick-sort(递归+迭代)

    递归版 直接上代码 span class token keyword static span span class token keyword void span span class token function list qsort s
  • 反向代理--解决跨域问题

    为什么要解决跨域问题 xff1a 因为浏览器有限制 xff0c 只有同域名同端口号下的数据才能拿来用 xff1b 那如果想拿到不同域名不同端口号下的数据就不行了 xff1b 在单文件组件中如何去解决跨域问题 xff1a 因为服务器没有跨域限
  • 写在2011

    很早就想写点东西了 xff0c 可晃荡晃荡地就到了2011年最后一刻 我想是要写点东西了 2011年 xff0c 我有太多的感触 这一年是我第一次在异地迎接农历新年了 xff0c 对 xff0c 当时的感觉很刺激 xff0c 刺激得让我和当
  • Translate Aticle

    最近在Thinkpad上安装Ubuntu12 04的时候 xff0c 经历了几个问题 xff0c 发现BOIS里多了很多选项 xff0c 而且安装双系统也有UEFI有关 xff0c 在网站上找了一篇文章 xff0c 发现这还是一个新概念 x

随机推荐

  • Window64位系统用HSDIS对java代码进行反编译

    1 下载hsdis amd64 dll文件并放入 JAVA HOME jre bin中 xff0c 例如 xff1a C Program Files Java jdk1 8 0 191 jre bin 书上说的是放在 JAVA HOME j
  • golang中的context

    一 Context含义 1 context定义 context是golang中的上下文 goroutine的相关环境快照 xff0c 其中包含函数调用以及涉及的相关的变量值 golang通过Context机制解决一个request中多个go
  • Win10部署Authelia(OAuth2授权框架)

    一 安装docker 二 下载authelia代码 span class token comment 下载代码并切换到本地运行例子 span span class token function git span clone https gi
  • golang并发学习及实战记录

    一 切片append方法不是原子操作 多个协程操作同一个切片 xff0c 使用append方法添加元素时 xff0c 存在并发安全问题 xff0c 需要对append方法加锁 span class token keyword func sp
  • Jetson TX1/TX2搭载RTSO-9003载板刷机及使用JetPack3.3安装软件教程(防踩坑)

    1 烧录Linux系统 1 1 系统要求 最好给主机电脑安装Ubuntu14和Ubuntu16 x86 64系统 Ubuntu18系统不能运行JetPack3 3软件 xff0c 且JetPack3 3安装软件必须在主机Host x86 6
  • Ubuntu系统下ROS安装说明

    1 准备工作 安装前看看有什么更改Ubuntu默认的更新源 xff0c 如果更改了 xff0c 要换回备份的默认的安装源 xff08 etc apt sources list bak xff09 权限设置 用户需要成为 拨出 组的一部分 x
  • 腾讯云服务器上搭建Hadoop伪分布式教程

    1 登陆腾讯云服务器控制台查看内网ip地址 2 更改主机名 修改master ip地址 xff0c 地址改为内网地址 vi etc hosts 172 21 0 修改主机名 vi etc hostname master 重启服务器 rebo
  • 时间序列(二)数据重采样

    数据重采样 时间数据由一个频率转换到另一个频率 降采样 升采样 生成一条带随机值的时间序列 rng 61 pd date range span class hljs string 39 1 1 2011 39 span periods 61
  • linux lib/list_sort.c排序算法

    linux lib list sort c排序算法 没看懂 xff0c 留念一下 patch地址是https www mail archive com linux kernel 64 vger kernel org msg1957556 h
  • RealSenseD345I —— imu + camera标定

    目录 1 标定目的 2 标定准备 3 标定步骤 nbsp nbsp nbsp nbsp 1 IMU标定 nbsp nbsp nbsp
  • 深度学习分类算法系列之 -KNN

    先看一个实例来体会一下什么叫做KNN 已知一堆数据a和一堆数据0 xff0c 然后有一个未知数据c xff0c 要判断c到底属于a还是0 如果是1NN 就找到离C最近的数据 xff0c 离哪一个最近 xff0c 就判断c属于哪一类 如果利用
  • docker注册中心

    docker hub镜像上传 span class token comment 1 修改镜像镜像加速器 span span class token punctuation span root 64 sunrui span class tok
  • http-digest的认证

    摘要认证 digest authentication HTTP1 1提出的基本认证的替代方法 服务器端以nonce进行质询 xff0c 客户端以用户名 xff0c 密码 xff0c nonce xff0c HTTP方法 xff0c 请求的U
  • OSI七层协议和tcp/ip四层协议详解

    谈到网络不能不谈OSI参考模型 xff0c 虽然OSI参考模型的实际应用意义不是很大 xff0c 但其的确对于理解网络协议内部的运作很有帮助 xff0c 也为我们学习网络协议提供了一个很好的参考 在现实网络世界里 xff0c TCP IP协
  • 协议栈概念

    协议栈 xff08 Protocol Stack xff09 是指网络中各层协议的总和 xff0c 其形象的反映了一个网络中文件传输的过程 xff1a 由上层协议到底层协议 xff0c 再由底层协议到上层协议 使用最广泛的是英特网协议栈 x
  • DSST算法详解

    论文 xff1a Accurate Scale Estimation for Robust Visual Tracking Martin Danelljan Gustav H ger Fahad Khan Michael Felsberg
  • 机器学习毕业设计 大数据股票数据量化分析与预测系统 - python

    文章目录 0 前言1 课题背景2 实现效果UI界面设计web预测界面RSRS选股界面 3 软件架构4 工具介绍Flask框架MySQL数据库LSTM 0 前言 x1f525 这两年开始毕业设计和毕业答辩的要求和难度不断提升 xff0c 传统
  • 教你如何选择无人机框架——基础和改进(1)

    教你如何选择无人机框架 基础和改进 xff08 1 xff09 什么是四边形框架理想的四边形框架四边形框架的材料构建四边形框架轴距大小框架形状和手臂布局一体式设计碳纤维厚度处理碳纤维边缘私人用或比赛其他考虑因素 本文章概述了四边形框架 xf
  • Linux docker 删除镜像文件 以及解决删除报错image is being used by stopped container 的问题

    1 使用命令查看所有镜像 docker images 2 根据ID删除需要删除的镜像 docker rmi 4e4e466c38c1 rmi 43 自己需要删除的镜像的ID 3 如果删除时出现了image is being used by
  • 使用 volatile 破坏系统代码的九种方法

    首先怼上 xff1a It s hard to overstate how bad an idea it is for a compiler to use strange heuristics about code structure to