为了使页面变脏(打开页面表条目中的脏位),我触摸页面的第一个字节,如下所示:
pageptr[0] = pageptr[0];
但实际上,gcc将通过消除死存储来忽略该语句。 为了防止gcc对其进行优化,我将语句重写如下:
volatile int tmp;
tmp = pageptr[0];
pageptr[0] = tmp;
看起来the俩有效,但有些难看。 我想知道是否有任何指令或语法具有相同的效果? 而且我不想使用-O0标志,因为它也会带来很大的性能损失。
您是否尝试过-O0?
@Mark -O0将停止优化,但也会降低程序性能。 我只想阻止此代码段的优化:P
您可以使用
#pragma GCC push_options
#pragma GCC optimize ("O0")
your code
#pragma GCC pop_options
自GCC 4.4起禁用优化。
如果需要更多详细信息,请参阅GCC文档。
但是,值得注意的是,这仅适用于整个功能,不适用于特定的说明:gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/"此后定义的每个功能就好像attribute((optimize (" STRING")))已为此功能指定。"。
除了使用新的编译指示外,您还可以根据需要使用__attribute__((optimize("O0")))。这样的优点是仅适用于单个函数,而不是应用于同一文件中定义的所有函数。
用法示例:
void __attribute__((optimize("O0"))) foo(unsigned char data) {
// unmodifiable compiler code
}
如果我没有使用-Olevel选项,而是使用了单独打开的个人选项怎么办? (就我而言,我无法确定哪个是破坏代码的单个优化选项)。
关闭优化可解决此问题,但这不是必需的。一种更安全的选择是使编译器使用volatile类型限定符来优化存储空间是非法的。
// Assuming pageptr is unsigned char * already...
unsigned char *pageptr = ...;
((unsigned char volatile *)pageptr)[0] = pageptr[0];
volatile类型限定符指示编译器对内存存储和加载严格。 volatile的一个目的是让编译器知道内存访问有副作用,因此必须保留。在这种情况下,存储具有导致页面错误的副作用,并且您希望编译器保留页面错误。
这样,仍然可以优化周围的代码,并且您的代码可以移植到其他不理解GCC的#pragma或__attribute__语法的编译器中。
我想说这比关闭优化更可取。使用此方法,您仍然可以从其他优化中受益。
您是否真的需要从页面进行加载?当然只有商店会这样做:*(volatile int *)pageptr = 0;
您需要修改程序,以使其变得难以阅读。
@caf-您的版本可能会导致页面内容更改。 OP表示页面内容不应更改。
没错,我读到了其中没有的东西(当然,如果pageptr[0]的类型大于char的类型,那么给定的解决方案也会更改页面)。
@caf-错过了int / char问题。 @DietrichEpp-看来您的修复应为*(unsigned char volatile *)pageptr = *(unsigned char *)pageptr;
Dietrich Epps解决方案在ARM4.1编译器下不起作用。甚至ZelluXs解决方案都无法正常工作。在ZelluXs解决方案中使ARM4.1起作用的替代方法是,将temp设为全局volatile变量。
那对于所说的编译器来说是很糟糕的。
谢谢你的提示 :)
这个把戏救了我一命。非常感谢你!
对于带有-O2的GCC 6.2.0,这不起作用。我的代码volatile Object* obj = ...和结果obj =
@Shocker:GCC仍然可以优化变量,而无需优化实际的内存访问。这些是不同的问题。
" volatile的一个目的是让编译器知道内存访问有副作用……"-在GCC下,这是不正确的。 GCC人士指出volatile的目的是用于内存映射的硬件。来自Ian Lance Taylors关于volatile的博客:"总之,如果您将volatile用于操作内存映射硬件以外的任何事物,或者用于线程之间的通信非常有限,则很可能您在犯错。请仔细考虑什么volatile意味着什么,不是什么意思。"
@jww:这种用法符合该博客文章中的描述。 volatile意味着必须按写入顺序进行内存访问,这正是我们想要的。换句话说,我们已经仔细考虑过了,这意味着我们认为的含义。
大!该方法适用于DSP 5509a编译器。