Post List

2018/02/24

System__StackFrame_StackPointer_FramePoiner


스택 프레임(Stack Frame) 구조

이전 내용에서 소개했던 스택은 함수 내에 선언된 변수가 할당되는 메모리 공간입니다.
그럼 여기서 스택 프레임이란, 함수 호출 과정에서 할당되는 메모리 블록(지역변수의 선언으로 인해 할당되는 메모리 블록) 가리켜 스택 프레임이라고 합니다.
CPU내에 sp(stack pointer)라는 이름의 레지스터가 존재합니다이는 레지스터 구조에도 포함되어 있습니다.



예를들면,
main()함수내에 변수 a b 선언되어 있을 , 변수 a b 할당되어 main()함수의 스택 프레임을 구성합니다.

함수 호출이 완료되면 기존에 선언된 지역변수에 접근이 불가능합니다. 주소를 알고 있다 하더라고 말이지요.
이는 할당되었던 메모리가 반환되었음을 의미하는 것입니다.

[ 스택 포인터 레지스터(Stack Pointer) ]
그럼 스택에 데이터를 쌓거나 스택이 반환하기 위해서는 현재 어느 위치까지 데이터를 저장했는지 , 어느 지점까지 스택이 위치한지 기억이 필요하겠죠, 이러한 기능을 해주는 sp 레지스터라는 것이 존재합니다.

sp레지스터값은 변수가 하나씩 할당될때마다 증가합니다. 증가하면서 다음 변수가 할당된 메모리 위치를 가리키게 됩니다.
예를 들어서 할당하고자 하는 변수가 4바이트 정수형 변수라고 하면 sp값을 4만큼만 증가시키면 되고, 8바이트 정수형 변수라고 하면 8만큼 증가시키면 됩니다.

반면에 호출된 함수가 종료될 경우, 스택 프레임 단위로 sp레지스터값을 이동시켜야 합니다.
호출된 함수가 종료될 경우 안에서 선언된 변수들을 동시에 모두 반환해야 하기 때문입니다. 따라서 정작 호출이 완료된 함수를 빠져나오는 시점에서, 앞서 얼마만큼 메모리 공간을 할당했는지 알지 못하기 때문에 프레임 포인터 레지스터를 통해 함수를 빠져 나올시점에 스택 프레임 단위로 sp 아래로 이동시킬 있습니다.

[ 프레임 포인터 레지스터(Frame Pointer) ]
스택포인터 위치를 함수 호출 이전으로 되돌리기 위해 사용하는 레지스터로 함수 호출 이전의 스택포인터위치를 저장해 놓는 역할 하는 레지스터를 가리켜 fp레지스터라 부릅니다.


여기서 짚고 넘어갈점이 있습니다. 스택포인터는 현재 위치를 가리키기 때문에 현재 메모리의 위치만 기억하면 됩니다. 하지만 프레임 포인터의 경우 main함수에서 fct1함수를 호출하고 fct1함수에서 fct2함수를 호출이 , 함수의 기능이 완료되어 이제 함수를 빠져나오게 되면 거쳐왔던 함수마다 스택메모리의 위치를 기억하고 있어야합니다. 왜냐하면 fct2함수에서 할당된 스택메모리를 반환한 fct1함수에서 까지 할당된 스택메모리의 위치로 스택포인트를 변경해야합니다. 하지만 함수내에서 다른함수가 호출될때마다 프레임 포인터의 위치가 계속 덮어씌워지면 지금까지 호출되어온 함수마다 스택메모리의 위치를 잃어버리게 됩니다.
그래서 덮어쓰는 문제가 발생하기 전에, fp 저장된 값을 어딘가에 저장해 두면 됩니다. , 함수 호출이 일어날 때마다 fp레지스터에 저장되어 있는 값을 스택에 저장하는 것입니다. 그리고 나서 새로운 값으로 fp 레지스터를 채웁니다.
원리로 fp레지스터에 저장된 값을 덮어쓰는 문제가 쉽게 해결됩니다.

예를 들어, 함수가 호출되고 반환되는 과정의 sp fp 값을 저장하고 변경하는 과정을 보겠습니다.


먼저, fct2 함수가 호출되기 직전에 sp레지스터에는 주소값 20 들어가 있습니다. 현재 스택 주소를 가리키는 것입니다.
그리고 fp레지스터에는 주소값 8 들어가 있습니다. Main함수와 fct1함수의 경계에 해당하는 주소 정보입니다.
이제 fct2 함수가 호출되면서, fp 레지스터에 저장된 (주소값 8) 현재 sp 레지스터가 가리키는 위치 20번지에 먼저 저장합니다. 다음 fp레지스터에 sp레지스터값 20 저장합니다. 값은 fct1 스택과 fct2 스택의 경계가 됩니다.
이후 fct2 함수 호출이 완료되어 반환하고자 한다면, fp 레지스터에 저장된 값을 참조해서 sp레지스터값을 20으로 변경합니다. 이는 fct2 함수의 스택 프레임을 날리는 효과를 가져옵니다.
현재 sp 래지스터가 가리키는 위치(주소 20번지) 저장되어 있는 값을 fp 레지스터에 옮겨다 놓습니다. 이로써 fct1 함수 호출이 완료되는 상황에서 sp 위치를 8번지에 가져다 놓을 있게 되었습니다. 이는 main 스택과 fct1 스택의 경계가 됩니다.