둠치킨
코딩하는 둠치킨
둠치킨

블로그 메뉴

  • 홈
  • 분류 전체보기 (230) N
    • 프로그래머스 (3) N
      • 해시 (1)
      • 다익스트라 (1) N
      • 크루스칼 (1) N
    • BOJ (179) N
      • 스택 (14)
      • 큐 (5)
      • 덱 (4)
      • 그래프 (32)
      • 배열 (8)
      • 재귀 (12)
      • 브루트 포스 (2)
      • 그리디 알고리즘 (7)
      • 다이내믹 프로그래밍 (14)
      • 백트래킹 (24)
      • 기하학 (4)
      • 트리 (4)
      • 구현 (14)
      • 수학 (4) N
      • 맵 (1)
      • 다익스트라 (2)
      • 누적합 (5)
      • 유니온 파인드 (1)
      • 분할 정복 (2)
      • 벨만-포드 (1) N
    • 자료구조 (15)
      • 스택 (3)
      • 큐 (5)
      • 덱 (2)
      • 그래프 (1)
      • 트리 (2)
      • 힙 (1)
      • 정렬 (1)
    • C++ (11)
      • 모두의코드 (2)
      • Effective C++ (3)
      • C++ STL (6)
    • 컴파일러 (1)
    • OS (17)
    • 컴퓨터 구조 (2)
    • Unreal Engine 5 (2)

공지사항

전체 방문자
오늘
어제

인기 글

최근 글

태그

  • BFS
  • boj
  • Bruteforce
  • C
  • C++
  • C++ STL
  • Cache Memory
  • deadlock
  • DFS
  • Effective C++
  • java
  • Mutex
  • next_permutation
  • os
  • Process
  • rotate
  • semaphore
  • spin lock
  • STL
  • STL C++
hELLO · Designed By 정상우.
둠치킨

코딩하는 둠치킨

OS

함수 호출의 리턴 주소는 어떻게 스택에 저장될까?

2025. 6. 23. 20:52

리턴 주소는 어떻게 스택에 저장될까?

C/C++을 포함한 대부분의 언어에서 함수 호출은 단순히 점프(jump)하는 것이 아니라, 나중에 돌아올 위치를 기억해야 하기 때문에 "리턴 주소(return address)"라는 개념이 사용됩니다. 이 리턴 주소는 스택(stack)에 저장되며, 함수가 끝나면 이 주소로 제어가 돌아옵니다.

이번 글에서는 리턴 주소가 스택에 어떻게 저장되고 다시 복원되는지, 그 과정을 함수 호출 단계별로 자세히 정리해보겠습니다.


1. 함수 호출 시: call 명령어의 역할

C++ 함수가 호출되면, 컴파일된 어셈블리 코드에서는 보통 다음과 같은 명령어가 사용됩니다:

call 함수_주소

이 call 명령은 다음 두 가지 일을 동시에 합니다:

  1. 리턴 주소를 스택에 push 한다
    → 즉, 현재 명령어의 다음 주소(복귀 위치)를 스택에 저장합니다.
  2. 함수로 점프한다
    → 스택에 주소를 저장한 뒤, 해당 함수의 코드로 제어를 이동합니다.

예를 들어:

push rip ; 리턴 주소 저장
jmp 함수_주소 ; 함수로 이동

2. 함수 종료 시: ret 명령어의 역할

함수가 끝나면 ret 명령어가 호출되며, 이는 다음 동작을 수행합니다:

  1. 스택에서 값을 pop
    → 가장 위에 있는 값, 즉 리턴 주소를 꺼냅니다.
  2. 그 주소로 점프
    → 프로그램의 흐름을 호출했던 함수의 다음 줄로 되돌립니다.

예:

pop rip ; 리턴 주소 복원
jmp rip ; 복귀

3. 예제: 함수 호출 시 스택 프레임 변화

void bar() {
    int b = 2;
}

void foo() {
    int a = 1;
    bar();
}

int main() {
    foo();
}

실행 흐름

[ main의 리턴 주소 ]   ← main 호출 시 저장됨 (OS에 의해)
[ foo의 리턴 주소 ]    ← foo() 호출 시 저장됨
[ bar의 리턴 주소 ]    ← bar() 호출 시 저장됨
[ bar의 지역 변수 b ]

함수가 끝날 때마다 ret 명령으로 리턴 주소를 pop하고, 제어를 원래 위치로 되돌립니다.


4. 보안 이슈: 리턴 주소 덮어쓰기

스택에 저장된 리턴 주소는 프로그램의 제어 흐름을 바꾸는 핵심 위치이기 때문에,
과거에는 버퍼 오버플로우 공격의 주요 대상이었습니다.

char buf[8];
gets(buf); // 입력 길이 제한 없음 → 스택의 리턴 주소 덮어쓰기 가능

이런 위험을 막기 위해 현대 시스템은 다음과 같은 보안 장치를 사용합니다:

  • Stack Canary: 리턴 주소 앞에 임의값을 두어 손상 여부 감지
  • ASLR (Address Space Layout Randomization): 리턴 주소 예측 어렵게 만듦
  • NX(Bit): 스택에 저장된 코드를 실행하지 못하게 함
저작자표시 (새창열림)

'OS' 카테고리의 다른 글

파편화 (Fragmentation)  (0) 2025.06.24
동기화 객체란?  (0) 2025.06.23
데드락(Deadlock)이란?  (0) 2025.06.23
임계영역(Critical Section) 이란?  (0) 2025.06.23
변수들이 메모리에 저장되는 영역  (0) 2025.06.23
    'OS' 카테고리의 다른 글
    • 동기화 객체란?
    • 데드락(Deadlock)이란?
    • 임계영역(Critical Section) 이란?
    • 변수들이 메모리에 저장되는 영역
    둠치킨
    둠치킨
    코딩 공부를 위한 코딩 블로그 기록 일기

    티스토리툴바