首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

从Entry Point到main函数调用(五):cinit

2012-11-10 
从Entry Point到main函数调用(5):_cinit_cinit在完成了_setargv() 以及_setenvp() 之后,进入到_cinit 函数

从Entry Point到main函数调用(5):_cinit
_cinit

在完成了_setargv() 以及_setenvp() 之后,进入到_cinit 函数。该函数的注释很短,就一句“do C data initialize”,让人完全摸不着头脑。不过不用着急,可以阅读_cinit 函数的实现来加以分析。

?

_cinit 函数很短,大致上分为三个步骤:

1. _fpmath() 或者 (*_FPinit)();

2. _initterm( __xi_a, __xi_z );

3. _initterm( __xc_a, __xc_z );

?

第一步是可选的,_FPinit 主要用来初始化浮点运算。只有当用户写的代码中出现了浮点运算,_FPinit 才会被定义。关于_FPinit 由于MSDN 上没相关资料,在此不做深究。

?

第二步和第三步是分别对C和C++程序做初始化。_initterm 接受两个指针作为参数,这两个指针中间的内存区域是一张函数指针表。_initterm 会从第一个指针开始,慢慢向后寻找,直到第二个指针结束,中间如果找到了一块内存表示一个函数指针,则执行该函数。

?

这里的两个call 分别表示调用了 _initterm( __xi_a, __xi_z ) 和_initterm( __xc_a, __xc_z ) 。对应的有:

__xi_a = 00406008

__xi_z = 00406010

__xc_a = 00406000

__xc_z = 00406004

?

继续跟进可以发现,在00406008 至 00406010之间仅有一个函数指针,指向__initmbctable()函数。__initmbctable() 在第(4)篇_setargv 中曾经有过介绍,它会创建一个新的int foo(){int a=1;int b=9;return a+b;}int a = foo();void main(){}

注意这里的全局变量a,C语言里是不会允许这种写法的,在C中全局变量只能用常量进行赋值。准确说C中的全局变量在编译期就需要被确定,链接器会把所有的全局变量都放进PE的data区域。说白了,这些全局变量都是直接写死在PE中的。

?

但是C++ 中确允许像上面那样动态赋值,原因就在于第二次调用 initterm 时,会调用foo函数为A进行初始化。对于上面的C++代码:

_initterm( __xi_a, __xi_z )? ------> 调用__initmbctable() ------> 实际上没做什么_initterm( __xc_a, __xc_z ) ------> 调用foo()函数

利用_initterm( __xc_a, __xc_z ) 对C++ data 进行 initialization 有点儿复杂,这里不讨论。

?

?

另参考:

http://blog.donews.com/x140yu/archive/2005/05/26/399256.aspx

?

?

?

?

?

热点排行