_cinit

前言

如果有全局类数组,在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 CRTDLL
void __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 initializations
186:           */
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,8
188:
189:          /*
190:           * do C++ initializations
191:           */
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,8
193:
194:  }

0042b000 ~ 0042b204 是初始化函数指针表
debug版里面不一定都是有函数地址,可能有一大片是空的.
release版会做成有效函数地址连续摆放.

初始化函数指针表中放的是初始化代理函数,离真正用户写的初始化函数还有好远.

00404428 8B 45 08             mov         eax,dword ptr [pfbegin]
0040442B 83 C0 04             add         eax,4
0040442E 89 45 08             mov         dword ptr [pfbegin],eax
  • pfbegin 0x0042b104 $S3

函数 S3 E2在初始化函数指针表中的2级指针

0042B104 A0 12 40 00 00 00 00 00 00 00 00 00 00 00 00 00 ..@………….
$E2是代理函数

$E2:
004012A0 55                   push        ebp
004012A1 8B EC                mov         ebp,esp
004012A3 83 EC 40             sub         esp,40h
004012A6 53                   push        ebx
004012A7 56                   push        esi
004012A8 57                   push        edi
004012A9 8D 7D C0             lea         edi,[ebp-40h]
004012AC B9 10 00 00 00       mov         ecx,10h
004012B1 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
004012B6 F3 AB                rep stos    dword ptr [edi]
004012B8 E8 23 00 00 00       call        $E1 (004012e0)
004012BD 5F                   pop         edi
004012BE 5E                   pop         esi
004012BF 5B                   pop         ebx
004012C0 83 C4 40             add         esp,40h
004012C3 3B EC                cmp         ebp,esp
004012C5 E8 16 18 00 00       call        __chkesp (00402ae0)
004012CA 8B E5                mov         esp,ebp
004012CC 5D                   pop         ebp
004012CD 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        ebp
004012E1 8B EC                mov         ebp,esp
004012E3 83 EC 40             sub         esp,40h
004012E6 53                   push        ebx
004012E7 56                   push        esi
004012E8 57                   push        edi
004012E9 8D 7D C0             lea         edi,[ebp-40h]
004012EC B9 10 00 00 00       mov         ecx,10h
004012F1 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
004012F6 F3 AB                rep stos    dword ptr [edi]
004012F8 6A 00                push        0
004012FA 6A FF                push        0FFh
004012FC 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        0FFh
00401308 6A 00                push        0
0040130A 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        0
00401316 6A 01                push        1
00401318 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        1
00401324 6A 00                push        0
00401326 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         edi
00401331 5E                   pop         esi
00401332 5B                   pop         ebx
00401333 83 C4 40             add         esp,40h
00401336 3B EC                cmp         ebp,esp
00401338 E8 A3 17 00 00       call        __chkesp (00402ae0)
0040133D 8B E5                mov         esp,ebp
0040133F 5D                   pop         ebp
00401340 C3                   ret

在_cinit的第二个_initterm的入参上,能找到初始化函数的地址. 此时,是在main之前跑的代码.

你可能感兴趣的:(_cinit)