我需要一个函数(就像来自WinAPI的SecureZeroMemory)总是将内存归零并且不会被优化掉,即使编译器认为在此之后永远不会再访问内存.似乎是挥发性的完美候选者.但是我实际上遇到了一些与GCC合作的问题.这是一个示例函数:
void volatileZeroMemory(volatile void* ptr, unsigned long long size)
{
volatile unsigned char* bytePtr = (volatile unsigned char*)ptr;
while (size--)
{
*bytePtr++ = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
很简单.但是,如果你调用它,GCC实际生成的代码会因编译器版本和你实际尝试为零的字节数而有很大不同.https://godbolt.org/g/cMaQm2
我测试过的任何其他编译器(clang,icc,vc)都会生成一个人们期望的存储,包括任何编译器版本和任何数组大小.所以在这一点上我想知道,这是一个(非常古老而严重的?)GCC编译器错误,或者是标准中volatile的定义,它不确定这实际上是符合行为的,这使得编写便携式基本上是不可能的" SecureZeroMemory"功能?
编辑:一些有趣的观察.
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <atomic>
void callMeMaybe(char* buf);
void volatileZeroMemory(volatile void* ptr, std::size_t size)
{
for (auto bytePtr = static_cast<volatile std::uint8_t*>(ptr); size-- > 0; )
{
*bytePtr++ = 0;
}
//std::atomic_thread_fence(std::memory_order_release);
}
std::size_t foo()
{
char …Run Code Online (Sandbox Code Playgroud) 我想为Atmel AVR微控制器编写C代码固件.我将使用GCC编译它.此外,我想启用编译器优化(-Os或-O2),因为我认为没有理由不启用它们,并且它们可能比手动编写汇编更快地生成更好的汇编方式.
但我想要一小段没有优化的代码.我想延迟函数的执行一段时间,因此我想写一个do-nothing循环只是为了浪费一些时间.不需要精确,只需等待一段时间.
/* How to NOT optimize this, while optimizing other code? */
unsigned char i, j;
j = 0;
while(--j) {
i = 0;
while(--i);
}
Run Code Online (Sandbox Code Playgroud)
由于AVR中的内存访问速度要慢得多,因此我希望i并将j其保存在CPU寄存器中.
更新:我刚刚发现UTIL/delay.h和UTIL/delay_basic.h从AVR libc库.尽管大多数情况下使用这些功能可能更好,但这个问题仍然有效且有趣.
相关问题:
我正在寻找一种编程技术,确保用于基准测试的变量(没有可观察到的副作用)不会被编译器优化掉
/**
* Call doNotOptimizeAway(var) against variables that you use for
* benchmarking but otherwise are useless. The compiler tends to do a
* good job at eliminating unused variables, and this function fools
* it into thinking var is in fact needed.
*/
#ifdef _MSC_VER
#pragma optimize("", off)
template <class T>
void doNotOptimizeAway(T&& datum) {
datum = datum;
}
#pragma optimize("", on)
#else
template <class T>
void doNotOptimizeAway(T&& datum) {
asm volatile("" : "+r" (datum)); …Run Code Online (Sandbox Code Playgroud) 考虑以下简单示例:
struct __attribute__ ((__packed__)) {
int code[1];
int place_holder[100];
} s;
void test(int n)
{
int i;
for (i = 0; i < n; i++) {
s.code[i] = 1;
}
}
Run Code Online (Sandbox Code Playgroud)
for 循环正在写入code大小为 1 的字段 。之后的下一个字段code是place_holder。
我希望在 的情况下n > 1,写入code数组会溢出并1写入place_holder.
但是,在使用-O2(在 gcc 4.9.4 上但也可能在其他版本上)进行编译时,会发生一些有趣的事情。
编译器识别出代码可能溢出数组code,并将循环展开限制为 1 次迭代。
很容易看出,在编译-fdump-tree-all和查看最后一个树传递(“t.optimized”)时:
;; Function test (test, funcdef_no=0, decl_uid=1366, symbol_order=1)
Removing basic block …Run Code Online (Sandbox Code Playgroud) 所以我在这个非常奇怪和恼人的问题上被困了几天.所以我有一个应用程序,我发布到ios应用商店,我最近回去并为应用程序添加了一些额外的功能.我没有触摸应用程序的核心,只是添加了诸如twitter,facebook,app应用程序和google admob(基于完整版的免费版本).所以这里的事情变得奇怪.我测试了我的更新我做了一个adhoc发布版本并在我的iphone 3gs,4s,ipad 2上测试 - 没有任何问题.我提交给苹果他们批准了更新,它已经发布.我更新了应用程序并尝试运行它并在启动画面后立即崩溃(此处没有任何更改).我的项目使用cocos2dx框架(版本cocos2d-2.0-x-2.0.4 @ 2012年11月2日),我使用cocosbuilder(2.1).我查看了日志,它似乎是CCBReader :: readFloat()函数内部的一个未对齐问题.我发现这里有一个解决方法:https://github.com/DarraghCoy/cocos2d-x/commit/34b31fd754778f815fcac108089e3fe015e2e2b9.
所以我继续修改我的默认情况:float CCBReader :: readFloat(){unsigned char type = this-> readByte();
switch (type) {
case kCCBFloat0:
return 0;
case kCCBFloat1:
return 1;
case kCCBFloatMinus1:
return -1;
case kCCBFloat05:
return 0.5f;
case kCCBFloatInteger:
return (float)this->readInt(true);
default:
{
/* using a memcpy since the compiler isn't
* doing the float ptr math correctly on device.
* TODO still applies in C++ ? */
float * pF = (float*)(this->mBytes + this->mCurrentByte); …Run Code Online (Sandbox Code Playgroud) 我是在函数之前编写的项目源代码中看到这一行的。我想知道,它有什么用?
#pragma GCC optimize ("O3")
void somefunction()
{
....
}
Run Code Online (Sandbox Code Playgroud)
请求解释指令中使用的每个参数。
谢谢并恭祝安康。
gcc/g++ 是否具有启用或禁用算术优化的标志,例如 wherea+a+...+a被n*awhen替换a为整数?特别是,在使用-O2or时可以禁用它-O3吗?
在下面的示例中,即使-O0将加法运算替换为单个乘法:
$ cat add1.cpp
unsigned int multiply_by_22(unsigned int a)
{
return a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;
}
$ g++ -S -masm=intel -O0 add1.cpp
$ cat add1.s
...
imul eax, edi, 22
Run Code Online (Sandbox Code Playgroud)
即使禁用-O0(参见g++ -c -Q -O0 --help=optimizers | grep enabled)中使用的所有标志仍然会产生imul操作。
添加循环时,需要-O1将重复加法简化为单个乘法:
$ cat add2.cpp
unsigned int multiply(unsigned int a, unsigned int b)
{
unsigned int sum=0;
for(unsigned int i=0; i<b; i++)
sum …Run Code Online (Sandbox Code Playgroud) 在 gdb 中,我设置了一个断点,让 gdb 在满足第一个if条件时停止。但是 gdb 停在另一行并且if不满足条件。我读过gdb breakpoint does not get hit,但它仍然没有解决。我认为 gdb 仅在if (a == 1)遇到并在第 3282 行时停止。我错了吗?
#pragma GCC push_options
#pragma GCC optimize("O0")
static void __attribute__ ((noinline)) search(int a, int b)
{
// other code here
if (a == 1) {
printf("condition1\n");
printf("condition1\n"); // line 3282, breakpoint is set here
}
if (b == 1) { // line 3284, in fact, gdb stops in this line
printf("condition2\n");
printf("condition2\n");
}
} …Run Code Online (Sandbox Code Playgroud) 在 ARM GCC(纯 C 代码)上,当我声明一个常量时,如下所示
__attribute__((used,section(".rodata.$AppID")))
const uint8_t ApplicationID[16] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x12, 0x34, 0x00, 0x00
};
Run Code Online (Sandbox Code Playgroud)
我没有在代码中引用它,它已被优化,并在地图文件上的废弃输入部分中列出。仅当我在源代码的其他地方引用它时,它才会包含在二进制输出中。
仅仅“ used”标签就足够了吗?在GCC手册(6.34.1公共变量属性)中我读到:
用过的
此属性附加到具有静态存储的变量,意味着即使看起来该变量未被引用,也必须发出该变量。
意思是把它放在指定段的固定内存地址,供单独的应用程序检查它
我正在运行 NXP MCUXpresso 11.1 提供的 ARM GCC,报告详细版本为
GNU C17 (GNU Tools for Arm Embedded Processors 8-2019-q3-update) version 8.3.1 20190703 (release) [gcc-8-branch revision 273027] (arm-none-eabi)
compiled by GNU C version 5.3.1 20160211, GMP version 6.1.0, MPFR version 3.1.4, …Run Code Online (Sandbox Code Playgroud) struct X {
void * a;
void * b;
};
X foo( void * u, void * v);
Run Code Online (Sandbox Code Playgroud)
类型X的返回值的地址作为隐藏参数传递给foo()
如果使用-O0编译测试代码,则代码按预期工作
如何强制编译器不为foo()添加RVO(又名强制-fno-elide-constructors)?
Update1:代码必须适用于任意编译器(至少gcc,clang,msvc),示例代码:
void * vp = bar();
X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0);
Run Code Online (Sandbox Code Playgroud)
Update2:问题是,编译器优化了x的实例
X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0)
Run Code Online (Sandbox Code Playgroud)
要么
X x1 = foo( vp, 0);
X x2 = foo( x1.a, 0);
X …Run Code Online (Sandbox Code Playgroud)