本博客(http://blog.csdn.net/livelylittlefish )贴出作者(三二一@小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!
Explanation about “pure virtual function call” on Win32 platform
Content
0. Introduction
1. an example
2. Disassemble code analysis
3. jump table of this program
4. _purecall function & its disassemble code
5. where is the message from?
5.1 _RT_PUREVIRT macro
5.2 _RT_PUREVIRT_TXT macro
5.3 rterrs array
6. which function does it prompt the message?
6.1 _NMSG_WRITE function
6.2 call stack
7. how does it be when the pure virtual function is implemented explicitly?
7.1 implement it inside of class
7.2 implement it outside of class
8. Summary
0. Introduction
In this article, we will not explain why does it prompt “pure virtual function call” and how to prompt “pure virtual function call”, but detailed explain the program itself when we call a pure virtual directly/indirectly in a constructor/destructor on win32 platform. This issue on Linux platform will be introduced in another article.
At the beginning, a classical example will be shown, in this example, it will prompt a message box with “pure virtual function call”.
1. An example
Running result:
From the example, we can conclude that,
In constructor/destructor,
l Direct call a pure virtual function, a compiling error will occur, such as
error LNK2001: unresolved external symbol "public: virtual double __thiscall Shape::area(void)const " (?area@Shape@@UBENXZ)
l Indirect call a pure virtual function, it will prompt “pure virtual function call”
2. Disassemble code analysis
Debug this program, we can see the disassemble code of Shape::value() listed below, my comments embedded.
double value() const { 004118F0 push ebp 004118F1 mov ebp,esp 004118F3 sub esp,0CCh 004118F9 push ebx 004118FA push esi 004118FB push edi 004118FC push ecx 004118FD lea edi,[ebp-0CCh] 00411903 mov ecx,33h 00411908 mov eax,0CCCCCCCCh 0041190D rep stos dword ptr es:[edi] 0041190F pop ecx 00411910 mov dword ptr [ebp-8],ecx return ValuePerSquareUnit * area(); 00411913 mov eax,dword ptr [this] //eax = 0x003b5fc0, move ‘this’ pointer to eax 00411916 mov edx,dword ptr [eax] //edx = 0x00417800, move vfptr to edx 00411918 mov esi,esp 0041191A mov ecx,dword ptr [this] //ecx = 0x003b5fc0, move ‘this’ pointer to ecx 0041191D mov eax,dword ptr [edx] //eax = 0x004111f4, the address of __purecall, move the first virtual function address to eax 0041191F call eax //call this virtual function 00411921 cmp esi,esp 00411923 call @ILT+500(__RTC_CheckEsp) (4111F9h) 00411928 mov ecx,dword ptr [this] 0041192B fmul qword ptr [ecx+8] } 0041192E pop edi 0041192F pop esi 00411930 pop ebx 00411931 add esp,0CCh 00411937 cmp ebp,esp 00411939 call @ILT+500(__RTC_CheckEsp) (4111F9h) 0041193E mov esp,ebp 00411940 pop ebp 00411941 ret |
the disassemble codes and my comments can be verified from the following figure, which was captured from debuging.
3. jump table of this program
To find the address of 0x004111f4, it is necessary to find the jump table of this program in the disassemble codes. Then, we find it listed below, which lists all jump items.
00411005 jmp _setdefaultprecision (413E80h)
0041100A jmp _setargv (413F20h)
0041100F jmp std::ios_base::good (41283Ah)
00411014 jmp DebugBreak (414B78h)
00411019 jmp _RTC_GetErrDesc (413BE0h)
0041101E jmp Rectangle::area (411BD0h)
00411023 jmp __p__fmode (413F94h)
00411028 jmp __security_check_cookie (412870h)
0041102D jmp IsDebuggerPresent (414B6Ch)
00411032 jmp std::basic_ostream<char,std::char_traits<char> >::sentry::operator bool (412630h)
00411037 jmp type_info::operator= (412BA0h)
0041103C jmp _RTC_Terminate (413F60h)
00411041 jmp WideCharToMultiByte (414B7Eh)
<