'Calling convention'에 해당되는 글 1건

  1. 2009.04.10 Calling Convention (VS)

Calling Convention (VS)

CS/Common 2009. 4. 10. 22:02
. 모든 calling convention에서 모든 Arguments는 함수로 전달될 32비트로 확장되며 리턴 값 또한 32비트로 확장되며, EAX에 리턴된다. 단, 8-byte 구조체에 대해서는 EDX:EAX 레지스터 쌍에 리턴된다.

. 더 큰 구조체는 리턴 구조체를 숨기기 위해서 EAX레지스터에 포인터로서 리턴된다.

. Parameter는 스택에 오른쪽에서 왼쪽으로 push 된다. 
(Structures that are not PODs will not be returned in registers.)

.만약 ESI, EDI, EBX, EBP 레지스터가 함수 내부에서 사용된다면, 컴파일러는 이들을 restore하고 save하기 위해서 prolog와 epilog 코드를 생성한다.



__cdecl 
Stack Cleanup : Caller
인자 전달 : 스택에 Parameters를 reverse order로 Push한다. (RIGHT to LEFT)

C/C++ 에서의 기본 Calling convention이다.
스택이 Caller에 의해서 cleanup 되기 때문에 가변인자 함수를 사용할 수 있다.
각 함수를 호출할 때마다 cleanup 코드를 포함하애 하기 때문에 __stdcall보다 큰 실행 파일을 생성한다.
__cdecl 변경자는 함수 이름이나 variable 전에 위치시킨다.
__cdecl을 강제하기 위해서는 /Gd 컴파일러 옵션을 지정한다.
/Gz(stdcall), /Gr(fastcall) 컴파일러 옵션을 지정했을 경우만 __cdecl을 필요로 한다.

// Example of the __cdecl keyword on function

int __cdecl system(const char *);

 

// Example of the __cdecl keyword on function pointer

typedef BOOL (__cdecl *funcname_ptr)(void * arg1, const char * arg2, DWORD flags, ...);

foo(1, 2, 3, 4);

004118F3  push        4   

004118F5  push        3   

004118F7  push        2   

004118F9  push        1   

004118FB  call        foo (411118h)

00411900  add         esp,10h

 

 

int __cdecl foo(int a, int b, int c, int d) {

00411840  push        ebp 

00411841  mov         ebp,esp

00411843  sub         esp,0CCh

00411849  push        ebx 

0041184A  push        esi 

0041184B  push        edi 

0041184C  lea         edi,[ebp-0CCh]

00411852  mov         ecx,33h

00411857  mov         eax,0CCCCCCCCh

0041185C  rep stos    dword ptr es:[edi]

    int x = a+b+c+d;

0041185E  mov         eax,dword ptr [a]

00411861  add         eax,dword ptr [b]

00411864  add         eax,dword ptr [c]

00411867  add         eax,dword ptr [d]

0041186A  mov         dword ptr [x],eax

    return x;

0041186D  mov         eax,dword ptr [x]

00411870  pop         edi 

00411871  pop         esi 

00411872  pop         ebx 

00411873  mov         esp,ebp

00411875  pop         ebp 

00411876  ret

}




__stdcall
Stack Cleanup : Callee
인자 전달 : 스택에 Parameters를 reverse order로 Push한다.(RIGHT TO LEFT)

Win32 API를 호출하기 위해 사용된다. 
#define CALLBACK __stdcall #define WINAPI __stdcall #define WINAPIV __cdecl #define APIENTRY WINAPI

__stdcall을 강제하기 위해서는 /Gz 컴파일러 옵션을 지정한다.
__cdecl로 선언된 함수와 같은 방법으로 values를 리턴한다.

// Example of the __stdcall keyword

#define WINAPI __stdcall

 

// Example of the __stdcall keyword on function pointer

typedef BOOL (__stdcall *funcname_ptr)

(void * arg1, const char * arg2, DWORD flags, ...);

foo(1, 2, 3, 4);

004118F3  push        4   

004118F5  push        3   

004118F7  push        2   

004118F9  push        1   

004118FB  call        foo (411249h)

 

 

int __stdcall foo(int a, int b, int c, int d) {

00411840  push        ebp 

00411841  mov         ebp,esp

00411843  sub         esp,0CCh

00411849  push        ebx 

0041184A  push        esi 

0041184B  push        edi 

0041184C  lea         edi,[ebp-0CCh]

00411852  mov         ecx,33h

00411857  mov         eax,0CCCCCCCCh

0041185C  rep stos    dword ptr es:[edi]

    int x = a+b+c+d;

0041185E  mov         eax,dword ptr [a]

00411861  add         eax,dword ptr [b]

00411864  add         eax,dword ptr [c]

00411867  add         eax,dword ptr [d]

0041186A  mov         dword ptr [x],eax

    return x;

0041186D  mov         eax,dword ptr [x]

00411870  pop         edi 

00411871  pop         esi 

00411872  pop         ebx 

00411873  mov         esp,ebp

00411875  pop         ebp 

00411876  ret         10h

}




__fastcall
Stack Cleanup : Callee
인자 전달 : Stored in registers, then pushed on stack

가능하다면 arguments가 함수에 레지스터를 통하여 전달된다.
이후의 컴파일러는 parameters를 저장하기 위해 다른 register를 사용할 수도 있다.
__fastcall을 강제하기 위해서는 /Gr 컴파일러 옵션을 지정한다.

// Example of the __fastcall keyword

#define FASTCALL    __fastcall

 

void FASTCALL DeleteAggrWrapper(void* pWrapper);

// Example of the __ fastcall keyword on function pointer

typedef BOOL (__fastcall *funcname_ptr)

(void * arg1, const char * arg2, DWORD flags, ...);

foo(1, 2, 3, 4);

004118F3  push        4   

004118F5  push        3   

004118F7  mov         edx,2

004118FC  mov         ecx,1

00411901  call        foo (41124Eh)

 

 

int __fastcall foo(int a, int b, int c, int d) {

004115D0  push        ebp 

004115D1  mov         ebp,esp

004115D3  sub         esp,0E4h

004115D9  push        ebx 

004115DA  push        esi 

004115DB  push        edi 

004115DC  push        ecx 

004115DD  lea         edi,[ebp-0E4h]

004115E3  mov         ecx,39h

004115E8  mov         eax,0CCCCCCCCh

004115ED  rep stos    dword ptr es:[edi]

004115EF  pop         ecx 

004115F0  mov         dword ptr [ebp-14h],edx

004115F3  mov         dword ptr [ebp-8],ecx

    int x = a+b+c+d;

004115F6  mov         eax,dword ptr [a]

004115F9  add         eax,dword ptr [b]

004115FC  add         eax,dword ptr [c]

004115FF  add         eax,dword ptr [d]

00411602  mov         dword ptr [x],eax

    return x;

00411605  mov         eax,dword ptr [x]

00411608  pop         edi 

00411609  pop         esi 

0041160A  pop         ebx 

0041160B  mov         esp,ebp

0041160D  pop         ebp 

0041160E  ret         8

}




__thiscall
Stack Cleanup : Callee
인자 전달 : Pushed on stack; this pointer stored in ECX



__clrcall
Stack Cleanup : n/a
인자 전달 : Parameters를 CLR expression stacke에 order로 Load한다.(left to right).


예전에 사용하던 블로그에 있던 글인데, 정리할 겸 다시 정리했다. 이놈의 calling convention은 왜 자꾸 까먹는건지.. ㅜㅜ

출처 : MSDN, 나의 옛 블로그
: