함수 호출 규약 이란?
함수가 호출될 때 매개변수와 반환값을 어떻게 전달하는지 정의하는 규칙이다.
함수 호출 규약은 컴퓨터 아키텍처, 운영체제, 컴파일러와 같은 요소에 따라 달라진다.
그러나, 대부분의 호출규약은 함수 호출 프로토콜을 다음과 같이 규정한다.
- 매개 변수 전달 방식
- 매개변수는 레지스터, 스텍, 메모리 또는 조합으로 전달된다.
- 매개변수 전달 순서
- 매개 변수는 왼쪽에서 오른쪽으로, 또는 오른쪽에서 왼쪽으로 전달된다.
- 반환값 처리
- 반환값은 레지스터, 스텍, 메모리 또는 조합으로 처리된다.
- 스택 처리
- 함수가 호출되고 반환될 때 스택 프레임이 생성되고 해제된다.
대표적인 함수 호출 규약으로는, C언어에서 사용되는 cdecl, stdcall, fastcall, this call, vectorcall, Nacked call이 있고,
Microsoft의 x64 calling convention이 있다.
- cdecl
- cdecl 호출규약의 단점.
- 매개변수의 개수가 많아질수록 스택의 사용이 늘어나게 되어 호출 속도가 느려질 수 있다.
- 호출 스택의 제거를 호출자가 해야함으로 함수 호출 시 오버헤드가 발생할 수 있다.
즉, 기본적인 함수 호출시 실행되는 함수 호출 규약은 cdecl이 사용된다.
- stdcall
- stdcall은 WinAPI와 같은 WIndows 플랫폼에서 주로 사용되는 함수 호출 규약으로, cdecl과 마찬가지로 매개변수와 반환값을 스택에 푸시하고, 호출한 함수가 스택을 제거하는 것 이 아니라, 호출한 함수가 만든 스택 프레임을 호출한 함수에서 제거하게 된다. Windows API와 같은 매개변수가 많은 함수에서 사용된다.
- stdcall의 특징은 다음과 같다.
- stdcall 호출규약의 단점.
- 매개변수의 개수가 많아질수록 스택의 사용이 늘어나게 되어 호출 속도가 느려질 수 있다.
- 호출 스택의 제거를 호출자가 해야함으로 함수 호출 시 오버헤드가 발생할 수 있다.
호출규약의 단점은 같으나, cdecl과 stdcall의 차이점이 존재한다.
cdecl은, 함수 호출 시 매개변수를 스택에 저장하고, 호출이 끝난 후 스택에서 매개변수를 제거한다. 이러한 방식은 매개변수의 개수가 많아질수록, 스택의 사용이 늘어나게되어 호출속도가 느려질 수 있다.
stdcall은, 함수 호출 시 매개변수를 스택에 저장하고, 호출이 끝난 후 스택에서 매개변수를 제거한다. 그럼으로, stdcall호출규약은 스텍의 제거를 호출 대상이 해야함으로 호출자는 호출대상에서 반환된 값을 쉽게 얻을 수 있다. 그러나, 호출 대상이 해야하기 때문에 호출대상에 대한 오버헤드가 발생할 수 있다.
- fastcall
- fastcall 호출규약의 단점
- 매개변수가 많으면 레지스터가 부적해져 스택을 이용하여 매개변수를 전달해야 함으로 호출속도가 떨어질 수 있다.
- 컴파일러에 따라 지원되지 않을 수 있다.
- 레지스터의 사용이 많아져서 함수의 크기가 증가할수 있음으로 코드의 크기가 커져, 캐시효과가 떨어지기 때문에 성능이 감소할 수 도 있다.
- thiscall
- thiscall 호출규약의 단점
- 인라인 함수에서의 오버헤드가 발생할 수 있다. 멤버함수가 인라인 함수로 작성될 경우 'this'포인터 전달 및 호출 스택 관련 작업 때문에 오버헤드가 발생한다. [인라인 함수는 코드가 함수 호출문에 삽입되는 방식을 이야기 한다]
- 함수포인터 사용에 제한이 있다. 일반적인 함수 포인터와 호환되지 않아, 호출대상 함수가 __thiscall 호출규약을 사용하는 경우 해당 함수를 호출하는 함수포인터 도 __thiscall 호출 규약을 사용해야 한다.
- 표준이 아닌 호출규약 이기 때문에, C++표준이 아님으로 특정 컴파일러에서만 지원된다(Microsoft Visual C++ 컴파일러 에서만 지원) 그럼으로 이식성이 떨어질 수 있다.
- vectorcall
- vectorcall 호출규약은 Microsoft Visual C++ 2013부터 도입된 비표준(non-standard)호출규약 중 하나이다. 이 호출규약은 SSE(SIMD) 명령어를 이용한 고성능 연산을 위해 만들어 졌으며, 벡터 자료형의 인자 전달 및 반환을 위한 호출규약 이다.
- vectorcall 의 특징은 다음과 같다.
- vectorcall 호출규약의 단점
- 비표준 호출규약이기 때문에 이식성이 떨어질 수 있다.
- 스택 프레임을 정리하는 부담이 호출자에게 들어가기 때문에, 함수 내에서 동적 메모리 할당을 수행하는경우 할당한 메모리를 호출자(예를들어 int main()같은 ) 가 스택 프레임을 정리하기 때문에 호출자가 동적 메모리를 반환하기전 에는 해당 메모리를 해제할 수 없다. 그럼으로 메모리누수가 발생할 가능성이 있으며, 이때문에 프로그래머는 메모리 해제 작업을 함수 외부에서 수행해야만 한다.
- Nacked Call
- Nacked Call 호출규약은 함수 진입점에서 컴파일러가 자동으로 함수 프롤로그와 에필로그 코드를 생성하지 않는 호출규약이다. 이 규약을 사용하면 호출된 함수가 진입점에서 스택 프레임을 생성하거나 삭제하지 않으며, 이에대한 방법은 전부 개발자가 작업해야 한다.
- Nacked Call 의 특징은 다음과 같다.
- Nacked Call 호출규약의 단점
- 컴파일러가 인자전달순서, 방법, 정리, 가변인자 사용여부 등을 생성하지 않기 떄문에 개발자가 스택 프레임과 관련된 모든 작업을 직접 구현해야 한다. 이에따라 코드가 복잡해질 수 있다.
- 스택 프레임과 관련된 작업이 제대로 구현되지 않으면 큰 문제가 발생할 수 있다.
- 이 호출규약은 Microsoft Visual C++ 에서만 지원됨으로 이식성이 떨어질 수 있다.
- Microsoft x64 calling convention
- Microsoft x64 calling convention은 64비트 WIndows에서 사용되는 함수 호출 규약으로, cdecl과 유사하게 매개변수와 반환된 값을 스택에 저장한다. 그러나, 레지스터를 더 많이 사용하여 매개 변수 전달 및 반환 값을 최적화 한다.
Microsoft x64 calling convention 은 cdecl 과 마찬가지로 따로 지정하지 않아도, 64비트 환경에서는 컴파일러가 플랫폼과 아키텍처에 따라 선택하게 됨으로. 호출규약을 지정해주지 않아도 64비트 환경에서는 사용된다.
- Microsoft x64 calling convention 호출규약의 단점
- 매개변수 전달방식에 따른 제약이 존재한다. 처음 4개의 정수형 매개변수 까지는 레지스터에 저장하여 전달하고 5번째 매개변수 부터는 스택을 사용하여 전달하게 된다. 이때문에 매개변수의 개수가 많을 경우 스택을 사용하기 때문에 느려질 수 있다.
- 반환값의 제약이 존재한다. 해당 호출규약은 반환값을 레지스터에 저장하는 방식을 사용하는데, 그 반환값이 레지스터에 저장할 수 있는 크기보다 큰 경우 스택을 이용하게 된다. 이 경우 속도의 저하가 발생할 수 있다.
- 함수 호출 시 레지스터 사용이 많아지게 되면, 다른 함수 호출 시 레지섵의 값을 저장하고 복원하는 작업이 필요해짐으로 호출 속도가 느려질 수 있다.
- Microsoft x64 calling convention은, 64비트 시스템에서만 사용이 가능하다! 이러한 제한 때문에 32비트에서는 다른 호출규약을 사용해야 한다.
'컴퓨터 용어 정리' 카테고리의 다른 글
함수 오버로딩(Function Overloading) (0) | 2023.04.20 |
---|---|
인라인 함수(inline function) (0) | 2023.04.20 |
가변인자(variable argument) (0) | 2023.04.20 |
스택 프레임(Stack Frame) (0) | 2023.04.20 |
호출 스택 포인터(Call Stack Pointer) (0) | 2023.04.20 |