_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

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

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
原创粉丝点击