tag:blogger.com,1999:blog-5246987755651065286.post2953656169769020390..comments2024-02-22T16:15:42.388-08:00Comments on cbloom rants: 08-04-09 - CINITcbloomhttp://www.blogger.com/profile/10714564834899413045noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-5246987755651065286.post-10543853242001324392009-08-06T12:20:35.046-07:002009-08-06T12:20:35.046-07:00Awesome!
BTW I did some investigation and it seem...Awesome!<br /><br />BTW I did some investigation and it seems MSVC sticks everything in init_seg user by default; eg. libs don't get put in init_seg(lib) unless you manually tell it to do so.<br /><br />I always try to make my static C++ initialization stuff be initialize-on-use so it's not order dependent, but one thing I discovered by doing dumpbins is that the damn float constants become initializers in cinit. eg. something like<br /><br />const double c = 0.5 + 0.1;<br /><br />becomes a cinit call.cbloomhttps://www.blogger.com/profile/10714564834899413045noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-65737848349716293352009-08-06T12:16:00.737-07:002009-08-06T12:16:00.737-07:00Addendum: Less bothersome version of above (no nee...Addendum: Less bothersome version of above (no need to stuff everything into init_seg(lib)), including a small test case:<br /><br />// ---- code stars here<br />#include <stdio.h><br /><br />// ---- start of relevant part<br /><br />static bool inCInit = false;<br /><br />static void __cdecl startCInit() { inCInit = true; }<br />static void __cdecl endCInit() { inCInit = false; }<br /><br />// the required VC++/linker voodoo<br />#pragma section(".CRT$XCB",long,read)<br />#pragma section(".CRT$XCY",long,read)<br /><br />typedef void (__cdecl *FuncPtr)();<br /><br />__declspec(allocate(".CRT$XCB")) FuncPtr __startPtr__[] = { startCInit };<br />__declspec(allocate(".CRT$XCY")) FuncPtr __endPtr__[] = { endCInit };<br /><br />// ---- end of relevant part<br /><br />static void func()<br />{<br /> printf("func called from %s\n",inCInit ? "cinit" : "normal program flow");<br />}<br /><br />struct A<br />{<br /> A() { func(); }<br />} a;<br /><br />int main()<br />{<br /> A b;<br /> func();<br />}<br /><br />// ---- code ends here<br /><br />Now let's see how much Blogger will mutilate this...ryghttps://www.blogger.com/profile/03031635656201499907noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-70350112668221751672009-08-05T01:12:39.486-07:002009-08-05T01:12:39.486-07:00Heavily depends on the compiler and platform, obvi...Heavily depends on the compiler and platform, obviously.<br /><br />For VC++, you have the init_seg stuff. Stuff all your lib code into init_seg(lib). Then you can do:<br /><br />--------------<br /><br />static bool initFinished = false;<br /><br />#pragma init_seg(lib)<br />// your static initializers<br />#pragma init_seg(user)<br />struct __InitDone { __InitDone() { initFinished = true; } } __InitDoneInst;<br /><br />--------------<br /><br />Disallowing cinit code: No way to make the compiler reject this that I'm aware of, at least for VC++. But you can test whether the compiled object files contain any initializers, since they're put into special sections:<br /><br /><b>dumpbin myfile.obj /sections | find ".CRT$"</b><br /><br />Look at crt0init.c / crtexe.c in the CRT source code to see how it works. The linker sorts all sections starting with ".CRT$" alphabetically then merges them into one big ".CRT" section, which is then merged into the const data section (that's the "<b>#pragma comment(linker, "/merge:.CRT=.rdata")</b>" in crtinit.c). The $XCA and $XCZ names are used to get labels that point at the start and end of the respective sublists, initializers are put somewhere inbetween. (Normally $XCU for C++ constructors with user-level priority).<br /><br />If you want something to get executed just after all cinit has been completed, put a function pointer into section .CRT$XCY.<br /><br />This automatic section-merging is a general linker thing and not tied to the .CRT stuff. If you put a $ in a section name, the linker will always use the remainder of the name as a sort key then merge everything.ryghttps://www.blogger.com/profile/03031635656201499907noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-28557747506014418982009-08-05T00:10:59.415-07:002009-08-05T00:10:59.415-07:00Yeah, obviously if I can write something at the st...Yeah, obviously if I can write something at the start of main() it's trivial.<br /><br />I want this to be in a library and have it work for clients and not require them to write anything in main. It should work automatically using only cinit, not relying on any code in main.cbloomhttps://www.blogger.com/profile/10714564834899413045noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-19392229841765201312009-08-04T23:13:58.577-07:002009-08-04T23:13:58.577-07:00The other way around might be easier, maybe?
// B...The other way around might be easier, maybe?<br /><br />// BSS should be initialized to zero<br />bool g_main_has_started;<br /><br />int main (...) {<br /> g_main_has_started = true;<br /> ...<br />}Brethttps://www.blogger.com/profile/03262475856836100420noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-4813069528164769582009-08-04T21:08:09.670-07:002009-08-04T21:08:09.670-07:00Did you try pragma init_seg on MSVC (or init_prior...Did you try pragma init_seg on MSVC (or init_priority attribute on GCC)?<br /><br />Something like:<br /><br />#pragma init_seg(lib) // this will be initialized before user consturctors, but after CRT libs<br />bool g_cinit = true;<br /><br />int main...<br />{<br /> g_cinit = false;<br />...<br />}Branimir Karadžićhttps://www.blogger.com/profile/08258281434387357224noreply@blogger.com