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
Posted By 九天雁翎 at 九天雁翎的博客 on 2009年06月14日