본문 바로가기
공부

[C,C++] 함수 호출 규약

by MY블로그 2023. 4. 8.
함수 호출 규약이란

함수의 호출 규약은 Calling Convention 이라고 합니다.

함수의 파라미터(인자)를 어떠한 방식으로 전달하는지에대한 하나의 규약입니다.

 

함수를 호출 할 때, 프로세스에 정의되어있는 스택 메모리 공간을 이용하여 인자를 함수로 전달하게 되고,

이 스택 메모리 공간은 프로세스가 실행 될 때에 해당 PE헤더에 스택 메모리의 크기가 명시되어 있습니다.

 

스택에 저장되는 값들은 임시적인 값들이기 때문에 사용하지않더라도 값을 지우거나 하지 않습니다.

왜냐하면 굳이 지우려 하지않더라도 스택에 다른 값을 입력할 때 저절로 덮어 씌우고 갱신시키기 때문에 이에대한 불필요한 CPU 자원 소모의 낭비를 줄이기 위해서 방치 됩니다.

 

스택 메모리가 부족하다면 스택포인터(ESP)가 스택의 끝을 가리키게 되는데 이렇게된다면 스택영역을 사용할 수 없게 됩니다. 그렇기 때문에 함수를 사용한 후에 스택포인터(ESP)의 위치를 함수 시작 전으로 돌려 주면서 사용가능한 스택 메모리의 공간을 확보 하게 됩니다.

이때 스택포인터(ESP)가 정리하는지를 함수호출규약 이라고 합니다.

 

함수 호출 규약의 Caller & Calle

함수 호출 규약을 이해하기 위해서 필요한 것이 콜러와 콜리 입니다.

콜러(Caller) = 호출자 , 콜리(Callee) = 피호출자 를 의미합니다.

예시로 main() 함수에서 add() 라는 함수가 있다면 이때 콜러는 main()이며 콜리는 add() 가 됩니다.

 

cdecl (Caller가 직접 스택을 정리하는 방식)

cdecl 방식은 주로 C언어(C, C++) 에서 사용되는 방식 입니다.

콜러가 직접 스택을 정리하는 방식을 가지게 됩니다.

스택이 호출자에 의해 지워지기 때문에 가변 인자를 가지는 함수를 정의할 수 있습니다.

실행파일의 크기는 cdecl > stdcall 입니다. 이유는 각 함수 호출마다 스택을 정리하는 코드가 있어야하기때문에 그에 대한 공간만큼 크기가 더 커질 수 밖에 없습니다.

요소 구현
인수 전달 순서 오른쪽에서 왼쪽
스택 유지 관리 책임 호출하는 함수가 스택에서 인수를 꺼냅니다(정리합니다).
이름 수식 컨벤션
(Name-decoration convention)
C 연결을 사용하는 __cdecl 함수를 내보낼 때를 제외하고 이름 앞에 _가 붙습니다. (_함수명)
대소문자 변환 규칙 수행되지 않습니다.

 

#include "stdio.h"

int add(int a, int b) // add 함수 , 콜리
{
    return (a + b);
}

int main(int argc, char* argv[]) // main 함수 , 콜러
{
    return add(1, 2);
}

위의 예시는 콜러(main함수)에서 콜리(add함수)를 호출한 코드입니다. 콜리의 인자로 상수 1과 2를 넘겨줍니다.

출처 : https://velog.io/@dnrgus1127/%ED%95%A8%EC%88%98-%ED%98%B8%EC%B6%9C-%EA%B7%9C%EC%95%BD

위의 코드를 실행시켜 디버거로 살펴보면 401010[main]함수에서 파라미터 1과 2를 401000[add]로 넘겨주고

PUSH 2, PUSH 1 함수가 끝난 뒤 콜러였던 main함수에서 ADD ESP,8 코드를 통해서 스택포인터의 위치를 조정해 줍니다.

이처럼 콜러가 직접 스택을 정리하는 방식을 cdecl 이라고 합니다.

 

장점 : 가변 길이 파라미터를 전달 할 수 있다는 장점이 있습니다.

 

stdcall (Callee가 직접 스택을 정리하는 방식)

콜러가 직접 스택을 정리하는 방식과는 반대로 콜리가 직접 스택을 정리하는 방식이 있습니다.

Win32 API에서 사용되는 호출 규약 입니다.

Win32 API 의 경우 C언어로 만들어진 라이브러리이지만 호환성 때문에 stdcall 방식을 사용하고 있다고 합니다.

요소 구현
인수 전달 순서 오른쪽에서 왼쪽
인수 전달 컨벤션
(Argument-passing convention)
포인터 또는 참조자 타입이 아닌 경우, 값 전달
스택 유지 관리 책임 피호출자가 스택에서 인수들을 꺼냅니다(정리합니다).
이름 수식 컨벤션 함수명 앞에 _가 붙으며, 함수명 뒤에 인자 리스트의 바이트 크기를 @와 함께 표기합니다(_함수명@인자리스트크기)
대소문자 변환 규칙 없음.
#include "stdio.h"

int _stdcall add(int a, int b)
{
    return (a + b);
}

int main(int argc, char* argv[])
{
    return add(1, 2);
}

이번 예시코드는 add 함수가 _stdcall 이 명시되어져 있습니다.

stdcall 방식을 사용하고자 한다면 함수에 명시해주어야 합니다.

출처 : https://velog.io/@dnrgus1127/%ED%95%A8%EC%88%98-%ED%98%B8%EC%B6%9C-%EA%B7%9C%EC%95%BD

위의 코드를 실행시켜 디버거를 살펴본다면 이번에는 add함수에서 RETN 8 을 통해서 콜리가 직접 스택을 정리하는 모습을 볼 수 있습니다. (RETN 8 = RETN + POP 8 Bytes / 리턴 후 지정된 크기만큼 ESP가 증가)

 

stdcall방식의 장점은 호출되는 함수내에 스택을 정리하는 코드가 있기 떄문에 함수를 호출할때마다 ADD ESP, * 명령을 직접 하지 않아도 되기떄문에 코드가 간결해질 수 있습니다.

 

기본적인 호출규약의 정의와 cdecl & stdcall 에 대하여 알아보았습니다.

추가적인 규약으로

  • fastcall
  • thiscall
  • vectorcall
  • syscall
  • pascal
  • naked

등의 다양한 규약이 있습니다. 

 

[참고 블로그]

 

함수 호출 규약

Calling Convention, 해석하면 '함수 호출 규약' 이란 어떤 함수를 호출 할 때, 그 함수의 파라미터(인자)를 어떤 방식으로 전달하는가에 대한 하나의 약속이다.함수를 호출 할 때, 프로세스에 정의되

velog.io

 

함수 호출 규약(Calling Convention)

프로젝트 개발을 다른 사람들과 협업하여 진행하게 되면 자주 듣는 용어가 있는데, 그 중 하나가 코딩 컨벤션(coding convention) 입니다. 코딩 컨벤션이란, 읽고 관리하기 쉬운 코드를 작성하기 위한

minusi.tistory.com

 

'공부' 카테고리의 다른 글

[CS]캐시 메모리(캐시히트&캐시미스)  (0) 2023.04.20
[CS]기초  (0) 2023.04.19
[참고자료] 2D 게임 에셋 추출 하기  (0) 2023.01.30
게임 에셋 검색 참조 사이트  (0) 2023.01.30
[C++/DX11] - 텍스처 렌더링  (0) 2023.01.27

댓글