본문 바로가기

시스템

[시스템] Prologue / Epilogue (프롤로그 / 에필로그)

프롤로그의 사전적 정의는 음악 및 이야기 또는 영화등의 도입부를 의미한다.

 

스택구조에서도 프롤로그는 사전적의미와 유사한 의미를 가진다.

바로 함수의 시작을 말한다. (시작은 곧 구분을 의미한다.)

 

프롤로그가 일어나기 전 스택에서는 2가지 값이 먼저 쌓이게 되는데 이는 다음과 같다. 

RET

SFP

 

먼저 RET부터 알아보자.

함수가 호출되면 스택에는 먼저 함수가 모든 일을 마치고 돌아갈 주소를 저장한다. 즉, push eip가 일어나는데 우리는 이를 RET라고 부른다.

여기서 eip(Extended Instruction Pointer)란 다음 명령어가 저장되어 있는 주소를 가리키는 포인터를 말한다. 

그림으로 살펴보면 다음과 같다.

그림을 통해 조금 더 쉽게 설명하자면 func1함수를 호출하면 다음 명령어의 주소가 eip에 저장된다는 뜻이다.

(컴퓨터가 이때까지 어떤 코드까지 실행했고 이제는 어떤 코드부터 실행하면 된다는 것을 기억시켜주기 위함이다.)

 

RET가 들어간 스택의 다음공간에는 SFP가 들어가게 되는데 SFP는 Stack Frame Pointer의 약자로 이전 ebp주소를 가리키는 포인터를 의미한다. 즉, 상위 스택 프레임(나를 호출한 함수)의 베이스 포인터를 말한다.

func1함수가 호출되어 스택에 RET이 push되고 SFP가 push될 때 이 SFP는 main함수의 ebp를 가리키게 된다.

SFP를 사용하는 이유는 하나의 함수가 종료되고 그전의 함수로 되돌아 갔을 때 ebp를 정상적으로 사용하기 위함이라고 할 수 있다.

 

이제 프롤로그가 시작된다. 프롤로그의 명령어는 다음과 같다.

push ebp

mov ebp, esp

 

먼저 push ebp부터 살펴보자.

push ebp는 말 그대로 ebp의 값을 push하는 것을 의미한다.

다음은 mov ebp, esp이다.

ebp의 값에 esp값을 옮겨라는 뜻으로 이 명령어로 인해 ebp는 esp의 값과 동일한 값을 가지게 된다.

이는 ebp가 맨 꼭대기로 올라옴으로써(밑단이 맨 위로 올라옴) 이전까지 스택에 쌓여 있는 값들과는 구분되는 새로운 시작이 된다고 말할 수 있다. 우리는 이를 스택프레임이 형성되었다라고 표현한다.

따라서, 우리는 프롤로그를 통해 스택프레임을 형성하고 형성된 스택프레임을 통해 함수를 구분지을 수 있게 되는 것이다.

 

다음은 에필로그의 과정이다.

에필로그는 프롤로그로 형성된 스택프레임을 지우고 이전 함수로 돌아가는 역할을 하며 에필로그의 명령어는 다음과 같다.

leave

ret

 

먼저 leave명령어부터 살펴보자.

leave명령어는 다시 다음과 같은 명령어로 구성되어 있다.

mov esp, ebp

pop ebp

 

mov esp, ebp는 esp의 값에 ebp의 값을 옮긴다. esp의 값이 ebp의 값과 동일한 값을 가지게 된다. 따라서 스택상에 push된 값들이 지워지는데. 즉, 해당 스택프레임을 이루고 있는 함수가 선언한 변수들이 사라지게 되는 것을 의미한다.  -> 이를 통해 지역변수가 왜 해당 함수에서밖에서는 사용하지 못하는지를 알 수 있다.

다음으로 pop ebp는 ebp한 값을 빼는 것으로 이 때 sfp의 값(이전 함수의 ebp값)이 ebp에 들어가게 된다. 따라서 ebp가 이전 함수의 ebp가 되므로 해당 함수의 스택프레임은 완전히 사라지게 된다.

 

마지막으로 ret명령어이다.

ret명령어도 마찬가지로 다시 다음과 같이 2가지의 명령어로 구성된다.

pop eip

jmp eip

 

pop eip는 eip를 꺼냄으로 ret(push eip)의 값을 eip에 넣는다.

jmp eip는 넣은 eip(함수호출한 후 다음 명령어)로 이동한다.

 

궁금한점

1.push ebp, pop ebp, pop eip가 와닿지 않는다.

2.메인함수가 호출될 때의 ebp는 어디를 가리키고 있는가.

반응형