Global constructors not called

Mate 25 Reputation points
2024-02-28T10:50:07.1933333+00:00

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;
	}
}
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,720 questions
Windows Hardware Performance
Windows Hardware Performance
Windows: A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.Hardware Performance: Delivering / providing hardware or hardware systems or adjusting / adapting hardware or hardware systems.
1,613 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.