레이블이 cdecl인 게시물을 표시합니다. 모든 게시물 표시
레이블이 cdecl인 게시물을 표시합니다. 모든 게시물 표시

2009년 11월 25일 수요일

호출 규약(__cdecl, __stdcall)

호출 규약 (Calling Convention)

  1. 함수를 호출하는 방식에 대한 일종의 약속
  2. 인수는 어떻게 전달하며 리턴값은 어떻게 반환하고 인수 전달을 위해 사용한 메모리는 누가 정리할 것인지를 규정함.
  3. 호출하는 쪽과 호출되는 쪽의 약속이 맞아야 한다.
  4. 컴파일러 내부에서 일어난다.


 호출 규약인수 전달스택 정리이름 규칙
 __cdecl 오른쪽 먼저  호출원  _ 함수명
 __stdcall 오른쪽 먼저  함수  _함수명@인수크기
 __fastcall  ECX, EDX에 우선 전달,  나머지는 오른쪽 먼저  함수 @함수명@인수크기
 thiscall  오른쪽 먼저, this 포인터는 ecx 레지스터로 전달된다.  함수  C++ 이름 규칙 따름
 naked  오른쪽 먼저  함수  없음


(1) __cdecl
  1. C 컴파일러 혹은 C++ 컴파일러에서 전역 함수나 전역 static 함수, static 멤버 변수 호출에 기본적으로 사용하는 규약.
  2. 가변 인수를 지원
  3. 리턴값은 eax를 통해서 되돌려 받음.(다른 규약도 동일함)
(2) __stdcall
  1. 윈도우즈 API 함수들의 기본 호출 규약.(비주얼 베이직도 사용)
  2. __cdecl과 인수를 전달하는 방법은 동일하되 인수 전달에 사용된 스택을 정리하는 주체가 호출원이 아니라 함수라는 점이 다르다.
  3. 함수 이름 앞에 __stdcall 키워드를 사용하면 이 함수는 __stdcall 호출 규약을 사용한다.
  4. 가변 인수를 지원하지 않는다.
(3) __fastcall
  1. 인수 전달을 위해 스택을 쓰지 않고 레지스터를 우선적으로 사용하므로 인수 전달 속도가 빠르다
  2. 비주얼 C++은 fastcall을 형식적으로 지원할 뿐 fastcall의 장점을 취하진 않는다.(컴파일러 구현상 ecx, edx 레지스터가 꼭 필요하기 때문임)
  3. 이식성에 불리하다.(ecx, edx 레지스터를 사용하지 않는 CPU에서는 지원 안함)
  4. 볼랜드의 델파이가 __fastcall을 사용함.
(4) thiscall
  1. 클래스의 멤버 함수에 대해서만 적용됨.
  2. ecx로 객체의 포인터(this)가 전달되는 특징이 잇다.
  3. 나머지 규칙은 __stdcall과 동일함.
  4. 예외적으로 가변 인수를 사용하는 멤버 함수는 __cdecl로 작성되면 이때 this는 스택의 제일 마지막에(그러므로 첫번째 인수로) 전달된다.
  5. 이 호출 규약은 컴파일러가 멤버함수에 대해서만 적용하는 것이므로 일반 함수에는 이 호출 규약을 적용할 수 없다.(thiscall 키워드가 아님.)
(5) __naked
  1. 컴파일러가 접두, 접미를 작성하지 않는 호출 규약.
  2. 일반적인 목적으로는 사용되지 않음.
  3. C/C++이 아닌 언어에서 호출하는 함수를 작성할 때 필요함.
  4. 속도가 지극히 중요한 디바이스 드라이버를 작성할 때도 사용함.
  5. __naked 호출 규약을 사용하려면 함수의 정의부에 __declspec(naked)를 적어주면 된다.
(6) 기타(__pascal, __fortran, __syscall)

* __cdecl과 __stdcall의 차이점
  • 누가 스택을 정리하느냐
  • stdcall의 경우 호출된 함수(Callee)가 스택을 정리하기 때문에 호출하는 함수(Caller)와 Callee 모두 파라미터의 크기를 알고 있어야 정상적인 처리가 가능하다.
  • cdecl의 경우 Caller가 스택을 정리하기 때문에 Callee는 파라마티의 크기를 정확히 몰라도 된다.