相关疑难解决方法(0)

"volatile"这个定义是不稳定的,还是GCC有一些标准的合规性问题?

我需要一个函数(就像来自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

  • GCC 4.4.7和4.5.3永远不会忽略volatile.
  • 对于数组大小为1,2和4,GCC 4.6.4和4.7.3忽略volatile.
  • GCC 4.8.1直到4.9.2忽略数组大小1和2的volatile.
  • GCC 5.1直到5.3忽略数组大小1,2,4,8的volatile.
  • GCC 6.1只是忽略任何数组大小(一致性的奖励点).

我测试过的任何其他编译器(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 c++ standards gcc

87
推荐指数
2
解决办法
4507
查看次数

是否允许编译器优化本地volatile变量?

是否允许编译器对此进行优化(根据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.但是现在,为什么要停在这里?由于edxeax均为零,我们可以只说:

xor    eax,eax // eax is the return, and x as well
ret    
Run Code Online (Sandbox Code Playgroud)

我们转变 …

c++ volatile language-lawyer c++17

75
推荐指数
5
解决办法
5748
查看次数

优化商店/构建易变的堆栈变量是否合法?

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)

c++ optimization x86 volatile language-lawyer

8
推荐指数
1
解决办法
226
查看次数

标签 统计

c++ ×3

language-lawyer ×2

volatile ×2

c ×1

c++17 ×1

gcc ×1

optimization ×1

standards ×1

x86 ×1