Leu*_*nko 8 c++ optimization x86-64
C++ 中的本地静态对象在第一次需要时初始化一次(如果初始化有副作用,这是相关的):
void once() {
static bool b = [] {
std::cout << "hello" << std::endl; return true;
} ();
}
Run Code Online (Sandbox Code Playgroud)
once 将在第一次调用时打印“hello”,但如果再次调用则不会打印。
我已经将这种模式的一些变体放入Compiler Explorer并注意到所有知名实现(GCC、Clang、ICC、VS)本质上都在做同样的事情:guard variable for once()::b创建一个隐藏变量,并检查是否“这次”需要初始化主变量;如果是,它会被初始化,然后设置守卫,下次它不会跳出初始化代码。例如(通过将 lambda 替换为对 的调用来最小化extern bool init_b();):
once():
movzx eax, BYTE PTR guard variable for once()::b[rip]
test al, al
je .L16
ret
.L16:
push rbx
mov edi, OFFSET FLAT:guard variable for once()::b
call __cxa_guard_acquire
test eax, eax
jne .L17
pop rbx
ret
.L17:
call init_b()
pop rbx
mov edi, OFFSET FLAT:guard variable for once()::b
jmp __cxa_guard_release
mov rbx, rax
mov edi, OFFSET FLAT:guard variable for once()::b
call __cxa_guard_abort
mov rdi, rbx
call _Unwind_Resume
Run Code Online (Sandbox Code Playgroud)
...来自带有 -O3 的 GCC 6.3。
这并非不合理,而且我知道在实践中,当条件一致时,条件跳转无论如何都接近免费。然而,我的直觉仍然会被执行这一联合国有条件地跳转到初始化代码,这为最后一个动作将覆盖与发信跳转nop指令。不一定是每个平台上的选项,但 x86 系列似乎对您可以读取或写入的内容以及位置非常自由。
这个看似简单的想法没有主流编译器使用它有什么问题?(或者我只需要在我的例子中更加努力?)
在大多数现代操作系统上,修改程序加载的代码会导致问题。这既可能导致性能问题(未经修改的代码可以在某些系统上的 dll 的许多实例之间共享页面),也可能导致安全问题(阻止使用可执行空间保护技术)。