__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>