Googles appar
Huvudmeny

Post a Comment On: cbloom rants

"08-04-09 - CINIT"

6 Comments -

1 – 6 of 6
Blogger Branimir Karadžić said...

Did you try pragma init_seg on MSVC (or init_priority attribute on GCC)?

Something like:

#pragma init_seg(lib) // this will be initialized before user consturctors, but after CRT libs
bool g_cinit = true;

int main...
{
g_cinit = false;
...
}

August 4, 2009 at 9:08 PM

Blogger Bret said...

The other way around might be easier, maybe?

// BSS should be initialized to zero
bool g_main_has_started;

int main (...) {
g_main_has_started = true;
...
}

August 4, 2009 at 11:13 PM

Blogger cbloom said...

Yeah, obviously if I can write something at the start of main() it's trivial.

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.

August 5, 2009 at 12:10 AM

Blogger ryg said...

Heavily depends on the compiler and platform, obviously.

For VC++, you have the init_seg stuff. Stuff all your lib code into init_seg(lib). Then you can do:

--------------

static bool initFinished = false;

#pragma init_seg(lib)
// your static initializers
#pragma init_seg(user)
struct __InitDone { __InitDone() { initFinished = true; } } __InitDoneInst;

--------------

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:

dumpbin myfile.obj /sections | find ".CRT$"

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 "#pragma comment(linker, "/merge:.CRT=.rdata")" 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).

If you want something to get executed just after all cinit has been completed, put a function pointer into section .CRT$XCY.

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.

August 5, 2009 at 1:12 AM

Blogger ryg said...

Addendum: Less bothersome version of above (no need to stuff everything into init_seg(lib)), including a small test case:

// ---- code stars here
#include <stdio.h>

// ---- start of relevant part

static bool inCInit = false;

static void __cdecl startCInit() { inCInit = true; }
static void __cdecl endCInit() { inCInit = false; }

// the required VC++/linker voodoo
#pragma section(".CRT$XCB",long,read)
#pragma section(".CRT$XCY",long,read)

typedef void (__cdecl *FuncPtr)();

__declspec(allocate(".CRT$XCB")) FuncPtr __startPtr__[] = { startCInit };
__declspec(allocate(".CRT$XCY")) FuncPtr __endPtr__[] = { endCInit };

// ---- end of relevant part

static void func()
{
printf("func called from %s\n",inCInit ? "cinit" : "normal program flow");
}

struct A
{
A() { func(); }
} a;

int main()
{
A b;
func();
}

// ---- code ends here

Now let's see how much Blogger will mutilate this...

August 6, 2009 at 12:16 PM

Blogger cbloom said...

Awesome!

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.

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

const double c = 0.5 + 0.1;

becomes a cinit call.

August 6, 2009 at 12:20 PM

You can use some HTML tags, such as <b>, <i>, <a>

This blog does not allow anonymous comments.

Comment moderation has been enabled. All comments must be approved by the blog author.

You will be asked to sign in after submitting your comment.