Global constructors not called
Posted: Wed Feb 28, 2024 6:07 am
Hello, I am writing toy OS using MSVC and C++. 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:
I did try all possible versions of this I found online.
In my Multiboot.cpp file I declare init/done functions and call them like this:
I went to see the binaries output using dumpbin, and using /headers this is part containing CRT$XCA and similiar:
But opening it with /all /symbols I cant find anything crt related.
Just to show an example, this works fine:
But this crashes:
I am running out of ideas, any suggestions?
Code: Select all
#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.cpp file I declare init/done functions and call them like this:
Code: Select all
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;
}
}
Code: Select all
SECTION HEADER #6
.CRT$XCA name
0 physical address
0 virtual address
4 size of raw data
E50 file pointer to raw data (00000E50 to 00000E53)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40300040 flags
Initialized Data
4 byte align
Read Only
SECTION HEADER #7
.CRT$XCZ name
0 physical address
0 virtual address
4 size of raw data
E54 file pointer to raw data (00000E54 to 00000E57)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40300040 flags
Initialized Data
4 byte align
Read Only
Just to show an example, this works fine:
Code: Select all
struct S
{
int a = 10;
};
static S s{}; //I expected that atleast C initializers need to be called but I guess not since it works even without calling crt_init
Code: Select all
struct S
{
S() : a() {}
int a = 10;
};
static S s{};