이번엔 Stack의 구조와 Stack Frame Pointer에 대해 알아보겠습니다.
Stack이란?
Stack이란 RAM내의 영역 중 하나로
프로그램에서 함수가 호출될 때 필요한 지역변수와 매개변수가 저장되는 영역입니다.
또 Stack은 후입선출(Last In First Out)구조이기 때문에 데이터 저장시 높은 주소에서 낮은 주소방향으로 데이터를 저장하게 됩니다.
Stack의 구조
Stack은 기본적으로 저장공간이기 때문에 데이터를 담을 수 있는 상자가 쭉 늘어서 있는 창고라고 생각하면 됩니다.
그럼 이 Stack에 우리의 컴퓨터는 어떤 방식으로 데이터를 저장하는걸까요?
이해를 위해서 예시를 하나 보도록 하겠습니다.
main(){
int A = sum(1,2)
return A
}
sum(x,y){
return x+y
}
위와 같은 단순한 코드하나를 만들어 봤습니다.
우리가 이 코드로 만든 프로그램을 돌릴때 Stack에선 데이터를 어떻게 처리하는지 보겠습니다.
함수가 호출될 때 Stack엔 매개변수, 반환 주소값, 지역변수 이렇게 3가지의 데이터가 들어갑니다.
main()함수 실행시
- main()함수엔 매개변수가 없어 반환 주소값부터 들어가게 됩니다.
- 가장 아래(높은)주소부터 RET(반환 주소값), RBP(main()함수 스택 프레임의 시작점), 변수 c, 버퍼(지역변수) 이렇게 채워 가는걸 볼 수 있습니다.
위와 같은 함수의 호출 정보를 스택 프레임(Stack Frame) 이라고 합니다.
sum()함수 실행시
- sum()함수는 main()함수 안에서 호출되기 때문에
- sum()함수를 호출하게 되면 main()함수의 스택 프레임위에 다시 sum()함수의 스택 프레임을 쌓게 됩니다.
- sum()함수엔 매개변수가 있어 매개변수 x, y를 먼저 쌓아주는 모습을 볼 수 있습니다.
스택 프레임 포인터(Stack Frame Pointer)
이제 Stack이 어떤식으로 데이터를 저장하는지 알게됐습니다.
그럼 저걸 어떻게 사용해서 프로그램을 돌리는 걸까요?
CPU내에는 레지스터라고 하는 아주 작은 값만을 담을 수 있는(하지만 처리속도가 매우 빠른) 메모리가 있습니다.
CPU는 이 레지스터와 RAM에 저장되어있는 값들을 이용하여 프로그램을 돌립니다.
Stack의 데이터들을 이용할때도 이 레지스터들을 이용하게됩니다.
레지스터는 여러가지 종류가 있지만 Stack에 있는 데이터를 다룰 때 사용하는 레지스터는 SP, FP 레지스터입니다.
SP(Stack Pointer) 레지스터 : 다음 데이터가 저장될 스택의 주소를 담고 있는 레지스터
FP(Frame Pointer) 레지스터 : SP레지스터가 돌아갈 주소(함수 호출 전)를 담고있는 레지스터
SP레지스터는 함수 호출 중 데이터가 저장될 스택의 주소를 가리킵니다. CPU가 SP가 가리키고 있는 스택에 값을 넣고 나면 SP레지스터는 그 위의 주소를 가리키게 변경됩니다.
FP레지스터는 함수 호출 이전에 SP레지스터가 가리키고 있던 주소를 담고있게됩니다.
함수 호출이 끝난 후 SP레지스터는 FP레지스터에 쓰여져있는 주소를 참고하여 함수를 호출하기 이전의 주소로 돌아가게됩니다.
하지만 함수 호출을 여러번 하게 될 경우 FP레지스터의 값이 계속 바뀌기 때문에 스택에 FP레지스터의 값을 저장해 놓음으로써 스택 프레임간의 경계정보를 저장합니다.