Home Stack, Stack Frame
Post
Cancel

Stack, Stack Frame


CPU를 학습하던 중, 스레드 스택과 함수 스레드 스택 프레임에 대해 알게 됐고, 이를 정리하기 위해 글을 작성하게 되었습니다.

아직 작성 중입니다.




1. Stack, Stack Frame


스택은 스레드 단위로 하나만 존재합니다. 함수마다 독립적인 스택이 따로 있는 것이 아니라, 스레드마다 하나의 스택이 있고 함수 호출마다 그 위에 스택 프레임이 하나씩 쌓입니다. 스레드는 생성 시 자신만의 스택 메모리 영역을 할당받습니다. 이 스택은 해당 스레드 전용이며 다른 스레드는 접근하지 않습니다. 스레드가 중단되거나 다시 실행될 때는 스택 포인터가 레지스터 문맥과 함께 저장되고 복원됩니다. 따라서 스택은 스레드의 실행 상태를 구성하는 요소입니다.

1
2
3
4
# 스레드 단위 스택 분리

Thread A Stack   ← Thread A만 사용
Thread B Stack   ← Thread B만 사용




함수 호출은 스레드 스택 위에서 이루어집니다. 함수가 호출될 때마다 해당 스레드의 스택 위에 새로운 스택 프레임이 생성됩니다. 이 스택 프레임에는 지역 변수, 저장된 레지스터 값, 반환 주소가 포함됩니다. 이 묶음이 하나의 함수 호출을 나타냅니다. 즉, 스택은 스레드의 실행 상태를 저장하는 메모리 영역이고, 스택 프레임은 그 스택 위에서 각 함수 호출을 구분하기 위해 생성되는 실행 단위입니다. 스택은 스레드에 귀속되고, 스택 프레임은 함수 호출에 귀속됩니다.

1
2
3
4
5
6
7
8
9
10
# 스레드 스택 내부 구조

[ Thread Stack ]
┌──────────────┐
│ main frame   │
├──────────────┤
│ foo frame    │
├──────────────┤
│ bar frame    │ ← 현재 실행 중인 함수
└──────────────┘





2. 프레임


모든 스택 프레임은 동일한 스레드 스택 내부에 존재합니다. 함수마다 독립적인 스택이 따로 존재하는 것은 아니며, 스레드마다 하나의 스택이 존재하고 함수 호출마다 그 위에 스택 프레임이 순차적으로 쌓입니다. 따라서 “함수가 자기 스택을 가진다”라는 표현은 개념 설명으로는 사용될 수 있으나, 구조적으로는 정확하지 않습니다.

스택은 스레드의 실행 단위이며, 스택 프레임은 함수 호출 단위입니다. 스레드는 생성 시 자신만의 스택 메모리 영역을 할당받고, 이후 해당 스레드에서 호출되는 모든 함수는 이 스택 위에 프레임을 추가하는 방식으로 실행됩니다. 함수 호출이 끝나면 해당 함수의 스택 프레임은 제거되고, 제어 흐름은 바로 아래 프레임으로 복귀합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 하나의 스레드 스택과 여러 스택 프레임
# Thread Stack
+------------------------------+
| funcC() frame                | <- current
|   - locals                   |
|   - temporaries              |
|   - return address           |
+------------------------------+
| funcB() frame                |
|   - locals                   |
|   - return address           |
+------------------------------+
| funcA() frame                |
|   - locals                   |
|   - return address           |
+------------------------------+
| main() frame                 |
+------------------------------+




현재 실행 중인 함수는 스택 포인터(Stack Pointer) 가 가리키는 자신의 스택 프레임 범위만을 사용합니다. 컴파일러는 함수마다 고정된 프레임 크기와 레이아웃을 결정하고, 생성된 코드는 해당 범위를 벗어나 접근하지 않도록 구성됩니다. 이로 인해 같은 스레드 안에 존재하더라도, 현재 함수는 자신보다 아래에 쌓인 다른 함수의 스택 프레임을 실행 흐름 상에서 접근하지 않습니다.

이러한 제약은 메모리 보호 장치에 의해 강제되는 것이 아니라, 호출 규약(Call Convention) 과 컴파일러가 생성한 코드 규칙에 의해 유지됩니다. 즉, 함수는 오직 자신의 프레임을 기준으로 지역 변수를 접근하고, 반환 시에는 저장된 반환 주소를 통해 이전 프레임으로 정확히 복귀합니다. 그 결과, 함수 내부에서 스택에 저장한 값은 같은 스레드 안의 다른 함수에 의해 임의로 변경되거나 덮어쓰이지 않습니다. 이 의미에서 스택은 함수 실행을 안전하게 분리하며, “스택에 의해 보호된다”라고 표현할 수 있습니다. 다만 이 보호는 스레드 단위의 보호이며, 다른 스레드와는 애초에 스택 영역 자체가 분리되어 있습니다.


This post is licensed under CC BY 4.0 by the author.