호출 규약(Call Convention)은 함수가 호출될 때 함수의 인수들이 어떻게 전달되고, 함수가 실행된 후 결과가 어떻게 반환되는지를 정의하는 규칙입니다. 호출 규약은 함수와 호출자 간의 약속으로, 다양한 컴파일러나 시스템에서 일관성 있게 함수를 호출하고 결과를 얻기 위해 필수적인 개념입니다. 이번 블로그 포스트에서는 PDF 자료를 바탕으로 호출 규약에 대해 자세히 분석해 보겠습니다.
호출 규약은 함수 호출 시 스택에 인수들이 어떻게 저장되는지, 레지스터가 어떻게 사용되는지, 그리고 함수가 끝난 후 반환 값이 어떻게 전달되는지를 정의합니다. 호출 규약은 프로세서 아키텍처와 운영체제에 따라 다를 수 있으며, 주요 호출 규약으로는 cdecl, stdcall, fastcall 등이 있습니다.
함수가 호출될 때, 인수들은 스택에 푸시(push)되거나 특정 레지스터에 저장됩니다. 이 과정은 호출 규약에 따라 다릅니다. 예를 들어, x86 아키텍처에서 cdecl 호출 규약은 인수들이 스택에 푸시되고, EAX 레지스터가 반환 값을 저장하는 데 사용됩니다.
PDF 자료에 따르면, 함수가 호출될 때 스택 프레임(stack frame)이 설정되고, ESP(Stack Pointer)와 EBP(Base Pointer) 레지스터가 함수 내에서 지역 변수와 인수를 관리하는 데 사용됩니다. 반환 주소는 EIP(Instruction Pointer)에 저장되며, 함수가 끝나면 이 주소로 돌아가 프로그램이 계속 실행됩니다.
PDF에서 제공된 예제 코드와 스택 상태를 통해, 호출 규약이 실제로 어떻게 적용되는지 살펴보겠습니다.
int sum(int x, int y)
{
int total = x + y;
return total;
}
int result = sum(10, 20);
이 코드에서 sum
함수가 호출되면 다음과 같은 과정이 발생합니다:
10
과 20
이 스택에 푸시됩니다. 이때 10
은 x
에, 20
은 y
에 할당됩니다.x
와 y
를 더하여 total
에 저장합니다.total
은 EAX 레지스터를 통해 호출자에게 전달됩니다.각 호출 규약은 스택과 레지스터를 다르게 사용합니다. 주요 호출 규약의 차이점을 정리하면 다음과 같습니다:
EAX
레지스터에 저장됩니다.호출 규약은 함수 간 일관된 통신을 보장하고, 특히 외부 라이브러리나 시스템 콜을 사용할 때 중요한 역할을 합니다. 잘못된 호출 규약을 사용할 경우, 스택이 불안정해지거나 잘못된 반환 값을 받을 수 있습니다.
호출 규약은 함수 호출의 기초를 이해하는 데 필수적인 개념입니다. 이를 이해하면, 다양한 플랫폼에서의 함수 호출이 어떻게 이루어지는지, 그리고 어떻게 최적화할 수 있는지를 알 수 있습니다. 이번 포스트를 통해 호출 규약의 기본 개념과 다양한 유형을 이해하는 데 도움이 되었길 바랍니다.