天衣有缝

冠盖满京华,斯人独憔悴~
posts - 35, comments - 115, trackbacks - 0, articles - 0
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
内核当然可用用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`
里面定义了很多的函数。

Feedback

# re: C++写内核需要注意的一些事情(原创)  回复  更多评论   

2007-12-22 09:30 by Nubix
顶一下

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理