首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >gcc:硬件寄存器读取时“-fno-严格-混叠”的奇怪行为

gcc:硬件寄存器读取时“-fno-严格-混叠”的奇怪行为
EN

Stack Overflow用户
提问于 2013-09-24 00:11:06
回答 2查看 240关注 0票数 1

我正在尝试使用gdb.The编译标志调试C程序,我使用的标记如下所示

代码语言:javascript
复制
-fno-strict-aliasing -Wall -DHAVE_CONFIG_H -DNO_OLD_ERF_TYPES -Werror  -Wredundant-decls -O2 -DNDEBUG -DBYTESWAP -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -g 

我使用的编译器的版本是

代码语言:javascript
复制
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

有争议的代码如下所示

代码语言:javascript
复制
spm->num_streams = (uint16_t)((MkIV->stream_counts >> 16 ) & 0xfff);

num_streams with -fno-strict-aliasing

代码语言:javascript
复制
 0xffff (4095)

num_streams WITHOUT-fno-strict-aliasing

代码语言:javascript
复制
 0x1 (1)

值得注意的是,mkIV->stream_counts is 0x10020.This的实际值是从HARDWARE REGISTER读取的。

我们感兴趣的值是spm->num_streamsBIT27:BIT16.Therefore,期望值是'1'

如果我要取代

代码语言:javascript
复制
spm->num_streams = (uint16_t)((MkIV->stream_counts >> 16 ) & 0xfff);

使用

代码语言:javascript
复制
spm->num_streams = (uint16_t)((MkIV->stream_counts & 0xfff0000) >> 16);

然后,我得到了0x1(1)的值和不含-fno-strict-aliasing的值。

stream_counts in MkIV结构(MkIV->stream_countsuint32_t type)

代码语言:javascript
复制
spm->num_streams is of type uint16_t

有人能解释一下为什么会这样吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-09-24 02:05:25

由于使用stream_countsvolatile进行了限定,所以您似乎受到了as-if规则的影响,该规则基本上说,如果编译器能够修改程序,只要它能够确定它不会影响可观察到的行为。Cp偏好在这里有一个很好的解释,尽管它是针对C++编写的,但大多数也适用于C。这些代码示例特别有指导意义。

与C++标准草案不同的是,C99标准草案只明确提到索引中指向第3段中的5.1.2.3程序执行的“如果”规则,它说(强调“我的”):

在抽象机器中,所有表达式都由语义指定。一个实际的实现不需要计算表达式的一部分,如果它可以推断它的值没有被使用,并且没有产生所需要的副作用(包括调用函数或访问易失性对象所引起的任何副作用)。

它确实在一些例子中使用了好象短语,从第11段中我们有以下例子:

代码语言:javascript
复制
float f1, f2;
double d;
/* ... */
f1 = f2 * d;

下面的案文是(强调我的):

如果实现可以确定结果与使用双精度算法执行的相同,则可以使用单精度算法执行乘法。

如果我们看一看6.7.3类型限定符部分,第6段说(强调我的):

具有易失性限定类型的对象可以以实现未知的方式进行修改,或者具有其他未知的副作用。因此,引用这样一个对象的任何表达式都应严格按照5.1.2.3中描述的抽象机器的规则进行计算。此外,在每个序列点上,最后存储在对象中的值应与抽象机器规定的值一致,除非前面提到的未知因素对其进行了修改。

这就限制了编译器对volatile限定对象可以采取的快捷方式。5.1.2.3第5段涵盖了对符合实现的最小要求。

票数 1
EN

Stack Overflow用户

发布于 2013-09-24 00:25:26

你是“以假乱真”规则的受害者。编译器不知道您是从硬件寄存器中读取的。当你写:

代码语言:javascript
复制
spm->num_streams = (uint16_t)((MkIV->stream_counts & 0xfff0000) >> 16);

编译器完全有权这样做:

代码语言:javascript
复制
uint16_t j = MkIV->stream_counts;
MkIV->stream_counts &= 0xfff0000;
MkIV->stream_counts >>= 16;
sp->num_streams = MKIV->stream_counts;
MkIV->stream_counts = j;

最有可能的是,您可以通过使stream_counts易挥发或通过易失性指针“清洗”读取来解决这个问题。

不要使用MkIV->stream_counts,而是使用*(volatile uint16_t *)&MkIV->stream_counts

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18970921

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档