我需要一个函数(就像来自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) 是否允许编译器对此进行优化(根据C++ 17标准):
int fn() {
volatile int x = 0;
return x;
}
Run Code Online (Sandbox Code Playgroud)
这个?
int fn() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果是,为什么?如果没有,为什么不呢?
这里有一些关于这个主题的思考:当前编译器编译fn()为放在堆栈上的局部变量,然后返回它.例如,在x86-64上,gcc创建了这个:
mov DWORD PTR [rsp-0x4],0x0 // this is x
mov eax,DWORD PTR [rsp-0x4] // eax is the return register
ret
Run Code Online (Sandbox Code Playgroud)
现在,据我所知,标准并没有说应该将一个局部volatile变量放在堆栈上.所以,这个版本同样好:
mov edx,0x0 // this is x
mov eax,edx // eax is the return
ret
Run Code Online (Sandbox Code Playgroud)
这里,edx商店x.但是现在,为什么要停在这里?由于edx和eax均为零,我们可以只说:
xor eax,eax // eax is the return, and x as well
ret
Run Code Online (Sandbox Code Playgroud)
我们转变 …
struct在某些情况下,我注意到clang和gcc优化了堆栈中声明的volatile的构造或赋值.例如,以下代码:
struct nonvol2 {
uint32_t a, b;
};
void volatile_struct2()
{
volatile nonvol2 temp = {1, 2};
}
Run Code Online (Sandbox Code Playgroud)
编译 clang:
volatile_struct2(): # @volatile_struct2()
ret
Run Code Online (Sandbox Code Playgroud)
另一方面,gcc不会删除商店,尽管它确实将两个隐含商店优化为一个商店:
volatile_struct2():
movabs rax, 8589934593
mov QWORD PTR [rsp-8], rax
ret
Run Code Online (Sandbox Code Playgroud)
奇怪的是,clang不会将易失性存储优化为单个int变量:
void volatile_int() {
volatile int x = 42;
}
Run Code Online (Sandbox Code Playgroud)
编译为:
volatile_int(): # @volatile_int()
mov dword ptr [rsp - 4], 1
ret
Run Code Online (Sandbox Code Playgroud)
此外,没有优化具有1个成员而不是2个成员的结构.
虽然gcc在这种特殊情况下不会删除构造,但在struct成员本身被声明的情况下,它可能甚至更积极的优化volatile,而不是在struct构造点本身:
typedef struct {
volatile uint32_t a, b;
} vol2;
void volatile_def2()
{ …Run Code Online (Sandbox Code Playgroud)