Visual C++ Runtime

From OSDev Wiki
Jump to navigation Jump to search

Since you can't link standard C++ runtime to your kernel, you'll need several functions to replace it's functionality. This article provides information on how to implement your own C++ runtime for Visual C++ compiler.


Call Constructors For Global Static Variables

This code will help to call all constructors for global static variables.

// Constructor prototypes
typedef void (__cdecl *_PVFV)(void);
typedef int  (__cdecl *_PIFV)(void);

// Linker puts constructors between these sections, and we use them to locate constructor pointers.
#pragma section(".CRT$XIA",long,read)
#pragma section(".CRT$XIZ",long,read)
#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)

// Put .CRT data into .rdata section
#pragma comment(linker, "/merge:.CRT=.rdata")

// Pointers surrounding constructors
__declspec(allocate(".CRT$XIA")) _PIFV __xi_a[] = { 0 };
__declspec(allocate(".CRT$XIZ")) _PIFV __xi_z[] = { 0 };
__declspec(allocate(".CRT$XCA")) _PVFV __xc_a[] = { 0 };
__declspec(allocate(".CRT$XCZ")) _PVFV __xc_z[] = { 0 };

extern __declspec(allocate(".CRT$XIA")) _PIFV __xi_a[];
extern __declspec(allocate(".CRT$XIZ")) _PIFV __xi_z[];    // C initializers
extern __declspec(allocate(".CRT$XCA")) _PVFV __xc_a[];
extern __declspec(allocate(".CRT$XCZ")) _PVFV __xc_z[];    // C++ initializers

// Call C constructors
static int _initterm_e(_PIFV * pfbegin, _PIFV * pfend) {
        int ret = 0;

        // walk the table of function pointers from the bottom up, until
        // the end is encountered.  Do not skip the first entry.  The initial
        // value of pfbegin points to the first valid entry.  Do not try to
        // execute what pfend points to.  Only entries before pfend are valid.
        while ( pfbegin < pfend  && ret == 0)
        {
            // if current table entry is non-NULL, call thru it.
            if ( *pfbegin != 0 )
                ret = (**pfbegin)();
            ++pfbegin;
        }

        return ret;
}

// Call C++ constructors
static void _initterm (_PVFV * pfbegin, _PVFV * pfend)
{
        // walk the table of function pointers from the bottom up, until
        // the end is encountered.  Do not skip the first entry.  The initial
        // value of pfbegin points to the first valid entry.  Do not try to
        // execute what pfend points to.  Only entries before pfend are valid.
        while ( pfbegin < pfend )
        {
            // if current table entry is non-NULL, call thru it.
            if ( *pfbegin != 0 )
                (**pfbegin)();
            ++pfbegin;
        }
}

// Call this function as soon as possible. Basically should be at the moment you
// jump into your C/C++ kernel. But keep in mind that kernel is not yet initialized,
// and you can't use a lot of stuff in your constructors!
bool CallConstructors() {
	// Do C initialization
	int initret = _initterm_e(__xi_a, __xi_z);
	if ( initret != 0 ) {
            return false;
	}

        // Do C++ initialization
        _initterm(__xc_a, __xc_z);
	return true;
}


new And delete Operators

One of the first things you'll want to do is implement new and delete operators. At first, you can't really implement them, and just need to have their stubs. Later on, when you get your memory manager working, you can fully implement them. Bellow are the stubs:

void* __cdecl operator new(size_t size)
{
	// Allocate memory
	return 0;
}


void* __cdecl operator new[](size_t size)
{
	// Allocate memory
	return 0;
}


void __cdecl operator delete(void *p)
{
	if (p == 0) {
		return;
	}

	// Release allocated memory
}

void __cdecl operator delete[](void *p)
{
	if (p == 0) {
		return;
	}

	// Release allocated memory
}


If you'll want to use placement new, then you'll need to put the following implementation into a header file, and include it whenever you need it.

inline void* __cdecl operator new(size_t size, void* address)
{
	return address;
}


See Also

Articles

External Links