3-1 절차적 함수 호출
- 스택 프레임 / 프레임 포인터
- 프로그램 카운터
스택 프레임 / 프레임 포인터
스택 프레임
함수 호출 과정에서 할당되는 메모리 블록
-> 함수 호출이 마무리된 이후에는 해당 함수의 지역 변수에 접근 불가
-> 메모리 블록이 함수 호출이 끝나면서 반환되었기 때문
-> main()이 fct1을, fct1은 fct2를 호출하는 구조
-> fct2의 지역변수 e와 h는 fct2 호출이 완료되면 반환되어 사라지는 스택 프레임에 해당
스택이라는 이름이 부여된 이유는 메모리의 구조적인 특성 때문
-> 가장 먼저 할당되면 가장 나중에 반환, 가장 나중에 반환되면 가장 먼저 반환되는 특성 : Stack
sp 스택 포인터
기본적으로 스택이 데이터를 쌓거나 반환하기 위해서는 어느 위치까지 데이터를 저장했는지 스택의 위치를 기억해야 함
-> CPU 내부에 sp 레지스터 즉, 스택 포인터를 가지고 있음
-> sp 레지스터는 변수가 하나씩 할당될 때마다 그 값이 하나씩 증가
-> 위 사진은 레지스터 예시, 모든 레지스터가 위와 같이 디자인 되지는 않았음
-> sp 레지스터(스택 포인터)는 반환하고 되돌아갈 위치 정보까지 가지고 있는 것이 아닌, 변수 선언 시에 하나씩 값을 증가시키는 작업만을 수행
-> CPU는 fp(프레임 포인터)라는 레지스터의 도움을 받아서 스택의 할당과 해제 작업을 완전하게 수행
-> 프레임 포인터 : 스택 포인터의 위치를 저장하는 역할을 수행
fp 프레임 포인터
프레임 포인터 : 스택 포인터의 위치를 저장하는 역할 수행
ex) 만약 여러 함수를 동시에 호출하면 fp 레지스터에 저장되어 있는 값이 덮어씌워지게 되는 문제 발생
-> sp 레지스터가 되돌아갈 위치를 제공해야하는데 값이 덮어씌워져서 적절한 위치를 제공해주지 못하는 문제 발생
-> 해결 : 프레임 포인터의 값을 스택에 저장하는 방법 사용
sp / fp 포인터 요약
1. 변수가 하나씩 선언
2. sp의 값이 하나씩 증가
3. 다른 함수의 호출이 이루어지면 프레임 포인터는 현재 sp의 위치에 해당하는 정보를 스택에 저장, sp의 값도 1 증가
4. 스택에는 변수 값 + 기존 함수의 위치 정보도 들어가있게 됨
5. 반환되어야 한다면 프레임 포인터가 스택에 저장시켰던 이전 함수의 위치정보를 참조해서 메모리를 해제
프로그램 카운터
코드 영역
프로그램이 동작하기 위한 코드, 즉 컴파일된 명령어들이 올라가는 메모리 영역
-> 프로그램을 실행시키면 코드 영역에 데이터 세그먼트 형성
-> 형성된 데이터 세그먼트(코드 영역)에 명령어들이 순차적으로 올라가서 실행
-> 폰 노이만의 아키텍쳐 구조 중 fetch, execution 과정이 이 영역을 통해서 이루어짐
ex) 명령어의 길이가 4Byte인데, 실행 중인 프로그램이 1000번지의 명령어인 경우
-> 1004번지의 명령어를 fetch 해야함
-> 스택의 지역 변수는 sp와 fp 포인터를 통해 위치를 백업하고 스택을 쌓는 방식으로 컨트롤
-> 코드 영역은 sp와 fp의 컨트롤 영역 밖
-> 따라서 어느 위치에 있는 명령어까지 실행 했는지의 위치정보를 기억하는 레지스터가 존재 : 프로그램 카운터
프로그램 카운터
어느 위치에 있는 명령어까지 실행 했는지의 위치정보를 기억하는 레지스터
-> 스택 포인터의 동작은 프레임 포인터가 보조
-> 프로그램 카운터의 동작은 링크 레지스터가 보조
-> 프로그램 카운터는 링크 레지스터에 위치정보를 백업하고, 링크 레지스터는 데이터를 스택에 저장
-> 백업의 이유는 프로그램 실행의 이전 위치로 되돌아가기 위함
요약
스택 영역에서의 메모리 반환
-> 변수가 하나씩 증가하면서 sp가 증가, 다른 함수 호출이 일어나면 fp가 해당 정보를 스택에 백업
-> 반환하는 경우 스택에 저장된 이전 함수의 위치 정보를 참조하여 sp가 메모리 반환 수행
코드 영역에서의 메모리 반환
-> 명령어가 실행되면서 프로그램 카운터가 증가, 다른 프로그램이 실행되면 링크 레지스터에 기존 정보를 스택에 백업
-> 되돌아가려는 경우, 스택에 저장된 이전 명령어의 위치 정보를 참조하여 이전 위치로 되돌아감