__thiscall 是为了解决类成员调用中this指针传递而规定的。__thiscall要求把this指针放在特定寄存器中,该寄存器由编译器决定。VC使用ecx,Borland的C++编译器使用eax。
注 : 测试环境为VS2012 , 编译方式为Debug版.
测试代码:
#include "stdafx.h"
struct MyStruct
{
int x ;
int y ;
void Plus(int a, int b )
{
printf("%d\n",x+y+a+b) ;
}
};
void Plus(int a,int b)
{
printf("%d\n",1+2+a+b) ;
}
int _tmain(int argc, _TCHAR* argv[])
{
MyStruct haha ;
haha.x = 1 ;
haha.y = 2 ;
haha.Plus(3,4);
Plus(3,4);
return 0;
}
以上测试代中结构体内码成员函数是__thiscall调用方式 , 结构体外定义的Plus()函数 VS2012是默认__cdecl(即C调用方式) , 下面主要从三个方面比较两种调用方式区别
A : 参数传递顺序
B : 参数传递方式
C : 堆栈平衡
下面是两个函数内部的反汇编代码 :
26: haha.Plus(3,4);
013C3BA6 6A 04 push 4 <span style="color:#009900;">/* 参数1 入栈 */</span>
013C3BA8 6A 03 push 3 <span style="color:#009900;">/* 参数2 入栈 */</span>
013C3BAA 8D 4D F0 lea ecx,[ebp-10h] <span style="color:#009900;">/* this指针用ecx传递 */</span>
013C3BAD E8 56 D6 FF FF call 013C1208
27: Plus(3,4);
013C3BB2 6A 04 push 4
013C3BB4 6A 03 push 3
013C3BB6 E8 52 D6 FF FF call 013C120D
013C3BBB 83 C4 08 add esp,8 <span style="color:#009900;">/* 调用者平衡堆栈 */</span>
A : 参数传递顺序 B : 参数传递方式 C : 堆栈平衡
__thiscall( 即 <span style="color:#3333FF;">haha.Plus(3,4)</span> ) : 自右向左传参,最后传递this指针 普通参数用栈传递,this指针用ecx传递 被调用者平衡堆栈(内平栈)
__cdecl( 即 haha.Plus(3,4) ) : 自右向左传参 栈传递 调用者平衡堆栈(外平栈)
/************************************************************
*
* haha.Plus(3,4)函数内部(即__thiscall调用方式)
*
************************************************************/
10: void Plus(int a, int b )
11: {
013C39C0 55 push ebp
013C39C1 8B EC mov ebp,esp
013C39C3 81 EC CC 00 00 00 sub esp,0CCh
013C39C9 53 push ebx
013C39CA 56 push esi
013C39CB 57 push edi
013C39CC 51 push ecx <span style="color:#009900;">/* 保存现场 ,后面的填充0xCC会用到ecx */</span>
013C39CD 8D BD 34 FF FF FF lea edi,[ebp+FFFFFF34h]
013C39D3 B9 33 00 00 00 mov ecx,33h
013C39D8 B8 CC CC CC CC mov eax,0CCCCCCCCh
013C39DD F3 AB rep stos dword ptr es:[edi]
013C39DF 59 pop ecx
013C39E0 89 4D F8 mov dword ptr [ebp-8],ecx
12: printf("%d\n",x+y+a+b) ;
013C39E3 8B 45 F8 mov eax,dword ptr [ebp-8] <span style="color:#009900;">/***************</span>
013C39E6 8B 08 mov ecx,dword ptr [eax] <span style="color:#009900;">*</span>
013C39E8 8B 55 F8 mov edx,dword ptr [ebp-8] <span style="color:#009900;">* 函数核心功能</span>
013C39EB 03 4A 04 add ecx,dword ptr [edx+4] <span style="color:#009900;">*</span>
013C39EE 03 4D 08 add ecx,dword ptr [ebp+8] <span style="color:#009900;">*</span>
013C39F1 03 4D 0C add ecx,dword ptr [ebp+0Ch] <span style="color:#009900;"> ***************/</span>
013C39F4 8B F4 mov esi,esp
013C39F6 51 push ecx
013C39F7 68 A8 58 3C 01 push 13C58A8h
013C39FC FF 15 B8 92 3C 01 call dword ptr ds:[013C92B8h]
013C3A02 83 C4 08 add esp,8
013C3A05 3B F4 cmp esi,esp
013C3A07 E8 D4 D7 FF FF call 013C11E0
13: }
00393A0C 5F pop edi
00393A0D 5E pop esi
00393A0E 5B pop ebx
00393A0F 81 C4 CC 00 00 00 add esp,0CCh
00393A15 3B EC cmp ebp,esp
00393A17 E8 C4 D7 FF FF call 003911E0
00393A1C 8B E5 mov esp,ebp
00393A1E 5D pop ebp
00393A1F C2 08 00 ret 8 <span style="color:#009900;">/* 平衡堆栈(被调用者平衡堆栈) */</span>
/************************************************************
*
<span style="color:#009900;">* haha.Plus(3,4)函数内部(即__thiscall调用方式)
</span>
*
************************************************************/ 17: void Plus(int a,int b)
18: {
00393420 55 push ebp
00393421 8B EC mov ebp,esp
00393423 81 EC C0 00 00 00 sub esp,0C0h
00393429 53 push ebx
0039342A 56 push esi
0039342B 57 push edi
0039342C 8D BD 40 FF FF FF lea edi,[ebp+FFFFFF40h]
00393432 B9 30 00 00 00 mov ecx,30h
00393437 B8 CC CC CC CC mov eax,0CCCCCCCCh
0039343C F3 AB rep stos dword ptr es:[edi]
19: printf("%d\n",1+2+a+b) ;
0039343E 8B 45 0C mov eax,dword ptr [ebp+0Ch]
00393441 8B 4D 08 mov ecx,dword ptr [ebp+8]
00393444 8D 54 01 03 lea edx,[ecx+eax+3]
00393448 8B F4 mov esi,esp
0039344A 52 push edx
0039344B 68 A8 58 39 00 push 3958A8h
00393450 FF 15 B8 92 39 00 call dword ptr ds:[003992B8h]
00393456 83 C4 08 add esp,8
00393459 3B F4 cmp esi,esp
0039345B E8 80 DD FF FF call 003911E0
20: }
00393460 5F pop edi
00393461 5E pop esi
00393462 5B pop ebx
00393463 81 C4 C0 00 00 00 add esp,0C0h
00393469 3B EC cmp ebp,esp
0039346B E8 70 DD FF FF call 003911E0
00393470 8B E5 mov esp,ebp
00393472 5D pop ebp
00393473 C3 ret <span style="color:#009900;"> /* 直接返回 , 并没有在被调用函数内部平衡堆栈 */</span>