티스토리 뷰

[전광성의 어셈블리어 이해하기:5회] 프로시져(Procedure) (2)
저자: 전광성 |  날짜: 2005년 03월 02일  

/
1 .0 함수의 동작 원리
0 프로시져(Procedure)
3 .0 USES 연산자
/
  • 프로시져(Procedure)

    고급언어를 공부했다면, 프로그램을 함수(function)로 잘게 쪼개어 작생하는 것이 얼마나 유용한지에 대해 잘 알고 있을 것이다. 해결해야할 복잡한 문제들을 작은 부분들로 쪼개어 하나하나 풀어간다면 프로그래밍이 한결 쉬워진다. 어셈블리에서는 이를 프로시져(Procedure)라고 부른다.

  • PROC 디렉티브

    프로시져의 정의란, 고급언어에서 함수를 정의하는 것과 같다. 먼저 우리가 앞선 예제들에서 나오던 main 프로시져를 생각해 보자. 기억이 나지 않을 테니 main프로시져를 정의했던 예를 적어보겠다.

      main PROC
      .
      .
      main ENDP

    프로시져의 정의는 "프로시져이름 PROC"으로 시작해서 "프로시져이름 ENDP"로 끝난다. 한가지 유의할 사항은 프로시져를 정의할 때 "프로시져이름 ENDP"앞에 함수의 끝을 나타내는 ret 인스트럭션을 반드시 적어 주어야 한다는 것이다. 그런데 가만보자. 방금 들었던 main PROC의 예에서는 ret인스트럭션을 적어주지 않았다. 왜일까? main은 프로세스가 시작되는 특별한 프로시져이기 때문에 ret대신 프로세스를 종료시켜주는 프로시져를 호출해 주어야 한다.

    이렇게 말해서는 제대로 느낌이 오지 않을 듯 싶다. 그래서 eax,ebx,ecx에 들어있는 값들의 합을 eax에 넣어주는 프로시져를 정의해보겠다.

      SumOf PROC
            add eax, ebx
             add eax, ecx
            ret
      SumOf ENDP

    그렇다면 프로시져의 호출은 어떻게 할까? 이전에 잠깐 봤던 call 인스트럭션을 기억하는가?

  • CALL 인스트럭션

    방금 정의한 프로시져를 이용해 세 수를 더하는 예제를 작성해 보겠다.

      mov eax, 1000h
      mov ebx, 2000h
      mov ecx, 3000h
      call SumOf         ; eax = 6000h

    보다시피 우리가 정의해 두었던 프로시져를 호출하려면 "call 호출할프로시져이름"을 적어주기만 하면 된다.

  • CALL 인스트럭션이 하는 일

    본 회의 앞부분에서 함수호출에 대해 간단히 언급하였다. 이번에는 함수호출이 어떻게 이루어 지며, 어떻게 해서 호출환경으로 제어가 넘어가게 되는지에 대해 조금 더 자세히 알아보자. 먼저, 다음과 같은 코드가 있고, 각 인스트럭션 앞에 있는 것이 해당 인스트럭션의 주소라고 하자.

                    main PROC
           00000020 call SumOf
           00000025 mov eax, ebx
                     .....
                    main ENDP

           .....

                    SumOf PROC
            00000040 mov add eax, ebx
                    .....
                    ret
                    SumOf ENDP
    /

    <그림 2 : 프로시져 호출 구조>


    먼저 main프로시져 내에서 call인스트럭션을 만났을 때, 그림 2-(1)과 같이 프로시져가 호출된 다음에 수행할 인스트럭션 주소(25)가 스택에 push된다. 그 다음 인스트럭션 포인터(EIP)에는 호출한 함수가 시작되는 부분의 주소(40)가 들어간다. 따라서 다음의 수행은 EIP에 들어있는 주소의 코드부터 하게 된다. 그러다가 ret인스트럭션을 만나면 그림 2-(2)와 같이 스택에서 아까 저장해둔 값(25)을 pop하여 EIP에 넣게 된다. 따라서 다음에 수행할 인스트럭션은 mov eax, ebx가 된다. 이런 식으로 프로시져는 호출되며 리턴된다.

  • 중첩된 프로시져 호출하기

    함수가 중첩되어 호출되는 상황을 좀 더 쉽게 이해할 수 있게 하기 위해 간단한 예를 들어 보이겠다.

      main PROC
              .
              .
              call Sub1
              exit
      main ENDP

      Sub1 PROC
              .
              .
              call Sub2
              ret
      Sub1 ENDP

      Sub2 PROC
              .
              .
              call Sub3
              ret
      Sub2 ENDP

      Sub3 PROC
              .
              .
              ret
      Sub3 ENDP

    Sub3프로시져가 호출되었을 때는 스택이 그림 3과 같이 되어 있을 것이다.
    /

    < 그림 3 : 스택 >


    이제 스택이 함수 호출에 왜 필수적인지 이해가 가는가?
  • 댓글
    안내
    궁금한 점을 댓글로 남겨주시면 답변해 드립니다.