함수 호출 규약(calling convention) – Cdecl, Stdcall, Fastcall

함수 호출 규약에 따라 스택을 정리하는 위치가 바뀌게 되는데, Callee(호출된 함수)가 사용한 스택을 정리하는 Fastcall, Stdcall 호출 규약(API, C++ 등, 기본적으로 이 함수 호출 규약을 사용한다.)과 Caller(호출자)가 사용한 스택을 정리하는 Cdecl이 있으며 이외 최적화를 위해 사용하는 Frame Pointer Omission(1부에서 다루었다.)도 있으며, 여기서는 Stdcall, Cdecl, Fastcall에 대해 알아보도록 하자.

호출 규약 인자 스택에 넣는 순서 스택정리 표시방식 장점
Cdecl 오른쪽에서 왼쪽 호출자 함수앞에 “_” 추가 가변길이 인자 전달가능
Stdcall 오른쪽에서 왼쪽 호출된 함수 함수앞에 “_” 추가

이름뒤에는 “@” 추가

코드길이 짧아짐
Fastcall 처음 두인자는 ECX와 EDX에 넣고 나머지는 오른쪽에서 왼쪽 순으로 전달된다. 호출된 함수 함수앞에 “@” 추가

이름뒤에는 “@” 추가

스택 이용 바이트 수 표시

빠른 함수 호출

[내용] 함수 호출 규약

그럼 먼저 아래 프로그램을 C++을 이용하여 만들어 보자.

source\part02\ch04\call.cpp
#include
<stdio.h>
int Foun(int a, int b, int c)

{

return (a+b+c);

}

void main()

{

int a=1, b=2, c=3;

Foun(a,b,c);

}

[내용] 1, 2, 3을 더하는 C++예제

그럼 위 간단한 예제를 call.cpp라 하고, 앞서 설치한, Microsoft Visual C++ 2010 Express의 명령 프롬프트를 이용하여, 프로그램을 우리가 원하는 호출 규약으로 빌드해보자.

[그림] 프로그램 시작 메뉴에서 확인할 수 있다

Microsoft Visual C++에서는 명령 프롬프트에서 사용할 수 있는 컴파일러를 함께 제공하는데, Cl.exe 이다. 이 컴파일러를 통해 호출 규약을 변경하는 옵션을 제공한다.

만약 GUI로 진행하고자 한다면, 프로젝트에서 속성을 열어 아래 메뉴를 변경하여 진행할 수 있다.

[그림] 프로젝트 속성 변경

Cl.exe를 이용할 경우 아래와 같은 옵션을 통해 사용할 수 있다.

/Gd __cdecl 호출 규칙

/Gr __fastcall 호출 규칙

/Gz __stdcall 호출 규칙

그럼 프로그램을 3가지 호출 규약을 이용해 컴파일 해보자.

// 그럼 먼저 Cdecl로 컴파일하자.

C:\ >cl /Gd call.cpp

Microsoft (R) 32비트 C/C++ 최적화 컴파일러 버전 15.00.21022.08(80×86)

Copyright (c) Microsoft Corporation. All rights reserved.

call.cpp

Microsoft (R) Incremental Linker Version 9.00.21022.08

Copyright (C) Microsoft Corporation. All rights reserved.

/out:call.exe

call.obj

// 컴파일된 파일의 이름을 call_cdecl.exe로 변경후 Fastcall로 컴파일하자.

C:\ >cl /Gr call.cpp

Microsoft (R) 32비트 C/C++ 최적화 컴파일러 버전 15.00.21022.08(80×86)

Copyright (c) Microsoft Corporation. All rights reserved.

call.cpp

Microsoft (R) Incremental Linker Version 9.00.21022.08

Copyright (C) Microsoft Corporation. All rights reserved.

/out:call.exe

call.obj

// 컴파일된 파일의 이름을 call_fast.exe로 변경후 Stdcall로 컴파일하자.

C:\ >cl /Gz call.cpp

Microsoft (R) 32비트 C/C++ 최적화 컴파일러 버전 15.00.21022.08(80×86)

