SylixOS动态加载器系列文章(6) C++支持

来源:互联网 发布:36氪的next网站源码 编辑:程序博客网 时间:2024/04/29 14:26

全局对象构造函数和析构函数

前面文章已有说明,c++全局对象构造/析构函数在内核模块和共享库中的处理方式不一样。内核模块中由加载器按节名称查找,应用程序和共享库中在dynamic段中查找。然后在模块初始化和销毁阶段调用。

静态局部对象

c++静态局部对象的构造和析构流程则要比全局对象复杂很多,主要原因是不确定静态局部对象在何时构造。静态局部对象在第一次访问时构造,构造时会调用__cxa_atexit函数注册析构函数到一个全局链表,在模块卸载时,SylixOS系统查找已注册析构函数链表,调用并删除函数地址位于被卸载模块的析构函数。这一实现方式与linux有区别,linux在函数__cxa_atexit注册时传入一个唯一的模块句柄(编译器生成的一个模块全局变量),模块卸载时根据这个模块局部查找析构函数。SylixOS的编译器不能生成这个模块句柄,SylixOS应用程序可以在链接libsohandle.a的到这个句柄,但是是可选的。即使没有这个句柄,SylixOS也能实现相同的功能。

另外静态全局对象的构造是要加锁保护的,防止多线程环境下被不同线程多次调用构造函数。在调用构造函数前,编译器会生成代码调用__cxa_guard_acquire函数获取锁,构造完成后编译器会调用__cxa_guard_release函数释放锁。

       所以为支持静态局部对象,加载器需要实现如下ABI函数,事实上远不止这些,具体可以查看SylixOS源码。

int  __cxa_guard_acquire(int volatile  *piGv);

void  __cxa_guard_release(int volatile *piGv);

int  __cxa_atexit(void (*f)(void *), void *p, void *d);

c++操作符

为支持c++,SylixOS实现了自己的new和delete操作符,定义如下:

void  *operator  new (size_t  stSize)

{

    return  ((void *)lib_malloc_new(stSize));

}

void  *operator  new[] (size_t   stSize)

{

    return  ((void *)lib_malloc_new(stSize));

}

void  operator  delete (void *pvMem)

{

    if (pvMem) {

        lib_free(pvMem);

    }

}

void  operator  delete[] (void  *pvMem)

{

    if (pvMem) {

        lib_free(pvMem);

    }

}

 RTTI支持

RTTI(Run-Time Type Information),通过运行时类型信息程序能够使用基类指针或引用来检查这些指针或引用所指的对象的实际派生类型。SylixOS加载器无需做太多工作,这个主要由编译器配合stdc++库实现。

c++异常

异常是c++相对于c的一大特色功能,其实现相当负责,涉及到大量的堆栈回溯工作。再次感谢强大的编译器为我们做了大部分工作,编译只需要加载器实现一些ABI函数,而这些函数大部分也已经在stdc++中有默认实现,可以直接在SylixOS中使用。在ARM体系结构中,加载器只需要额外实现一个函数。

_Unwind_Ptr dl_unwind_find_exidx (_Unwind_Ptr pc, int*pcount, PVOID *pvVProc);

       函数原型解析:

l  返回pc对应模块的ARM.exidx 段内存地址。ARM.exidx 段是ELF中类型为PT_ARM_EXIDX的段,模块加载时加载器将其记录到模块结构中。

l  参数pc是需要查找的地址。

l  参数pcount是ARM.exidx段中表项的数量。

l  参数pvVProc是要查找的进程,只查找该进程的模块。

ARM.exidx 段的实现原理很复杂,简单的说,它提供了在异常产生时堆栈回溯程序查找和访问ELF文件的方式。


SylixOS官网:www.sylixos.com

SylixOS源码下载:git.sylixos.com

SylixOS百科:wiki.sylixos.com


0 0