C++中_cdecl _stdcall _fastcall _thiscall関数呼び出し要約(照合アセンブリコード)
8629 ワード
まず、Visual Studio 2008でC++コードに対応するアセンブリコードを表示することを学びます.
プログラムにブレークポイントを追加してデバッガを開始すると、ファイルの中央を右クリック=)で逆アセンブリに移動し、アセンブリコードが表示されます.
アセンブリコードは//注釈、説明用//***/注釈で、それぞれ基本データ型、配列、ポインタ、参照の4種類のデータ型のパラメータを使用して比較し、コードは以下の通りである.
まとめ
プログラムにブレークポイントを追加してデバッガを開始すると、ファイルの中央を右クリック=)で逆アセンブリに移動し、アセンブリコードが表示されます.
アセンブリコードは//注釈、説明用//***/注釈で、それぞれ基本データ型、配列、ポインタ、参照の4種類のデータ型のパラメータを使用して比較し、コードは以下の通りである.
#include
using namespace std;
/*C,C++ default style
**arguments passing order: from right to left
**who clean stack: caller function*/
void __cdecl Cdecl(int a, int b[], int *c, int &d)
{
cout << endl;
cout << a++ << "/t" << b << "/t" << c << "/t" << d++ << "/t" << endl;
for(int i = 0; i < 3; i ++)
{
cout << b[i]++ << "/t";
}
cout << endl;
cout << "hello cdecl" << endl;
}
/*PASCAL,CALLBACK,Win32 API style
**arguments passing order: from right to left
**who clean stack: callee function*/
void __stdcall Stdcall(int a, int b[], int *c, int &d)
{
cout << endl;
cout << a++ << "/t" << b << "/t" << c << "/t" << d++ << "/t" << endl;
for(int i = 0; i < 3; i ++)
{
cout << b[i]++ << "/t";
}
cout << endl;
cout << "hello stdcall" << endl;
}
//0041175A pop edi
//0041175B pop esi
//0041175C pop ebx
//0041175D add esp,0C8h
//00411763 cmp ebp,esp
//00411765 call @ILT+440(__RTC_CheckEsp) (4111BDh)
//0041176A mov esp,ebp
//0041176C pop ebp
//0041176D ret 10h //clean the stack
/*A fast call style
**arguments passing order: from right to left
**who clean stack: callee function*/
void __fastcall Fastcall(int a, int b[], int *c, int &d)
{
cout << endl;
cout << a++ << "/t" << b << "/t" << c << "/t" << d++ << "/t" << endl;
for(int i = 0; i < 3; i ++)
{
cout << b[i]++ << "/t";
}
cout << endl;
cout << "hello fastcall" << endl;
}
//004118D2 pop edi
//004118D3 pop esi
//004118D4 pop ebx
//004118D5 add esp,0E0h
//004118DB cmp ebp,esp
//004118DD call @ILT+440(__RTC_CheckEsp) (4111BDh)
//004118E2 mov esp,ebp
//004118E4 pop ebp
//004118E5 ret 8 //clean the stack
class E
{
public:
int m_e; //member variable
static int m_s; //static variable
E(int e)
{
m_e = e;
}
/*static function invoke, just like the __cdecl style
**note: You can add the modifier __thiscall before the static function name,
but you cannot force the program pass THIS Pointer to static function
**arguments passing order: from right to left
**who clean stack: caller function*/
static void Staticcall(int a, int b[], int *c, int &d)
{
cout << endl;
m_s ++;
cout << a++ << "/t" << b << "/t" << c << "/t" << d++ << "/t" << endl;
for(int i = 0; i < 3; i ++)
{
cout << b[i]++ << "/t";
}
cout << endl;
cout << "hello staticcall" << endl;
}
//00412284 pop edi
//00412285 pop esi
//00412286 pop ebx
//00412287 add esp,0DCh
//0041228D cmp ebp,esp
//0041228F call @ILT+460(__RTC_CheckEsp) (4111D1h)
//00412294 mov esp,ebp
//00412296 pop ebp
//00412297 ret
/*(Only for) C++ member functions default style, ECX register contains THIS Pointer secretly
**note: You can change the modifier to __cdecl or another to change the arguments passing style or who clean stack responsibility,
but you cannot stopping THIS Pointer passing
**arguments passing order: from right to left
**who clean stack: callee function*/
void __thiscall Thiscall(int a, int b[], int *c, int &d)
{
cout << endl;
cout << a++ << "/t" << b << "/t" << c << "/t" << d++ << "/t" << endl;
for(int i = 0; i < 3; i ++)
{
cout << b[i]++ << "/t";
}
cout << endl;
cout << "hello thiscall" << endl;
}
//00411CDF pop edi
//00411CE0 pop esi
//00411CE1 pop ebx
//00411CE2 add esp,0D4h
//00411CE8 cmp ebp,esp
//00411CEA call @ILT+445(__RTC_CheckEsp) (4111C2h)
//00411CEF mov esp,ebp
//00411CF1 pop ebp
//00411CF2 ret 10h
};
int E::m_s = 0; //Initial static variable, it cannot be initialed in the class, only if it's a const value
int main(int argc, char *argv[])
{
//data
int a = 1; //sample data
int b[] = {1,2,3}; //array
int *c = (int *)malloc(sizeof(int)); //pointer
int d = 2; //for inference
E e1(1), e2(2); //for member/static function
cout << &e1 << "/t" << &e2 << endl;
printf("%p/t%p/n", &e1.m_e, &e2.m_e);
printf("%p/t%p/n", &E::Thiscall, &E::Staticcall);
cout << &E::Thiscall << "/t" << &E::Staticcall << endl;
cout << &e1.m_s << "/t" << &e2.m_s << "/t" << &E::m_s << "/t" << E::m_s << endl;
cout << "hello main" << endl;
Cdecl(a, b, c, d);
//00411838 lea eax,[d] //actually pass the address of the data
//0041183B push eax
//0041183C mov ecx,dword ptr [c]
//0041183F push ecx
//00411840 lea edx,[b]
//00411843 push edx
//00411844 mov eax,dword ptr [a]
//00411847 push eax
//00411848 call Cdecl (411032h)
//0041184D add esp,10h //clean the stack
Stdcall(a, b, c, d);
//00411A6F lea eax,[d]
//00411A72 push eax
//00411A73 mov ecx,dword ptr [c]
//00411A76 push ecx
//00411A77 lea edx,[b]
//00411A7A push edx
//00411A7B mov eax,dword ptr [a]
//00411A7E push eax
//00411A7F call Stdcall (41103Ch)
Fastcall(a, b, c, d);
//00411A84 lea eax,[d]
//00411A87 push eax
//00411A88 mov ecx,dword ptr [c]
//00411A8B push ecx
//00411A8C lea edx,[b]
//00411A8F mov ecx,dword ptr [a] //use two registers to pass the last two arguments(so called "fastcall")
//00411A92 call Fastcall (4110DCh)
e1.Thiscall(a, b, c, d);
//00411AD2 lea eax,[d]
//00411AD5 push eax
//00411AD6 mov ecx,dword ptr [c]
//00411AD9 push ecx
//00411ADA lea edx,[b]
//00411ADD push edx
//00411ADE mov eax,dword ptr [a]
//00411AE1 push eax
//00411AE2 lea ecx,[e] //a secret extra parameter
//00411AE5 call E::Thiscall (41105Fh)
E::Staticcall(a, b, c, d);
//00411B04 lea eax,[d]
//00411B07 push eax
//00411B08 mov ecx,dword ptr [c]
//00411B0B push ecx
//00411B0C lea edx,[b]
//00411B0F push edx
//00411B10 mov eax,dword ptr [a]
//00411B13 push eax
//00411B14 call E::Staticcall (4110A5h)
//00411B19 add esp,10h //clean the stack
return 0;
}
まとめ