九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

C++中的成员函数调用原理及this指针的传递方式


C++中的成员函数调用原理及this指针的传递方式

write by 九天雁翎(JTianLing) -- www.jtianling.com

测试 源代码:

 1 #include
 2 #include
 3
 4 class CTestThisPointer
 5 {
 6 public:
 7     CTestThisPointer(int ai):mi(ai) { }
 8     int Add(int ai)
 9     {
10         mi += ai;
11         return mi;
12     }
13     
14 private:
15     int mi;
16 };
17
18
19 int main()
20 {
21     CTestThisPointer loTest(10);
22
23     printf("%d",loTest.Add(5));
24     return 0;
25 }
26

 

反汇编:

.text:00401000 ; int __cdecl main(int argc, const char **argv, const char *envp)

.text:00401000 _main proc near ; CODE XREF: _mainCRTStartup+AFp

.text:00401000

.text:00401000 this = byte ptr -4

.text:00401000 argc = dword ptr 8

.text:00401000 argv = dword ptr 0Ch

.text:00401000 envp = dword ptr 10h

.text:00401000

.text:00401000 push ebp ; 在默认优化的时候,总算看到了正统的一个push ebp;

.text:00401000 ; mov ebp,esp的保护堆栈并用ebp的过程

.text:00401001 mov ebp, esp

.text:00401003 push ecx

.text:00401004 push 0Ah ; 构造函数的除了默认this外的唯一参数,10

.text:00401006 lea ecx, [ebp+this] ; 这个参数时this指针,通过寄存器ecx传递

.text:00401009 call CTestThisPointer__CTestThisPointer

.text:0040100E push 5 ; Add函数除默认的this外唯一的参数,5

.text:00401010 lea ecx, [ebp+this] ; this指针

.text:00401013 call CTestThisPointer__Add

.text:00401018 push eax ; 将add的返回值入栈,调用printf

.text:00401019 push offset aD ; "%d"

.text:0040101E call _printf

.text:00401023 add esp, 8 ; 变长参数的函数,只能是通过__cdecl调用约定罗,由main

.text:00401023 ; 函数来维护栈平衡

.text:00401026 xor eax, eax

.text:00401028 mov esp, ebp

.text:0040102A pop ebp

.text:0040102B retn

.text:0040102B _main endp

 

 

构造函数:

.text:00401030 CTestThisPointer__CTestThisPointer proc near ; CODE XREF: _main+9p

.text:00401030

.text:00401030 var_4 = dword ptr -4

.text:00401030 arg_0 = dword ptr 8

.text:00401030

.text:00401030 push ebp

.text:00401031 mov ebp, esp

.text:00401033 push ecx ; 将this指针入栈保存

.text:00401034 mov [ebp+var_4], ecx

.text:00401037 mov eax, [ebp+var_4] ; 将this的值传给eax,默认优化的代码实在够繁琐,接下来

.text:00401037 ; 几步都是的,其实本质无非就是一个

.text:00401037 ; mov [ecx],[ebp+arg_0]的过程,但是因为不能直接的从

.text:00401037 ; 内存mov到内存,所以中间用了临时变量,但是因为要用

.text:00401037 ; 寄存器做临时变量,所以得先保存寄存器。。。。。

.text:00401037 ; 其实还有那么多寄存器,咋不用呢?呵呵,因为是默认优化

.text:0040103A mov ecx, [ebp+arg_0]

.text:0040103D mov [eax], ecx

.text:0040103F mov eax, [ebp+var_4]

.text:00401042 mov esp, ebp

.text:00401044 pop ebp

.text:00401045 retn 4

.text:00401045 CTestThisPointer__CTestThisPointer endp

 

 

Add函数:

.text:00401050 CTestThisPointer__Add proc near ; CODE XREF: _main+13p

.text:00401050

.text:00401050 var_4 = dword ptr -4

.text:00401050 arg_0 = dword ptr 8

.text:00401050

.text:00401050 push ebp

.text:00401051 mov ebp, esp

.text:00401053 push ecx

.text:00401054 mov [ebp+var_4], ecx ; 这个临时变量用的最费

.text:00401057 mov eax, [ebp+var_4]

.text:0040105A mov ecx, [eax]

.text:0040105C add ecx, [ebp+arg_0] ; 因为返回的是mi,所以以下是老老实实的取出this指针中的

.text:0040105C ; 地址到寄存器,然后在通过mov re,[re]的形式取出值

.text:0040105C ; BTW:看没有优化的代码实在不习惯

.text:0040105F mov edx, [ebp+var_4]

.text:00401062 mov [edx], ecx

.text:00401064 mov eax, [ebp+var_4]

.text:00401067 mov eax, [eax]

.text:00401069 mov esp, ebp

.text:0040106B pop ebp

.text:0040106C retn 4

.text:0040106C CTestThisPointer__Add endp

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

分类:  汇编和反汇编 
标签:  C++ 

Posted By 九天雁翎 at 九天雁翎的博客 on 2009年06月14日

前一篇: C/C++与汇编的函数相互调用分析 后一篇: C++中的虚函数调用原理的反汇编实例分析(1)