프로그래밍2006.03.10 18:00
-- Calling Conventions (콜링 컨벤션)에 대한 정리

콜링 컨벤션(Calling Conventions)란?
Microsoft의 Calling Conventions은 모두 5가지 종류의 Calling Conventions가 존재 한다.
각각의 차이점은 스택을 어떤 식으로 관리하고 또한 어떤 방법을로 인자를 전달하느냐의 차이가 있다.


1) __cdecl
. 인자 전달순서는 RIGHT -> LEFT 순서
. 스택관리를 호출한곳에서 관리한다.
. 함수의 이름에 _ 가 붙는다. ex) _Test
. 기본 호출 규약이므로 /Gz (stdcall) 또는 /Gr (fastcall) 옵션이 켜졌을 때, 필요한 변수나 함수 이름 앞에 __cdecl을 놓으면 된다.
/Gd 옵션은 강제로 __cdecl 규약으로 호출한다.

ex) _CRTIMP int __cdecl system(const char *);


2) __stdcall
. 인자 전달순서는 RIGHT -> LEFT 순서
. 스택관리를 호출 받은곳에서 관리한다.
. 함수의 이름에 _ 가 붙으며 뒤에 @가 붙은후 인자목록의 바이트수(10진수)가 붙는다. ex) int Test(int a, double b)는 _Test@12
. /Gz 옵션은 호출규약이 명시적으로 선언되지 않은 모든 함수를 __stdcall로 만든다. __stdcall 형식으로 선언된 함수는 __cdecl 형식으로 값을 리턴한다

ex) #define WINAPI __stdcall


3) __fastcall
. 처음 2개의 DWORD 또는 더 작은 인자들이 ECX와 EDX 레지스터로 전달. 나머지 인자들은 오른쪽 --> 왼쪽으로 스택에 저장.
. 스택관리를 호출 받은곳에서 관리한다.
. 함수의 이름에 @가 붙은후 인자목록의 바이트수(10진수)가 붙는다. ex) int Test(int a, double b)는 Test@12
. /Gr 옵션은 선언된 함수가 충돌하지 않고 이름이 main이 아니라면, 모듈 내 각 함수를 fastcall로 컴파일한다.

ex) void __fastcall Test(void);


4) thiscall
가변인자를 사용하지 않는 C++ 멤버함수의 기본 호출 규약. 호출한곳에서 스택을 관리하고 스택 끝에 this 포인터를 넣으며,
컴파일시 컴파일러에 의해 가변인자(vararg) 함수는 __cdecl로 변경된다.
thiscall은 키워드가 아니므로 thiscall 호출 규약은 명시적으로 사용될 수 없다.
모든 함수인자들은 스택 상에 놓여지며, 이 호출규약은 C++에만 적용되므로, C 이름 장식 스키마는 없다.

5) naked
. 인자 전달순서는 RIGHT -> LEFT 순서
. 스택관리를 호출한곳에서 관리한다.
. VxDs에서만 사용한다.


< SAMPLE CODE >
http://www.cs.cornell.edu/courses/cs412/2001sp/resources/microsoft-calling-conventions.html

// The strings passed to each function.
static char * g_szStdCall = "__stdcall" ;
static char * g_szCdeclCall = "__cdecl" ;
static char * g_szFastCall = "__fastcall" ;
static char * g_szNakedCall = "__naked" ;

