요약
- 스택은 LIFO 구조로 함수 호출마다 스택 프레임을 push하고, 함수 종료 시 pop하여 중첩된 함수 실행을 관리한다
- 각 프레임에 반환 주소가 저장되어 있어 함수 종료 후 어디로 돌아갈지 알 수 있다
본문
스택 프레임에 저장되는 정보
- 반환 주소 (Return Address): 함수 종료 후 돌아갈 코드 위치
- 이전 프레임 포인터: 호출자의 스택 프레임 위치
- 매개변수: 함수에 전달된 인자
- 지역 변수: 함수 내부에서 선언된 변수
반환 주소의 정체
- 반환 주소는 Text 영역에 있는 call 명령어 바로 다음 명령어의 주소
- 반환 주소 값은 Text 영역의 주소, 저장 위치는 Stack 영역
Text 영역
─────────────────────────────
0x1004: call foo ← 함수 호출
0x1009: call bar ← 반환 주소 (foo가 끝나면 여기로)
- call 명령어 자체가 아닌 "다음" 명령어 주소를 저장하는 이유: call 주소로 돌아가면 같은 함수를 다시 호출하여 무한 루프 발생
Text 영역 vs Stack 영역
| 구분 | Text 영역 | Stack 영역 |
|---|---|---|
| 저장 내용 | 코드 (명령어) | 함수 실행 정보 |
| 특성 | 정적 (불변) | 동적 (호출마다 생성/소멸) |
| 예시 | 함수 코드는 한 번만 존재 | 같은 함수 10번 호출 시 10개의 스택 프레임 |
동작 원리
A() → B() → C() 호출 시:
┌─────────────────┐ ← Stack Top
│ C의 스택 프레임 │
├─────────────────┤
│ B의 스택 프레임 │
├─────────────────┤
│ A의 스택 프레임 │
└─────────────────┘
C() 종료 → C 프레임 pop → B로 복귀
B() 종료 → B 프레임 pop → A로 복귀
같은 함수도 호출마다 별도 프레임
int add(int a, int b) {
return a + b;
}
void main() {
int x = add(3, 5); // 첫 번째 스택 프레임 생성 → 종료 시 제거
int y = add(10, 20); // 두 번째 스택 프레임 생성 → 종료 시 제거
}
각 호출이 독립적인 스택 프레임을 가지므로 값이 섞이지 않는다.
스택의 특성
- 자동 메모리 관리: 함수 종료 시 스택 프레임이 자동으로 정리됨 (힙과 달리 명시적 해제 불필요)
- 크기 제한: 스택 영역은 고정 크기(보통 1~8MB)로 할당됨
- Stack Overflow: 재귀 호출이 깊어지면 스택 프레임이 계속 쌓여 크기 제한을 초과할 때 발생