January 22, 2008

__stdcall & __cdecl

WINDEF.H
CALLBACK = WINAPI = PASCAL = __stdcall
WINAPIV = __cdecl
위에서 알 수 있듯이, MS Windows의 calling convetion은 __stdcall과 __cdecl로 나뉜다.

이렇게 calling convetion을 둘로 나눈 이유는 함수 호출 후, stack pointer (sp)를 누가 원래데로 돌려놓을지 (정리할지)를 분간하기 위함이다. 결론 부터 애기하자면, __stdcall을 이요하면, callee측에서 sp를 정리하고, __cdecl을 이용하면, caller측에서 sp를 정리한다.

예를 들어보자.
SimpleFunction(TYPE arg1, TYPE arg2, TYPE arg3) { … }

SimpleFunction(…);
__cdecl의 경우, assembly code는 대략 다음과 같이 구성된다.
push arg3
push arg2
push arg1
call SimpleFunction
Add sp, 12

반면 __stdcall의 경우는 대락 다음과 같이 구성된다.
push arg3
push arg2
push arg1
call SimpleFunction

Assembly code를 보면 알 수 있듯이, __cdecl은 함수가 return된 이후에, caller가 직접 sp를 정리하고, __stdcall은 callee측에서 정리를 해주기 때문에, caller 쪽에서는 함수가 return된 이후에 sp 정리 작업을 하지 않는다.

sp의 정리를 어느 쪽에서 하든, 차이가 없어보이지만 두가지 정도 차이가 생길 수 있다.
먼저, 속도와 관련된 문제이다. 8086 계열의 assembly 명령어 중, 이라는 명령어가 있다. 이 명령어는 함수가 종료된 후, sp를 얼마만큼 add할지를 하나의 명령어로 만든것이다. __stdcall에서는 바로 이 명령어를 이용하여, 의 operation time만큼을 절약할 수 있으며, 그만큼 프로그램 사이즈도 줄일 수 있다 (물론, 한 단위로 보면 그 효과가 미비하지만, 그 수가 많아질 경우 어느정도 차이가 생길 수 있다).
다음으로, 가변 arguments의 지원 여부이다. __cdecl을 이용하면, caller측에서 sp를 정리하기 때문에, 가변 arguments를 지원할 수 있다.

사실, 몇가지 차이점이 더 있는 듯 하지만, 지금까지 파악된 부분은 이 두가지이다.

No comments:

Post a Comment