c++ - Why does initialization of local static objects use hidden guard flags? -
local static objects in c++ initialized once, first time needed (which relevant if initialization has side effect):
void once() { static bool b = [] { std::cout << "hello" << std::endl; return true; } (); }
once
print "hello" first time called, not if called again.
i've put few variations of pattern compiler explorer , noticed of big-name implementations (gcc, clang, icc, vs) same thing: hidden variable guard variable once()::b
created, , checked see whether primary variable needs initialized "this time"; if does, gets initialized , guard set, , next time won't jump out initialization code. e.g. (minimized replacing lambda call extern bool init_b();
):
once(): movzx eax, byte ptr guard variable once()::b[rip] test al, al je .l16 ret .l16: push rbx mov edi, offset flat:guard variable 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 once()::b jmp __cxa_guard_release mov rbx, rax mov edi, offset flat:guard variable once()::b call __cxa_guard_abort mov rdi, rbx call _unwind_resume
...from gcc 6.3 -o3.
this isn't unreasonable, , know in practice conditional jumps close free anyway when condition consistent. however, gut feeling still have been implement unconditionally jumping initialization code, last action overwrites originating jump nop
instructions. not option on every platform, x86 family seems quite liberal can read or write, , where.
what's wrong apparently-simple idea no mainstream compiler uses it? (or need try harder examples?)
on modern operating systems modifying code loaded program causes issues. can both cause performance issues (unmodified code can share pages between many instances of dll on systems), , security issues (preventing use of executable space protection technologies).
Comments
Post a Comment