ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • __cdecl, __stdcall 차이점
    Programming Language/C++ 2017. 1. 2. 00:06

    (2014년에 네이버 블로그에서 작성했던 글을 티스토리로 옮기며 이관했습니다)

     

     

     

    1. __cdecl

     

    함수 호출용으로 스택에 쌓은 파라미터를 호출한 함수에서 제거해 주는 Convention이다.

     

    알기 쉽게 간단한 예시를 보자.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
     
    int __cdecl cdeclFunction(int a, int b)
    {
        return a + b;
    }
     
    int main()
    {
        int varA = 1, varB = 2;
        cdeclFunction(1, 2);
        
        return 0;
    }

     

     

     

     

    위 C 코드를 Assembly로 짜보았다.

    (어셈블리 프로그래밍이 익숙하지 않아서 문법에 맞지 않는 부분이 있을 수 있는데 중요하지 않으니 넘어가도록 하자)

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // cdeclFunction 함수 //
    push ebp
    mov ebp, esp
    mov eax, [ebp+0x8]
    add eax, [ebp+0xC]
    mov esp, ebp
    pop ebp
    ret
     
     
    // main 함수//
    push ebp
    mov ebp, esp
    sub esp, 0x8
    mov [ebp-0x4], 1     // varA
    mov [ebp-0x8], 2     // varB
    mov eax, [ebp-0x8]
    push eax
    mov eax, [ebp-0x4]
    push eax
    call cdeclFunction
    add esp, 8              // 사용하지 않을 파라미터들이므로 값을 덮어쓸 수 있도록 해 준다.
    xor eax, eax
    mov esp, ebp
    pop ebp
    ret

     

     

     

     

     

     

    22 라인에서 cdeclFunction을 call 한 뒤, 23 라인에서 8바이트만큼의 스택을 재사용 할 수 있도록 스택 포인터에서 add 해 준다. 

    main 함수(호출시킨 함수)에서 이런 정리를 해 주는 것을 cdecl 호출 방식이라고 한다.

     

    예전부터 cdecl이 무슨 약자인지 알고 싶었는데 정리하면서 찾아보니 C DECLaration라는 뜻이란다.

    declaration이 한국어로 선언이라는 뜻이라는데 C DECLaration를 직역하자면 -> C 선언이라는 뜻이 된다.

     

    주관적인 생각이지만 이렇게 옛날에 만들어진 것들은 네이밍 센스가 정말 극악인 것 같다.

    저런 예약어나 함수 이름들 중 문서를 보지 않고서는 무슨 역할을 하는지 알기 어려운 것들이 정말 많다.

     

     

     

     

    2. __stdcall

     

    cdecl 호출 방식과는 다르게 호출 당한(?) 함수 내부에서 stack pointer 연산을 해 준다.

    위의 간단한 코드를 stdcall 호출 방식의 C/Assembly로 다시 짜보면 아래와 같다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
     
    int __stdcall cdeclFunction(int a, int b)
    {
        return a + b;
    }
     
    int main()
    {
        int varA = 1, varB = 2;
        cdeclFunction(1, 2);
        
        return 0;
    }

     

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // cdeclFunction 함수 //
    push ebp
    mov ebp, esp
    mov eax, [ebp+0x8]
    add eax, [ebp+0xC]
    mov esp, ebp
    pop ebp
    ret 8
     
     
    // main 함수//
    push ebp
    mov ebp, esp
    sub esp, 0x8
    mov [ebp-0x4], 1     // varA
    mov [ebp-0x8], 2     // varB
    mov eax, [ebp-0x8]
    push eax
    mov eax, [ebp-0x4]
    push eax
    call cdeclFunction
    xor eax, eax
    mov esp, ebp
    pop ebp
    ret

     

     

     

     

     

    위의 cdecl 호출 방식과 비교해 보면 main 함수에서 cdeclFunction을 call하고, esp 레지스터에 연산해 주는 과정이 빠졌고,

    cdeclFunction 함수에서 리턴할 때 8바이트를 pop함으로써 esp 레지스터가 기리키는 주소가 함수 호출 준비 전(파라미터 push 전)으로 복구된다.

     

    이렇게 호출된 함수 내부에서 esp 레지스터를 복구시켜 주는 호출 형식을 stdcall이라고 한다.

     

     

    * Win32 API가 보통 stdcall 형식으로 호출된다고 한다.

    (https://msdn.microsoft.com/ko-kr/library/zxk0tw93.aspx)

     

     

     

    3. 차이점

     

    사실 stack pointer를 어디서 연산하느냐의 차이지 저걸 왜 나누어 놓았는지 이해가 되지 않았다.

     

    stdcall 호출 방식이 cdecl 호출 방식보다 빠르고, 프로그램 용량도 적어진다고 하는데 그래도 모르겠다.

     

    stdcall 방식이 빠르면 cdecl를 버리고 stdcall만 쓰면 될 것을 왜 쓸데없이 나누었는지, 저게 무슨 차이길래 속도 차이가 나는건지 궁금했다.

     

     

    그래서 둘의 차이점을 알아보았다.

    (참고 : http://blog.naver.com/kimchulgoon/30024494772)

     

    일단 stdcall 호출 형식은 호출한 함수 내부에서 파라미터 크기만큼 pop을 해 주기 때문에 가변인자를 사용하는 것이 불가능하다고 한다.

     

     

    그리고 속도, 용량의 이점은 8086 CPU를 설계할 때 리턴 후 어차피 stack pointer 위치를 변경할 건데

    굳이 호출 후 연산을 해야 하나 싶어서 ret N 과 같은 명령어를 만든 것이라고 한다.

     

     

    예전부터 궁금했지만 알아보기 귀찮아서 넘어갔던 것들인데 이렇게 간단한 이유일 줄은 몰랐다.

Designed by Tistory.