Copyright (c) Microsoft Corporation. All rights reserved.

call.cpp

Microsoft (R) Incremental Linker Version 9.00.21022.08

Copyright (C) Microsoft Corporation. All rights reserved.

/out:call.exe

call.obj

[내용] Cl.exe를 이용한 서로 다른 호출 규약으로 컴파일

이제 컴파일된 내용을 1부에 설치한 IDA를 이용하여 분석하여 보자.

일부 값을 표시하는데 있어, 자동적으로 분석한 결과가 반영되어 표시되는데, 이 부분이 불편할 경우, 아래와 같이 “R”혹은 “S”키를 이용하여, 해당 내용을 주소값으로 변환하여 볼 수 있다.

[내용] 자동 분석 내용이 번거로울 경우 r, s 키를 이용하여, 변환 가능

그럼 본격적으로 분석을 진행해보자.

Cdeclcall
// Cdecl 호출 규약의 어셈블리 내용이다. 비주얼 스튜디오에서 기본적으로 사용하는 호출 규약이다. 호출자(Caller)인 main에서 add esp, 0Ch를 이용하여 스택을 정리하고 있다.

push ebp

mov ebp, esp

sub esp, 0Ch

mov dword ptr [ebp-4], 1

mov dword ptr [ebp-8], 2

mov dword ptr [ebp-0Ch], 3

mov eax, [ebp-0Ch]

push eax

mov ecx, [ebp-8]

push ecx

mov edx, [ebp-4]

push edx

call sub_401000

add esp, 0Ch
ß Caller에서 스택을 정리한다.

xor eax, eax

mov esp, ebp

pop ebp

retn

_main endp

sub_401000

push ebp

mov ebp, esp

mov eax, [ebp+8]

add eax, [ebp+0Ch]

add eax, [ebp+10h]

pop ebp

retn

sub_401000 endp

fastcall

// Fastcall 호출 규약의 경우 인자 2개인 1과 2를 ECX, EDX에 저장하는 것을 확인할 수 있다. 따라서 따로 정리할 스택이 없다. 단 인자가 2개 이상인 경우 3번째 값부터 스택을 이용한다.

push ebp

mov ebp, esp

sub esp, 0Ch

mov dword ptr [ebp-4], 1

mov dword ptr [ebp-8], 2

mov dword ptr [ebp-0Ch], 3

mov eax, [ebp-0Ch]

push eax

mov edx, [ebp-8] ß 스택을 이용하지 않고 레지스터에 직접 저장한다.

mov ecx, [ebp-4]

call sub_401000

xor eax, eax

mov esp, ebp

pop ebp

retn

_main endp

// Callee에서 사용한 스택을 정리한다. 사용한 스택이 1개이기 때문에, 코드도 줄어든다.

sub_401000

push ebp

mov ebp, esp

sub esp, 8

mov [ebp-8], edx

mov [ebp-4], ecx

mov eax, [ebp-4]

add eax, [ebp-8]

add eax, [ebp+8]

mov esp, ebp

pop ebp

retn 4
ß 사용한 1개의 스택만 Callee에서 정리한다.

sub_401000 endp

Stdcall

// Stdcall 호출 규약으로 Win32 API들이 사용한다. Callee에서 사용한 스택을 정리한다.

push ebp

mov ebp, esp

sub esp, 0Ch

mov dword ptr [ebp-4], 1

mov dword ptr [ebp-8], 2

mov dword ptr [ebp-0Ch], 3

mov eax, [ebp-0Ch]

push eax

mov ecx, [ebp-8]

push ecx

mov edx, [ebp-4]

push edx

call sub_401000

xor eax, eax

mov esp, ebp

pop ebp

retn

_main endp

// Callee에서 사용한 스택을 정리한다.

sub_401000

push ebp

mov ebp, esp

mov eax, [ebp+8]

add eax, [ebp+0Ch]

add eax, [ebp+10h]

pop ebp

retn 0Ch ß Callee에서 스택을 정리한다.

sub_401000 endp

[내용] 호출 규약별 스택 처리 내용

Facebook Comments

Leave A Reply

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다