윈도우즈 시스템 프로그래밍 10장 - 절차적 함수 호출(Procedure Call) 지원 CPU 모
윈도우즈 시스템 프로그래밍이라는 책과 해당 책의 저자이신 윤성우님의 강의를 통해 공부한 내용을 정리하는 글입니다.
스택 프레임(Stack Frame) 구조
⦁ 함수 호출 과정에서 할당되는 메모리 블록을 가리켜 스택 프레임이라 한다.
⦁ 함수 호출이 완료되면(반환 되고 나면) 기존에 선언된 지역변수에 접근이 불가하다. 할당되었던 메모리가 반환되었다는 뜻이다.
⦁ fct2 함수가 호출되면서 이 함수 내에 선언된 변수 e와 h가 스택에 할당되는데, 이 메모리 블록을 가리켜 스택 프레임이라 한다. fct2 함수가 반환되면 이 스택 프레임은 모두 반환된다.
sp 레지스터
⦁ 스택은 First In , Last Out 이다.
⦁ 스택에 계속해서 데이터를 쌓거나 반환하기 위해서는 현재 어느 위치까지 데이터를 저장했는지 기억해야 한다.
⦁ 이러한 역할을 CPU 내에 sp(Stack Pointer)라는 레지스터가 한다.
⦁ sp 레지스터값은 변수가 하나씩 할당될 때마다 증가하면서 다음 병수가 할당될 메모리 주소를 가리킨다.
⦁ 호출된 함수가 종료될 경우, 스택 프레임 단위로 sp 레지스터 값을 이동시켜야 한다.
⦁ sp 위치를 아래로 이동시키는 것만으로도 이전에 선언된 변수를 반환할 수 있다. 변수 할당 시 이전에 저장된 값들을 덮어 쓸 것이다.
⦁ 그러므로 sp가 가리키는 위치를 아래로 이동시키는 방식으로 스택 프레임을 반환한다.
⦁ 선언하고자 하는 변수가 4바이트 정수형이면 4만큼 sp를 증가시키면 된다.
⦁ 할당된 메모리 공간을 반환할때 얼만큼 sp를 내려야 할지 계산하기 위해 프레임 포인터 레지스터가 필요하다.
프레임 포인터(Frame Pointer) 레지스터
⦁ 새로운 함수가 호출될 때마다 이 레지스터 값을 0으로 초기화한다.
⦁ 위 그림의 상단 부분은 fct1 함수를 호출하는 과정에서 sp 레지스터에 저장된 값을 fp 레지스터에 저장하는 상황
⦁ fp에 저장된 값을 참조해서 fct1 함소 호출 이전으로 sp를 이동시킬 수 있다.
⦁ 위 그림의 하단 부분은 fct1 함수 호출이 끝난 상황이다.
⦁ fct1 함수 호출시에 fp 레지스터에 저장했던 sp 레지스터 값을 다시 sp 레지스터에 되돌리고 있다.
⦁ 하지만 이 방식은 [그림10-3]의 main 함수처럼 함수 호출이 중첩되면 fp가 덮어쓰여지는 문제가 발생한다.
스택에 저장하자, 프레임 포인터(Frame Pointer)
⦁ 위 그림은 함수 호출 시 fp 레지스터에 저장되어 있는 값을 스택에 쌓는 방식을 보여준다.
⦁ sp 레지스터에 저장된 값을 fp 레지스터에 옮기기 전에 fp 레지스터에 저장된 값을 스택에 쌓아두어 모든 스택 프레임의 경계 정보를 저장할 수 있다.
① fct2 함수가 호출되기 전에 sp 레지스터에는 주소값 20이 들어가 있다.
② fct2 함수가 호출되기 직전에 fp 레지스터에는 주소값 8이 들어가 있다. main 함수와 fct1 함수의 경계에 해당하는 주소 정보이다.
③ fct2 함수가 호출되면서 fp 레지스터에 저장된 값(8)을 현재 sp 레지스터가 가리키는 20번지에 저장한다. 그 다음 fp 레지스터에 sp 레지스터 값 20을 저장한다.(fct2와 fct1의 경계)
④ fct2 함수가 반환된다면, fp 레지스터에 저장된 값을 참조해서 sp 레지스터 값을 20으로 변경한다.
⑤ 현재 sp 레지스터가 가리키는 위치(20)에 저장된 값을 fp 레지스터에 옮긴다. 이렇게 fct1 함수 호출이 완료되는 상황에서 sp의 위치를 8번지에 가져다 놓을 수 있게 되었다.