ImFe's study

스택, 함수에필로그, 프롤로그 본문

Reversing

스택, 함수에필로그, 프롤로그

ImFe 2020. 5. 19. 01:47

프로그램이 동작하는 동안 함수 안에서 지역 변수(Local Variables)를 사용할 때가 많습니다.
지역 변수는 함수가 종료되고 나면 더 이상 참조되거나 사용되지 않기 때문에,

함수 안에서는 마치 연습장과 같은 역할을 합니다. 지역변수들은 스택(stack)에 저장됩니다.

 

 

새로운 함수가 시작 될 때 스택이 준비되고 (Function Prologue)

함수가 종료될 때 스택이 정리됩니다.(Function Epilogue)

이 과정은 레지스터들 중 스택의 가장 윗부분을 가리키는 rsp레지스터와 밀접한 관련이 있습니다.

 

 

rsp는 스택 포인터로, 스택의 가장 위쪽 주소를 가리킵니다.

스택에 새로운 데이터를 담을수록 스택은 점점 길어집니다.

마지막으로 담은 데이터 위에 새로운 데이터를 쌓아가는 방식으로 길어지게 됩니다.

따라서 스택의 가장 위쪽은 마지막으로 데이터가 담긴 메모리 주소입니다.

 

intel x86-64기준 스택은 낮은주소를 향해 자랍니다

= 높은주소에서 낮은주소로

 

 

-Function Prologue/Epilogue

함수가 시작될 때(Function Prologue)에는 rsp레지스터에 들어있는 주소에서 충분한 값을 빼줍니다.

 

이렇게 하면 rsp(stack pointer, 스택의 가장 위쪽)가 가리키는 곳을 낮은 주소로 당겨오는 효과가 있기 때문에, 함수 안에서 지역 변수를 사용하기 위한 공간을 확보하는 효과가 생깁니다.

 

이 때 rsp를 얼마나 내릴 것인지, 즉 스택을 어느 정도의 크기로 확보할 것인지는 컴파일러가 최적화를 통해 결정합니다.

 

함수가 끝날 때(Function Epilogue)에는 프롤로그에서 빼준 값 만큼 다시 rsp에 더해줍니다. 이렇게 스택 포인터를 복원하면 함수에서 사용했던 스택을 정리하는 효과를 볼 수 있습니다.

 

 

-push, pop

push와 pop명령어는 스택에 새로운 데이터를 추가하거나 때 사용합니다.

 

스택에 새로운 데이터를 넣는 명령어는 Push입니다.

새로운 데이터가 들어가면 rsp레지스터도 새로운 데이터가 들어간 주소를 가리켜야 하므로, 오른쪽 예시에서와 같이 push는 1)rsp가 가리키는 주소에서 들어갈 데이터의 사이즈만큼 빼서 데이터가 들어갈 크기를 확보한 뒤 2)데이터를 복사하는 과정과 동일한 효과를 냅니다.

 

pop은 push와 반대로 스택의 최상단에 있는 데이터를 빼내는 명령어이므로, 그 반대 순서로 진행하는 것과 동일한 효과를 냅니다.

 

 

 

-Procedure Call Instruction Instructions (함수 호출규약?)

 

함수를 호출하는 명령어와 함수를 종료하는 명령어입니다.

 

call

함수를 실행할 때에는 call의 명령어가 쓰입니다.

call은 피연산자로 실행할 함수의 주소를 받습니다.

한편, call로 호출한 함수가 종료되고 나면 다음 명령어를 실행할 장소로 돌아와야 합니다.

즉 call을 사용한 이후에 실행되어야 하는 명령어의 주소가 어디인지 기억해둬야 함수가 종료된 다음에도 프로그램의 실행을 이어갈 수 있습니다.

이렇게 함수의 종료 이후에 돌아와야 하는 주소, 즉 리턴할 때 참조해야 할 주소를 Return Address라고 부릅니다.

call의 수행은 Return Address를 스택에 push해 둔 다음, 호출할 함수의 주소로 jmp하는 것과 동일한 원리로 실행됩니다.

 

 

 

ret

호출된 함수가 마지막으로 사용하는 명령어는 ret입니다.

이 명령어는 함수를 종료한 뒤 Return Address로 돌아가는 역할을 합니다.

따라서 스택에 들어있는 Return Address를 pop하여 명령어 포인터인 rip레지스터에 넣은 다음, 그 주소로 jmp하는 것과 동일한 효과를 냅니다.

 

ret명령어를 사용하기 전까지는 함수에서 스택을 모두 정리한 상태입니다. 따라서 Function Epilogue까지 마무리 되어 있으므로 rsp는 함수가 시작하기 직전에 스택에 넣은 값을 가리키고 있습니다. 이 값은 call할때 스택에 넣었던 ReturnAddress이므로, pop을 하면 스택에서 Return Address를 가져오게됩니다.

 

Comments