본문 바로가기

Language/_Assembly

스택과 콜링컨벤션의 이해

Function(1, 2)라고 선언이 된 함수가 사용된다면

push 2
push 1
call 004017E0

이와 같은 어셈블리 코드가 되는데, 파라미터는 뒤에서부터 push가 된다.

그 이유는 스택(stack)에 값을 순서대로 쌓아놓고, 나중에 쌓인 값을 우선으로 해 빼서 사용하기 때문이다.

일반적인 메모리 구조는 그림과 같다.


프로그램이 실행되기 위해서는 실행에 필요한 모든 것들이 메모리에 적재되어야만 한다.

Text : 컴파일된 프로그램 소스가 기계어의 형태로 위치

Data : 프로그램에서 초기화된 데이터들의 위치

BSS : 초기화되지 않은 변수들의 위치. 항상 0으로 초기화됨

Stack : 지역변수, Command Line arguments 위치

Heap : 동적으로 할당된 변수들이 위치

Stack은 LIFO(Last In First Out)이다. 나중에 들어온 것이 먼저 나간다.
스택에 데이터를 넣는 것을 push, 스택에서 값을 추출하는 것을 pop이라고 하며 일반적으로 top으로 명명되는 현재 스택 포인터가 사용된다.
push가 될 때마다 스택 포인터가 하나씩 증가되고 pop이 될 때마다 스택 포인터가 하나씩 감소된다.



스택에 세 번의 push와 두번의 pop이 일어날 때의 메모리 상태이다. push, pop이 일어날 때마다 스택 포인터인 top의 값이 변하는 것을 볼 수 있다.

일반적으로 프로그램에서 함수가 호출될 때마다 새로운 스택이 할당된다. 새로운 함수가 호출되면 프로그램은 현재까지 실행된 곳의 주소를 저장한 뒤 새로운 스택을 생성하여 함수에 필요한 자료들을 처리하고, 함수가 끝나면 저장했던(함수가 시작된 곳) 곳으로 되돌아가서 다음 프로그램을 수행하게 된다.

Intel CPU에서는 EBP, ESP, SFP, EIP 등을 이용하여 스택을 구현하는데 현재까지 실행된 곳의 주소는 EBP에 저장되고, 스택 포인터는 ESP가 된다. SFP는 스택의 top을 가리키는 고정된 주소를 가지고 있으며 EIP는 다음으로 실행할 명령어의 주소를 가리키게 된다.(1)



콜링컨벤션(Calling Conventions) :
스택을 이용하여 파라미터를 전달할 때 스택에 파라미터를 어떠한 순서로 넣을 것이며 또한 전달된 파라미터를 어느 곳에서 해제할 것인가를 결정하는 방식.

1. _cdecl
C 또는 C++ 프로그램에서 파라미터 전달시 디폴트값
파라미터 전달은 오른쪽에서 왼쪽 방향으로 스택에 저장한다.
파라미터 해제는 프로시저를 호출한 것이 책임진다.


2. _stdcall
Window API 프로시저에서 사용한다.
파라미터 전달은 _cdecl과 동일하다.
파라미터 해제는 프로시저 복귀 전에 이루어진다.

장점 :
1. 함수 독립성이 뛰어나다.
2. 프로시저를 부르기 전에 스택에 파라미터를 쌓아놓고 그 프로시저를 부르기만 하면 그 함수가 리턴된 후에는 그 프로시저의 스택 포인터가 이전 상태로 복원되었으므로 복귀한 후에 호출한 프로시저에 대하여 신경쓸 필요가 없다.
3. _cdecl 방식의 콜링컨벤션에 비해 코드 크기가 줄어든다.
4. 스택을 해제하는 코드가 호출한 프로시저 안에 있으므로 이 프로시저가 여러 곳에서 호출된다 할지라도 스택 해제하는 코드는 프로시저 내에 하나만 존재한다.


3. fastcall
처음 두 개까지의 파라미터는 스택을 사용하지 않고, ecx와 edx 레지스터를 사용한다.
그 이상의 파라미터는 오른쪽에서 왼쪽으로 스택에 저장한다.
스택 제거는 _stdcall과 동일하다.

'Language > _Assembly' 카테고리의 다른 글

함수 호출 과정  (0) 2010.03.06
어셈블리 디자인을 통한 컴퓨터 구조의 접근  (0) 2010.02.09
상황별 기초 어셈블리어  (3) 2009.10.26
기초 어셈블리어.  (11) 2009.10.25