|
内核当然可用用c++来些,但是相对c来说有许多要注意的地方,我们不得不关掉一些特性。这里只提一些gcc相关的内容,Microsoft
VC我没有尝试。转载请注明原创:天衣有缝(http://jinglexy.cublog.cn),MSN: jinglexy at
yahoo dot com dot cn
1)g++选项-nostartfiles:用户环境的在main之前调用的代码,当然不能使用了 2)全局对象:每种类型都有自己的构造函数,如果不自己编写代码调用,它们不会执行。 这包括所有全局对象和局部static对象,建议的做法是在内核栈建立后,c++运行代码执行之前 调用构造函数,如果构造函数没有运行(假设里面有分配内存之类的操作),后果很严重:) 我们可以这样做: 先修改gnu-ld链接脚本 .data : { start_ctors = .; *(.ctor*) end_ctors = .; start_dtors = .; *(.dtor*) end_dtors = .;
*(.data) } 这样构造函数的指针就都保存在start_ctors 和end_ctors之间的内存中了,构造函数其实就是void foo(void);形式的函数,编写一个for循环
调用它即可;析构函数也是一样的。当每个构造函数调用完后,gcc会自动调用一个函数: int __cxa_atexit(void (* f)(void *), void *p, void *d); 当内核退出时,会执行一个函数: void __cxa_finalize(void *d); 这两个函数必须按上面格式定义,g++是这样规定的。看看下面的代码就明白了: extern "C" { int __cxa_atexit(void (*f)(void *), void *p, void *d); void __cxa_finalize(void *d); };
void *__dso_handle; /*only the address of this symbol is taken by gcc*/
struct object { void (*f)(void*); void *p; void *d; } object[32] = {0}; unsigned int iObject = 0;
int __cxa_atexit(void (*f)(void *), void *p, void *d) { if (iObject >= 32) return -1; object[iObject].f = f; object[iObject].p = p; object[iObject].d = d; ++iObject; return 0; }
/* This currently destroys all objects */ void __cxa_finalize(void *d) { unsigned int i = iObject; for (; i > 0; --i) { --iObject; object[iObject].f(object[iObject].p); } }
3)new和delete:在完成内存管理后,重载类的new和delete函数 4)-nostdlib:把标准库禁用掉,最近有了移植stl到内核的想法 5)RTTI:最好是禁止它,这样不能用typeid 和 dynamic_cast了 6)禁用异常:-fno-exceptions,这个和操作系统太紧密了 7)纯虚函数,如果子类没有实现父类中的纯虚函数,链接到下面默认例程: extern "C" void __cxa_pure_virtual() { // print error message } 虽然不是为了定义纯虚类的对象,但是链接时编译器会抱怨,所以定义上面函数使编译通过。 8)如果一定要使用异常,rtti,new/delete,gcc中提供了静态库:libgcc/libsupc++, 还得写这个库的一些基础函数,觉得它应该是在上层抽象出接口,将底层实现空出来给用户实现。 而且代码本身非常复杂,网络上也没有任何中文资料。 指令: readelf -a `gcc -print-libgcc-file-name` 里面定义了很多的函数。
|