Posted on 2007-06-25 21:19
天衣有缝 阅读(3412)
评论(2) 编辑 收藏 引用 所属分类:
os stuff
内核当然可用用c++来些,但是相对c来说有许多要注意的地方,我们不得不关掉一些特性。这里只提一些gcc相关的内容,Microsoft VC我没有尝试。转载请注明原创:天衣有缝(http://www.cppblog.com/jinglexy),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`
里面定义了很多的函数。