본문 바로가기

Research/Windows

C++ constructor 생성자 호출 방식




글로벌 오브젝트의 경우



           /*

            * do C++ constructors (initializers) specific to this EXE

            */

            if (__native_startup_state == __initializing)

010816CD A1 B0 33 08 01       mov         eax,dword ptr [___native_startup_state (10833B0h)]  

010816D2 3B C6                cmp         eax,esi  

010816D4 75 1B                jne         __tmainCRTStartup+0D0h (10816F1h)  

            {

                _initterm( __xc_a, __xc_z );

010816D6 68 F4 20 08 01       push        offset ___xc_z (10820F4h)  

010816DB 68 E8 20 08 01       push        offset ___xc_a (10820E8h)  

010816E0 E8 E7 05 00 00       call        _initterm (1081CCCh)  

010816E5 59                   pop         ecx  

010816E6 59                   pop         ecx  

                __native_startup_state = __initialized;

010816E7 C7 05 B0 33 08 01 02 00 00 00 mov         dword ptr [___native_startup_state (10833B0h)],2  

            }




__initterm:

6FC42627 8B FF                mov         edi,edi  

6FC42629 55                   push        ebp  

6FC4262A 8B EC                mov         ebp,esp  

6FC4262C 56                   push        esi  

6FC4262D 8B 75 08             mov         esi,dword ptr [ebp+8]  

6FC42630 3B 75 0C             cmp         esi,dword ptr [ebp+0Ch]  

6FC42633 73 0D                jae         __initterm+1Bh (6FC42642h)  

6FC42635 8B 06                mov         eax,dword ptr [esi]  

6FC42637 85 C0                test        eax,eax  

6FC42639 74 02                je          __initterm+13h (6FC4263Dh)  

6FC4263B FF D0                call        eax  

6FC4263D 83 C6 04             add         esi,4  

6FC42640 EB EE                jmp         __initterm+16h (6FC42630h)  

6FC42642 5E                   pop         esi  

6FC42643 5D                   pop         ebp  

6FC42644 C3                   ret  




MyObject hong(19, "Gildong Hong");

00CC2170 55                   push        ebp  

00CC2171 8B EC                mov         ebp,esp  

00CC2173 68 C4 31 CC 00       push        offset type_info::`vftable'+74h (0CC31C4h)  // "Gildong Hong"

00CC2178 6A 13                push        13h  

00CC217A B9 A0 43 CC 00       mov         ecx,offset hong (0CC43A0h)  // 할당한 메모리 공간

00CC217F E8 4C EF FF FF       call        MyObject::MyObject (0CC10D0h)  

00CC2184 68 A0 21 CC 00       push        offset `dynamic atexit destructor for 'hong'' (0CC21A0h)  

00CC2189 E8 1F F7 FF FF       call        atexit (0CC18ADh)  

00CC218E 83 C4 04             add         esp,4  

00CC2191 5D                   pop         ebp  

00CC2192 C3                   ret  




CRT STARTUP -> __initterm 에서 반복적으로 전역 오브젝트 생성자 호출.

글로벌 오브젝트의 생성자 위치는 CRT STARTUP 이며, 이 부분은 main 함수 이전/entry point 이후이다.










로컬 오브젝트의 경우




MyObject lee(23, "soonsin lee");

008111F6 68 D4 31 81 00       push        offset type_info::`vftable'+84h (8131D4h)  

008111FB 6A 17                push        17h  

008111FD 8D 4D EC             lea         ecx,[lee]  

00811200 E8 9B FE FF FF       call        MyObject::MyObject (8110A0h)  




MyObject lee(23);

00801226 6A 17                push        17h  

00801228 8D 4D EC             lea         ecx,[lee]  

0080122B E8 70 FE FF FF       call        MyObject::MyObject (8010A0h)  





로컬 오브젝트의 생성 과정에서는 객체 저장 공간으로 스택을 활용하는데 ecx 에 해당 객체를 위한 공간(스택)의 주소를 넣어 준다.

역으로 생각 했을 때, 초기화하지 않은 공간의 주소를 ecx 에 넣고 함수를 호출하는 부분이 있다면

그 부분은 생성자로 생각해도 무관하다.



객체의 멤버 함수를 호출할 때에 ecx 에 객체 주소를 달고 들어가는데

이는 객체함수 내부에서 this 라는 포인터 이름으로 표현된다.

로컬 오브젝트에서 함수를 호출한 경우 예를 들면 아래와 같다.





...

THIS  (ebp+4) ==> lee 를 가리키는 포인터

EBP

RET

ARG

 ...

lee (객체)



정리 겁나 대충이다