Visual C++ Runtime

来自osdev
跳到导航 跳到搜索

由于不能将标准C++运行时链接到内核,所以需要几个函数来替换它的功能。 本文提供有关如何为Visual C++编译器实现你自己的C++运行库的信息。


调用全局静态变量的构造函数

这段代码将有助于调用全局静态变量的所有构造函数。

// 构造函数原型
typedef void (__cdecl *_PVFV)(void);
typedef int  (__cdecl *_PIFV)(void);

// 链接器将构造函数放在这些部分之间,我们使用它们来定位构造函数指针。
#pragma section(".CRT$XIA",long,read)
#pragma section(".CRT$XIZ",long,read)
#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)

//将.CRT数据放入.rdata节
#pragma comment(linker, "/merge:.CRT=.rdata")

// 围绕构造函数的指针
__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初始化器
extern __declspec(allocate(".CRT$XCA")) _PVFV __xc_a[];
extern __declspec(allocate(".CRT$XCZ")) _PVFV __xc_z[];    // C++初始化器

// 调用C构造函数
static int _initterm_e(_PIFV * pfbegin, _PIFV * pfend) {
        int ret = 0;

        // 从下到上遍历函数指针表,直到
        // 遇到结尾。不要跳过第一个条目。初始
        // pfbegin的值指向第一个有效条目。不要试图
        // 执行pfend指向的内容。只有pfend之前的条目才有效。
        while ( pfbegin < pfend  && ret == 0)
        {
            //如果当前表项非空,则通过它进行调用
            if ( *pfbegin != 0 )
                ret = (**pfbegin)();
            ++pfbegin;
        }

        return ret;
}

// 调用C构造函数
static void _initterm (_PVFV * pfbegin, _PVFV * pfend)
{
        // 从下到上遍历函数指针表,直到
        // 遇到结尾。不要跳过第一个条目。初始
        // pfbegin的值指向第一个有效条目。不要试图
        // 执行pfend指向的内容。只有pfend之前的条目才有效。
        while ( pfbegin < pfend )
        {
            //如果当前表项非空,则通过它进行调用
            if ( *pfbegin != 0 )
                (**pfbegin)();
            ++pfbegin;
        }
}

// 尽快调用此函数。基本上应该是你现在
// 就要跳转到C/C++内核中。但请记住,内核尚未初始化,
// 而且你不能在构造函数中使用很多东西!
bool CallConstructors() {
	// 执行C初始化
	int initret = _initterm_e(__xi_a, __xi_z);
	if ( initret != 0 ) {
            return false;
	}

        // 执行C++初始化
        _initterm(__xc_a, __xc_z);
	return true;
}


new和delete运算符

你首先要做的事情之一就是实现new和delete运算符。 一开始,你还不能真正实现它们,只需要有它们的存根。 稍后,当你的内存管理器工作时,你可以完全实现它们。 下面是存根:

void* __cdecl operator new(size_t size)
{
	// 分配内存
	return 0;
}


void* __cdecl operator new[](size_t size)
{
	// 分配内存
	return 0;
}


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

	// 释放分配的内存
}

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

	// 释放分配的内存
}


如果你想要使用placement new(定位放置new),则需要将以下实现放入一个头文件中,并在需要时将其包括在内。

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


另见

文章

外部链接