사용자 도구

사이트 도구


kb:callingconvention

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

kb:callingconvention [2014/11/10 09:33] (현재)
줄 1: 줄 1:
 +====== Calling Convention? ======
 +함수 호출 방식(Calling Convention)이란 호출자(caller,​ 피호출자 함수를 호출하는 함수)와 피호출자(callee,​ 호출자로부터 호출되는 함수) 간에 미리 정해둔, **파라미터의 전달 순서와 사용이 끝난 후의 스택 정리**에 대한 규약이라고 할 수 있다. WIN32 환경에서는 기본적으로 세 가지의 호출 방식이 존재한다.
 +
 +  * **Standard Call** -- 파라미터들은 코드 상의 오른쪽 파라미터부터 먼저 푸쉬되고(첫번째 파라미터가 스택의 맨 위로 오게 된다는 말이다.),​ 피호출자(callee)가 스택을 정리한다.
 +  * **CDECL or C Calling Convention** -- 파라미터들은 코드 상의 오른쪽 파라미터부터 먼저 푸쉬되고(첫번째 파라미터가 스택의 맨 위로 오게 된다는 말이다.),​ 호출자(caller)가 스택을 정리한다.
 +  * **Fast Call** -- C++의 내부 구조에 익숙하다면,​ 멤버 함수를 호출하기 위해서는 this 포인터가 반드시 필요하다는 것을 알 것이다. 일반적으로 이 this 포인터가 스택에 최초로 푸쉬되는 파라미터다. 하지만 이 방식에서는 this 포인터를 스택에다가 푸쉬하는 게 아니라, 레지스터(ECX)에 저장한다. 파라미터들은 코드 상의 오른쪽 파라미터부터 먼저 푸쉬되고(첫번째 파라미터가 스택의 맨 위로 오게 된다는 말이다.),​ 피호출자(callee)가 스택을 정리한다.
 +  * **Pascal Calling Convention** -- 이 방식은 더 이상 사용할 수 없다. 이는 모두 Standard Call로 대체되었다. 어쨌든 원래의 Pascal Calling Convention은 파라미터를 코드 상의 **왼쪽** 것부터 먼저 푸쉬하고,​ 피호출자(callee)가 스택을 정리한다.
 +
 +결국 파라미터의 전달 순서와 스택 정리에 대한 규약이 다르므로,​ 다른 규약을 이용해서 만들어진 ​ DLL 안에 있는 함수를 헤더 같은 것도 없이 동적으로 바인딩해서 사용하는 경우, 그것을 컴파일러에게 명시적으로 가르쳐줘야하는 것이다. (호출하는 측과 호출받는 쪽이 다른 Calling Convention을 사용할 수 있으므로...)
 +
 +
 +====== 스택 정리를 누가 하든 무슨 상관인가?​ ======
 +===== - 호출자가 정리 - C Calling Convention =====
 +<​code>​
 +Invoke MyFunction, 1, 2, 3, 4
 +</​code>​
 +
 +코드가 아래와 같이 변환된다.
 +
 +<​code>​
 +PUSH    4  ​
 +PUSH    3  ​
 +PUSH    2  ​
 +PUSH    1  ​
 +CALL    MyFunction
 +ADD     sp, 16      ;; -->> 스택 정리 코드..  ​
 +</​code>​
 +
 +  * 장점 : 호출하는 측에서 스택에다 몇 개의 파라미터를 집어넣었는지 알고, 스택 정리를 담당하므로,​ 가변 인자(variable arguments)를 사용할 수 있다.
 +  * 단점 : 프로그램의 크기가 커진다. 호출자가 스택을 정리한다는 말은, 위에서도 보듯이 함수 호출할 때마다 스택 정리하는 코드가 들어가야 한다는 말이고, 이는 프로그램의 크기 증가와 속도 감소를 가져온다.
 +
 +printf 함수 같은 것이 가변 인자를 사용하는 대표적인 예이다. 하지만 피호출자는 인자가 몇개나 전달되었는지 정확히 알 수 없다. 그냥 포맷 문자열 같은 것을 이용해서 추측할 뿐이다. 예를 들어 printf 함수를 호출할 때, "%i %i %i" 문자열을 주면, printf 함수는 호출하는 측에서 추가적으로 스택에다 3개의 인자를 집어넣지 않은 경우(프로그래머의 실수!)에도,​ 스택에 있는 3개의 값을 이용해 문자열을 생성할 것이다. 이것이 크래시를 일으킬지,​ 아닐지는 정확히 알 수 없다. 3개 이상의 인수를 전달하는 경우는 어차피 호출하는 측에서 스택을 정리하므로 문제가 되지 않는다.
 +
 +===== - 피호출자가 정리 - Standard Calling Convention =====
 +<​code>​
 +Invoke MyFunction, 1, 2, 3, 4
 +</​code>​
 +
 +코드가 아래와 같이 변환된다.
 +
 +<​code>​
 +PUSH    4  ​
 +PUSH    3  ​
 +PUSH    2  ​
 +PUSH    1  ​
 +CALL    MyFunction
 +</​code>​
 +
 +  * 장점 : 피호출자가 스택 정리를 담당한다면,​ 프로그램의 크기는 작아진다. 또한 스택 정리 명령어를 매번 호출하지 않아도 되므로, 속도 또한 빨라진다.
 +  * 단점 : 피호출자가 자신이 정리할 스택의 크기(파라미터들의 총 크기)를 정확히 알고 있어야 하므로, 가변 인자를 사용할 수 없다.
 +
 +===== 차이점? =====
 +호출자가 하든, 피호출자가 하든 어딘가에서는 스택을 정리해야하지 않는가? 즉 위에서 없어진 <​code>​ADD sp, 16</​code>​는 어차피 피호출자,​ 즉 <​code>​MyFunction</​code>​ 내부에서 호출해야 하지 않느냐는 말이다. 어차피 어디에선가 호출해야 한다면 프로그램의 크기가 왜 작아지며,​ 빨라지는가?​ 이는 인텔 계열에서 지원하는 특수한 명령어 때문이다. 즉 리턴하면서 스택 정리를 동시에 하는 명령어가 있기 때문에, 프로그램의 크기가 작아지고,​ 빨라진다는 말이다.
 +
 +
 +====== 정리 ======
 +from [[http://​www.smkang.com/​Details/​API/​API3.htm | http://​www.smkang.com]]
 +
 +^ Calling Conventions ^ Arguments Passing ^ Stack Maintenance ^ Name Decorations ^ Notes ^
 +| cdecl | Right -> Left | 호출자가 Stack에서 인자를 제거한다. | 함수 이름 앞에 _를 붙인다. //Ex) _foo// | C/​C++함수의 기본 호출 규약 |
 +| stdcall | Right -> Left | 호출된 함수가 Stack에서 인자를 제거한다. | _가앞에 붙고 뒤에 @와 인자의 크기가 10진수로 붙는다. //Ex) _foo@12// | 대부분의 System 함수가 사용. VB에서 내부함수가 사용. |
 +| fastcall | 첫번째 2개의 DWORD 파라미터는 ECX, EDX 레지스터 사용. 나머지는 Right->​Left | 호출자가 Stack에서 인자를 제거한다. | @이 앞에 붙고 @과 인자의 크기가 10진수로 뒤에 붙는다. //Ex) @foo@12// | Intel CPU 만 사용. Borland의 Delphi 컴파일러가 사용. |
 +| this | Right -> Left this 매개변수는 ECX 레지스터사용. | 호출자가 Stack에서 인자를 제거한다. | None | C++클래스의 멤버 함수가 사용. COM에서 사용. |
 +| naked | Right -> Left | 호출자가 Stack에서 인자를 제거한다. | None | VxD에서 사용. Custom Prolog 와 Epilog를 만들때 사용. |
 +
 +====== 링크 ======
 +  * [[http://​msdn.microsoft.com/​library/​default.asp?​url=/​library/​en-us/​vccore98/​HTML/​_core_calling_conventions.3a_.overview.asp?​frame=true | Calling Conventions:​ Overview]]
 +  * [[http://​www.unixwiz.net/​techtips/​win32-callconv.html | Intel x86 Function-call conventions - C Programmer'​s view]]
 +  * [[http://​www.unixwiz.net/​techtips/​win32-callconv-asm.html | Intel x86 Function-call conventions - Assembly View]]
 +  * [[http://​www.codeproject.com/​tips/​stackdumper.asp | Playing with the stack]]
 +  * [[http://​www.angelcode.com/​dev/​callconv/​callconv.html | Calling conventions on the x86 platform]]
 +  * [[http://​www.hackcraft.net/​cpp/​MSCallingConventions/​ | Calling Convetions in Microsoft Visual C++]]
 +  * [[http://​blogs.msdn.com/​freik/​archive/​2006/​03/​06/​X64_calling_conventions_summary.aspx | x64 ABI vs. x86 ABI (aka Calling Conventions for AMD64 & EM64T)]]
 +
 +  * [[http://​www.codeguru.com/​cpp/​misc/​misc/​assemblylanguage/​article.php/​c14641/​ | Function Calls, Part 1 (the Basics)]]
 +  * [[http://​www.codeguru.com/​cpp/​v-s/​tips/​debugging/​article.php/​c14681/​ | Function Calls, Part 2 (Stack and Calling Conventions)]]
 +  * [[http://​www.codeguru.com/​cpp/​v-s/​debug/​openfaq/​article.php/​c14799/​ | Function Calls, Part 3 (Frame Pointer and Local Variables)]]
 +  * [[http://​www.codeguru.com/​cpp/​misc/​misc/​stack/​article.php/​c14801 | Function Calls, Part 4 (What Exactly Is "​this"?​)]]
 +
  
kb/callingconvention.txt · 마지막으로 수정됨: 2014/11/10 09:33 (바깥 편집)