Global constructors not called
Hello, I am writing toy OS using MSVC and C++. That means I cannot rely on MSVC CRT and I have to write CRT startup by myself. Until now, I bypassed the issue I have with global constructors using function with static local variable but it's getting annoying now. This is how relevant parts are set up. crt.cpp is inside CoreLib project which is built as static library and later linked with my OS executable. I did check that the library gets linked. This is the code of crt.cpp:
#define _CRTALLOC(x) __declspec(allocate(x))
#pragma section(".CRT$XIA",long,read)
#pragma section(".CRT$XIZ",long,read)
#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)
#pragma section(".CRT$XPA",long,read)
#pragma section(".CRT$XPZ",long,read)
#pragma section(".CRT$XTA",long,read)
#pragma section(".CRT$XTZ",long,read)
typedef void (*_PVFV)(void);
typedef int (*_PIFV)(void);
extern "C" _CRTALLOC(".CRT$XIA") _PIFV __xi_a[] = { 0 }; // C initializers (first)
extern "C" _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[] = { 0 }; // C initializers (last)
extern "C" _CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = { 0 }; // C++ initializers (first)
extern "C" _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = { 0 }; // C++ initializers (last)
extern "C" _CRTALLOC(".CRT$XPA") _PVFV __xp_a[] = { 0 }; // C pre-terminators (first)
extern "C" _CRTALLOC(".CRT$XPZ") _PVFV __xp_z[] = { 0 }; // C pre-terminators (last)
extern "C" _CRTALLOC(".CRT$XTA") _PVFV __xt_a[] = { 0 }; // C terminators (first)
extern "C" _CRTALLOC(".CRT$XTZ") _PVFV __xt_z[] = { 0 }; // C terminators (last)
#pragma comment(linker, "/merge:.CRT=.rdata")
extern "C" int crt_call_c(_PIFV * a, _PIFV * b)
{
while (a != b)
{
if (*a)
{
int r = (**a)();
if (r) return r;
}
++a;
}
return 0;
}
extern "C" void crt_call(_PVFV * a, _PVFV * b)
{
while (a != b)
{
if (*a)
{
(**a)();
}
++a;
}
}
static _PVFV ExitList[32];
static unsigned MaxExitListEntries;
static unsigned CurrentExitListIndex;
static void _crt_init_atexit_tables(void)
{
MaxExitListEntries = 32;
CurrentExitListIndex = 0;
}
static void _crt_clean_atexit_tables(void)
{
MaxExitListEntries = 0;
CurrentExitListIndex = 0;
}
extern "C" int
__cdecl atexit(_PVFV Func)
{
if (CurrentExitListIndex < MaxExitListEntries)
{
ExitList[CurrentExitListIndex++] = Func;
return 0;
}
return -1;
}
void _cdecl crt_init()
{
_crt_init_atexit_tables();
crt_call_c(__xi_a, __xi_z);
crt_call(__xc_a, __xc_z);
}
void _cdecl crt_done()
{
_crt_clean_atexit_tables();
crt_call(__xp_a, __xp_z);
crt_call(__xt_a, __xt_z);
}
int __cdecl _purecall_handler()
{
for (;;);
}
In my multiboot entry I declare init/done functions and call them like this but my OS crashes when adding any global variable with a constructor:
extern void _cdecl crt_init();
extern void _cdecl crt_done();
void Start(uint32 eax, uint32 ebx)
{
crt_init();
Kernel(eax, ebx);
crt_done();
}
NOPROLOGUE void MultibootEntry(void)
{
__asm {
align 4
multiboot_header:
dd(MULTIBOOT_HEADER_MAGIC);
dd(MULTIBOOT_HEADER_FLAGS);
dd(CHECKSUM);
dd(HEADER_ADDRESS);
dd(KERNEL_LOAD_ADDRESS);
dd(00);
dd(00);
dd(HEADER_ADDRESS + 0x20);
kernel_entry:
cli
mov esp, KERNEL_STACK;
mov ebp, esp
push 0;
popf;
push ebx;
push eax;
call Start;
halt:
jmp halt;
}
}