스택 메모리 작동구조
스택 프레임(간단한 그림)
함수 A가 함수 B를 호출할 때의 간단한 스택 모양:
高 주소
| 반환값 공간(가능) |
| 지역 변수 (B의 지역) | <-- B의 스택 프레임
| 호출 시 저장한 레지스터 |
| 복귀 주소 (return address) |
| 인자 (call arguments) |
| ... |
低 주소
복귀 주소(return address)는 호출한 함수로 돌아갈 명령어의 주소를 저장합니다. 이 값을 통해 CPU는 함수 실행이 끝난 뒤 어디로 돌아가야 하는지 알 수 있습니다.
레지스터와 명령 포인터
- RIP(또는 IP)은 다음에 실행할 명령어의 주소를 담는 레지스터입니다(64비트 시스템의 경우 RIP).
- 스택 포인터(RSP)나 베이스 포인터(RBP)는 현재 스택 프레임의 위치를 가리킵니다.
레지스터는 메모리를 직접 읽고 쓰는 주체는 아니지만, 메모리 접근과 제어 흐름에 핵심 역할을 합니다.
스택 프레임의 어셈블리 수준 동작 (초심자용 요약)
함수를 호출하면 운영체제와 CPU가 내부적으로 어떻게 동작하는지 이해하면 디버깅과 성능 분석에 도움이 됩니다. 아래는 x86_64 아키텍처(일반적인 System V 규약)를 기준으로 한 간단한 요약입니다. 다른 아키텍처나 호출 규약(Windows 등)은 약간 다릅니다.
- 호출(call)과 복귀(ret)
call명령은 현재 명령 다음 주소(복귀 주소)를 스택에 저장(push)하고, 제어를 호출된 함수의 시작 주소로 옮깁니다.ret명령은 스택에서 주소를 꺼내(just pop) 그 주소로 점프합니다. 이 과정에서 CPU의 명령 포인터(RIP)가 변경됩니다.
- 함수 진입/종료의 전형적인 패턴 (의사 어셈블리)
push rbp ; 이전 베이스 포인터 저장
mov rbp, rsp ; 새로운 베이스 포인터 설정
sub rsp, 0x20 ; 지역 변수용 스택 공간 확보
... ; 함수 본문
mov rsp, rbp ; 스택 포인터 복원
pop rbp ; 이전 베이스 포인터 복원
ret ; 복귀
- `rbp`(베이스 포인터)는 디버깅/프레임 기반 접근(예: [rbp-8] 등)을 쉽게 해 줍니다. 최적화 컴파일러는 `rbp`를 사용하지 않고 `rsp`만으로 프레임을 관리하기도 합니다.
- 지역 변수와 복귀 주소, 저장된 레지스터(saved registers)는 모두 스택 프레임에 위치합니다.
- 인자 전달
- 많은 64비트 규약에서 첫 몇 개 인자는 레지스터(예: RDI, RSI, RDX 등)에 들어갑니다. 추가 인자나 특정 상황에서는 스택을 사용합니다.
- 요약(핵심)
- 스택은 LIFO이며 각 함수는 자신의 스택 프레임을 가집니다.
call은 복귀 주소를 스택에 넣고 점프합니다.ret은 그 주소로 돌아갑니다.- 프롤로그/에필로그 패턴을 알면 로컬 변수 위치, 복귀 주소 위치를 추적할 수 있어 디버깅에 유리합니다.
추가 다룰것
- 레지스터에 대한 전반적인 설명
- cpu의 작동방식
- 함수콜링컨벤션