hhkb.dev

BLOG

2025-10-10 / 어셈블리 · 04

스택 메모리 관리 기법

스택은 프로그램 실행 흐름과 아주 밀접한 메모리 영역이다. 지역 변수 저장, 함수 호출, 복귀 주소 관리처럼 중요한 동작이 대부분 여기서 일어난다.

1. 스택의 동작 원리(LIFO)

스택은 나중에 들어간 값이 먼저 나오는 LIFO 구조다. 접시를 쌓고 맨 위부터 꺼내는 구조를 떠올리면 된다.

어셈블리에서는 보통 아래 두 명령으로 스택을 다룬다.

  • PUSH: 스택 최상단에 데이터를 넣는다.
  • POP: 스택 최상단 데이터를 꺼낸다.

2. 메모리 성장 방향

스택은 일반 데이터와 다르게 높은 주소에서 낮은 주소 방향으로 자란다.

  • 일반 데이터: 0x100 -> 0x108처럼 증가 방향
  • 스택(PUSH): 0x7FFF -> 0x7FF8처럼 감소 방향

push를 하면 RSP가 줄고, pop을 하면 다시 늘어난다. 스택이 메모리 상단에서 아래로 확장되기 때문이다.

반대로 힙은 낮은 주소에서 높은 주소 방향으로 커진다. 이 두 영역이 서로 침범하지 않게 관리하는 게 메모리 구조의 기본이다.

3. 스택의 용도

스택은 아래 같은 이유로 계속 쓰인다.

  1. 복귀 주소 저장: call 시 함수가 끝난 뒤 돌아올 주소를 저장한다.
  2. 레지스터 백업: 레지스터 수가 제한적이라, 잠깐 값을 빼둘 공간이 필요하다.
  3. 지역 변수 할당: 함수 내부에서만 쓰는 값을 두고, 함수가 끝나면 RSP를 되돌려 한 번에 정리한다.

스택에 저장된 복귀 주소를 덮어써서 흐름을 바꾸는 게 버퍼 오버플로우의 기본 원리다. 입력값 검증이 없으면 버퍼를 넘치게 채운 뒤, 그 뒤의 복귀 주소까지 침범할 수 있다.