_cinit
来源:互联网 发布:万游网络武汉 编辑:程序博客网 时间:2024/06/05 08:20
前言
如果有全局类数组,在main之前类数组会被初始化, 类的构造会被调用.
全局类的初始化由_cinit的第二个_initterm发起.
记录
_cinit 在\VC98\CRT\SRC\CRT0DAT.C
void __cdecl _cinit ( void ){ /* * initialize floating point package, if present */#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) /* * MIPS compiler doesn't emit external reference to _fltused. Therefore, * must always force in the floating point initialization. */ _fpmath();#else /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */ if ( _FPinit != NULL ) (*_FPinit)();#endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */ /* * do initializations */ _initterm( __xi_a, __xi_z ); /* * do C++ initializations */ // __xc_a(函数指针表开始地址) 和 __xc_z (函数指针表结束地址) 是编译器填写的 // 从__xc_a开始, 到 (__xc_z - 4)是函数指针表, 里面的内容是代理函数地址. _initterm( __xc_a, __xc_z ); ///< 负责全局类的初始化, 调用类的构造}
_initterm 也在\VC98\CRT\SRC\CRT0DAT.C
#ifdef CRTDLLvoid __cdecl _initterm (#else /* CRTDLL */static void __cdecl _initterm (#endif /* CRTDLL */ _PVFV * pfbegin, _PVFV * pfend ){ /* * walk the table of function pointers from the bottom up, until * the end is encountered. Do not skip the first entry. The initial * value of pfbegin points to the first valid entry. Do not try to * execute what pfend points to. Only entries before pfend are valid. */ // cmp a, b // a 和 b 都是无符号数, // 当 a >= b 时, CF = 0, jnb成立 // 当 a < b 时, CF = 1, 会进入到循环内 // jnb xx // 跳到循环外 while ( pfbegin < pfend ) //< 这里的反汇编比较是 jnb { // jnb 不成立时, 进入到这里 /* * if current table entry is non-NULL, call thru it. */ if ( *pfbegin != NULL ) (**pfbegin)(); ++pfbegin; }}
185: * do initializations186: */187: _initterm( __xi_a, __xi_z );00404282 68 20 B6 42 00 push offset ___xi_z (0042b620)00404287 68 0C B3 42 00 push offset ___xi_a (0042b30c)0040428C E8 7F 01 00 00 call _initterm (00404410)00404291 83 C4 08 add esp,8188:189: /*190: * do C++ initializations191: */192: _initterm( __xc_a, __xc_z );00404294 68 08 B2 42 00 push offset ___xc_z (0042b208)00404299 68 00 B0 42 00 push offset ___xc_a (0042b000)0040429E E8 6D 01 00 00 call _initterm (00404410)004042A3 83 C4 08 add esp,8193:194: }
0042b000 ~ 0042b204 是初始化函数指针表
debug版里面不一定都是有函数地址,可能有一大片是空的.
release版会做成有效函数地址连续摆放.
初始化函数指针表中放的是初始化代理函数,离真正用户写的初始化函数还有好远.
00404428 8B 45 08 mov eax,dword ptr [pfbegin]0040442B 83 C0 04 add eax,40040442E 89 45 08 mov dword ptr [pfbegin],eax
- pfbegin 0x0042b104 $S3
函数
0042B104 A0 12 40 00 00 00 00 00 00 00 00 00 00 00 00 00 ..@………….
$E2是代理函数
$E2:004012A0 55 push ebp004012A1 8B EC mov ebp,esp004012A3 83 EC 40 sub esp,40h004012A6 53 push ebx004012A7 56 push esi004012A8 57 push edi004012A9 8D 7D C0 lea edi,[ebp-40h]004012AC B9 10 00 00 00 mov ecx,10h004012B1 B8 CC CC CC CC mov eax,0CCCCCCCCh004012B6 F3 AB rep stos dword ptr [edi]004012B8 E8 23 00 00 00 call $E1 (004012e0)004012BD 5F pop edi004012BE 5E pop esi004012BF 5B pop ebx004012C0 83 C4 40 add esp,40h004012C3 3B EC cmp ebp,esp004012C5 E8 16 18 00 00 call __chkesp (00402ae0)004012CA 8B E5 mov esp,ebp004012CC 5D pop ebp004012CD C3 ret
call $E1 (004012e0)
$E1 才是用户写的初始化代码
307: COffset g_AryMoveToNextStep[4] = {COffset(-1, 0), COffset(0, -1), COffset(1, 0), COffset(0, 1)};004012E0 55 push ebp004012E1 8B EC mov ebp,esp004012E3 83 EC 40 sub esp,40h004012E6 53 push ebx004012E7 56 push esi004012E8 57 push edi004012E9 8D 7D C0 lea edi,[ebp-40h]004012EC B9 10 00 00 00 mov ecx,10h004012F1 B8 CC CC CC CC mov eax,0CCCCCCCCh004012F6 F3 AB rep stos dword ptr [edi]004012F8 6A 00 push 0004012FA 6A FF push 0FFh004012FC B9 28 F4 42 00 mov ecx,offset g_AryMoveToNextStep (0042f428)00401301 E8 4F FD FF FF call @ILT+80(COffset::COffset) (00401055)00401306 6A FF push 0FFh00401308 6A 00 push 00040130A B9 30 F4 42 00 mov ecx,offset g_AryMoveToNextStep+8 (0042f430)0040130F E8 41 FD FF FF call @ILT+80(COffset::COffset) (00401055)00401314 6A 00 push 000401316 6A 01 push 100401318 B9 38 F4 42 00 mov ecx,offset g_AryMoveToNextStep+10h (0042f438)0040131D E8 33 FD FF FF call @ILT+80(COffset::COffset) (00401055)00401322 6A 01 push 100401324 6A 00 push 000401326 B9 40 F4 42 00 mov ecx,offset g_AryMoveToNextStep+18h (0042f440)0040132B E8 25 FD FF FF call @ILT+80(COffset::COffset) (00401055)00401330 5F pop edi00401331 5E pop esi00401332 5B pop ebx00401333 83 C4 40 add esp,40h00401336 3B EC cmp ebp,esp00401338 E8 A3 17 00 00 call __chkesp (00402ae0)0040133D 8B E5 mov esp,ebp0040133F 5D pop ebp00401340 C3 ret
在_cinit的第二个_initterm的入参上,能找到初始化函数的地址. 此时,是在main之前跑的代码.
0 0
- _cinit
- 从Entry Point到main函数调用(5):_cinit
- VS下EXE可执行文件启动代码剖析(4)_cinit 函数
- hdu4221 Greedy?
- 深入浅出RxJava(二:操作符)
- 欢迎使用CSDN-markdown编辑器
- 任务一 HelloWorld
- OpenCV 图像线性滤波综合示例程序(用到了Trackbar轨迹条)
- _cinit
- Hibernate JAP 字段自动添加下划线问题,
- 基于c++标准库计算文件大小
- 第三章习题3-第6题==判断完数
- 滑动窗口机制
- 第三周 项目4-顺序表的应用
- PHP中echo和print的区别
- Linux的哲学思想
- 深入浅出RxJava三--响应式的好处