// The extern "C" turns off all C++ name decoration.
extern "C"
{
// The __cdecl function.
void CDeclFunction ( char * szString ,
unsigned long ulLong ,
char chChar ) ;
// The __stdcall function.
void __stdcall StdCallFunction ( char * szString ,
unsigned long ulLong ,
char chChar ) ;
// The __fastcall function.
void __fastcall FastCallFunction ( char * szString ,
unsigned long ulLong ,
char chChar ) ;
// The naked function. The declspec goes on the definition, not the
// declaration.
int NakedCallFunction ( char * szString ,
unsigned long ulLong ,
char chChar ) ;
}
void main ( void )
{
00401000 55 push ebp
00401001 8B EC mov ebp,esp
00401003 53 push ebx
00401004 56 push esi
00401005 57 push edi
// Call each function to generate the code.
CDeclFunction ( g_szCdeclCall , 1 , 'a' ) ;
00401008 6A 61 push 61h
0040100A 6A 01 push 1
0040100C A1 14 30 40 00 mov eax,[00403014]
00401011 50 push eax
00401012 E8 45 00 00 00 call 0040105C
00401017 83 C4 0C add esp,0Ch
StdCallFunction ( g_szStdCall , 2 , 'b' ) ;
0040101C 6A 62 push 62h
0040101E 6A 02 push 2
00401020 8B 0D 10 30 40 00 mov ecx,dword ptr ds:[00403010h]
00401026 51 push ecx
00401027 E8 3D 00 00 00 call 00401069
FastCallFunction ( g_szFastCall , 3 , 'c' ) ;
0040102E 6A 63 push 63h
00401030 BA 03 00 00 00 mov edx,3
00401035 8B 0D 18 30 40 00 mov ecx,dword ptr ds:[00403018h]
0040103B E8 38 00 00 00 call 00401078
NakedCallFunction ( g_szNakedCall , 4 , 'd' ) ;
00401042 6A 64 push 64h
00401044 6A 04 push 4
00401046 8B 15 1C 30 40 00 mov edx,dword ptr ds:[0040301Ch]
0040104C 52 push edx
0040104D E8 40 00 00 00 call 00401092
00401052 83 C4 0C add esp,0Ch
}
00401057 5F pop edi
00401058 5E pop esi
00401059 5B pop ebx
0040105A 5D pop ebp
0040105B C3 ret
void CDeclFunction ( char * szString ,
unsigned long ulLong ,
char chChar )
{
0040105C 55 push ebp
0040105D 8B EC mov ebp,esp
0040105F 53 push ebx
00401060 56 push esi
00401061 57 push edi
__asm NOP __asm NOP // NOPs stand for the function body here
00401062 90 nop
00401063 90 nop
}
00401064 5F pop edi
00401065 5E pop esi
00401066 5B pop ebx
00401067 5D pop ebp
00401068 C3 ret
void __stdcall StdCallFunction ( char * szString ,
unsigned long ulLong ,
char chChar )
{
00401069 55 push ebp
0040106A 8B EC mov ebp,esp
0040106C 53 push ebx
0040106D 56 push esi
0040106E 57 push edi
__asm NOP __asm NOP
0040106F 90 nop
00401070 90 nop
}
00401071 5F pop edi
00401072 5E pop esi
00401073 5B pop ebx
00401074 5D pop ebp
00401075 C2 0C 00 ret 0Ch
void __fastcall FastCallFunction ( char * szString ,
unsigned long ulLong ,
char chChar )
{
00401078 55 push ebp
00401079 8B EC mov ebp,esp
0040107B 83 EC 08 sub esp,8
0040107E 53 push ebx
0040107F 56 push esi
00401080 57 push edi
00401081 89 55 F8 mov dword ptr [ebp-8],edx
00401084 89 4D FC mov dword ptr [ebp-4],ecx
__asm NOP __asm NOP
00401087 90 nop
00401088 90 nop
}
00401089 5F pop edi
0040108A 5E pop esi
0040108B 5B pop ebx
0040108C 8B E5 mov esp,ebp
0040108E 5D pop ebp
0040108F C2 04 00 ret 4
78:
__declspec(naked) int NakedCallFunction ( char * szString ,
unsigned long ulLong ,
char chChar )
{
__asm NOP __asm NOP
00401092 90 nop
00401093 90 nop
// Naked functions must EXPLICITLY do a return.
__asm RET
00401094 C3 ret

< 참고자료 >
꼭 한번 보시길.
http://www.unixwiz.net/techtips/win32-callconv.html
Posted by codesafe