[CSAPP 3장 완전 정복] 3.7 함수 호출, 스택, 레지스터의 삼각관계

2025. 4. 7. 13:33·크래프톤 정글/컴퓨터구조(CSAPP)

함수 호출, 스택, 레지스터의 삼각관계

C에서의 function(a, b) 한 줄은 어셈블리어 세계에서는 꽤 복잡한 과정으로 번역됩니다. 이번 3.7절은 바로 그 "함수 호출의 내부 구조", 즉 스택을 어떻게 쓰고, 레지스터를 어떻게 관리하며, 인자와 반환값은 어떻게 주고받는지를 설명합니다.

 

이번 포스트부터는 우리가 배운 어셈블리 구조를 바탕으로, 함수 호출, 조건문, 반복문 같은 C 코드의 익숙한 구문들이 어셈블리에서 어떻게 구현되는지를 직접 매핑해보는 방식으로 진행할 예정입니다.

 

 

C 함수 호출, 내부적으로 어떤 일이 벌어질까?

int sum(int a, int b) {
    return a + b;
}

int main() {
    int x = sum(3, 4);
}

main에서 sum이 호출되어 반환값이 변수 x에 할당되는 간단한 코드가, 어셈블리어 수준에서는 어떤 흐름으로 작동하는지 살펴보겠습니다.

 

 

C -> 어셈블리 매핑: sum 함수의 호출 흐름

1. 인자 전달

sum(3, 4);
  • 인자 3, 4는 각각 %edi, %esi 레지스터에 담깁니다.

x86-64 (System V ABI)에서는 인자 6개까지를 %rdi,  %rsi,  %rdx,  %rcx,  %r8,  %r9 순서로 레지스터에 전달하고,
7번째 인자부터는 스택을 통해 전달합니다.

 

2. call 명령어를 통해 함수로 점프

call sum은 "함수를 마치고 돌아올 위치"인 다음 명령어 주소(복귀 주소)를 스택에 저장(push)한 뒤, 함수 sum으로 이동합니다. 이 주소는 나중에 ret 명령어로 복귀할 때 사용됩니다.

 

다시말해 call 명령어는 ret과 함께 사용되며, 스택 기반의 복귀 흐름을 만듭니다.

 

3. 함수 내부 실행 & 스택 프레임 설정

sum:
    pushq %rbp
    movq %rsp, %rbp          ; 새로운 스택 프레임 생성
    movl %edi, -4(%rbp)      ; a 저장
    movl %esi, -8(%rbp)      ; b 저장
    movl -4(%rbp), %eax
    addl -8(%rbp), %eax
    popq %rbp
    ret

스택 프레임은 push %rbp → mov %rsp, %rbp 순서로 생성되고, 지역 변수는 보통 %rbp 기준 음수 offset에 저장됩니다.

 

4. 반환값 전달

  • sum의 결과는 int형이므로 %eax에 저장되며, long형 반환이면 %rax를 사용합니다.
  • 그리고 main 함수는 %eax 값을 받아 변수 x에 할당합니다.

x86-64에서는 함수 반환값은 항상 %rax에 저장됩니다.

 

 

함수 하나당 생기는 스택 프레임 구조

[ 이전 %rbp가 저장된 메모리 주소 ]  ← 현재 함수의 %rbp 값이 가리키는 위치
[ 복귀 주소(리턴 주소) ]
[ 인자 7번 이후 ]
[ 지역 변수들 ]  ← %rsp (스택은 아래로 확장됨)
  • %rbp는 함수 기준점을 고정
  • %rsp는 현재 스택 꼭대기

→ 함수마다 해당 함수의 실행을 위한 독립적인 작업 공간이 만들어집니다.

 

스택 프레임이 없는 함수도 있을까?

함수 호출 시에 항상 스택 프레임이 만들어지는 건 아닌데요. 함수 안에서 지역 변수를 사용하지 않고, 다른 함수를 호출하지도 않는 경우, 컴파일러는 스택 프레임 생성을 생략할 수 있습니다.

 

이를 리프 함수(leaf function)라고 부르며, 이런 함수는 단순히 레지스터만으로 작업을 수행하고 바로 반환(ret)합니다. 이러한 최적화는 함수 호출 비용을 줄이고 성능을 높이는 데 유리합니다.

 

 

서로 약속해서 나눠 쓰는 레지스터

레지스터 사용 규약
Caller-saved %rdi, %rsi, %rdx, %rcx, %r8, %r9, %rax, %r10, %r11
→ 호출 전에 백업 필요
Callee-saved %rbx, %rbp, %r12~%r15
→ 함수 내부에서 쓰려면 복원해야 함  

이 규약을 지키면 함수들이 서로의 레지스터 값을 안전하게 유지할 수 있습니다.

 

 

함수 호출 정리

C 개념 어셈블리 매핑
함수 호출 call, 복귀 주소 push, ret
인자 전달 %rdi, %rsi 등 레지스터
지역 변수 스택 프레임의 오프셋 위치
반환값  %rax

이 구조를 이해하면 디버깅 시 스택을 추적, 함수 호출 흐름 파악, 보안/버그 분석 시 리턴 주소, 오버플로우 개념을 명확히 할 수 있습니다.

 

 

마치면서

C에서의 함수 호출은 어셈블리에서 정해진 스택 구조와 레지스터 규약에 따라 정교하게 구현됩니다. 그 흐름을 매핑해서 이해하면, C 코드가 어떻게 실행되는지를 스택과 레지스터 수준에서 정확히 따라갈 수 있게 됩니다.

 

이제 함수 호출의 구조를 정확히 이해했다면, 다음 포스트에서는 배열처럼 연속된 메모리 구조를 다루는 배열 접근을 다뤄보겠습니다. 감사합니다.

 

저작자표시 비영리 변경금지 (새창열림)

'크래프톤 정글 > 컴퓨터구조(CSAPP)' 카테고리의 다른 글

[CSAPP 3장 완전 정복] 3.8.5 동적 배열(VLA), 주소 계산은 어떻게 달라질까?  (0) 2025.04.08
[CSAPP 3장 완전 정복] 3.8 배열, 포인터, 주소 계산의 모든 것  (0) 2025.04.07
[CSAPP 3장 완전 정복] 3.4 메모리와 레지스터, 정보를 어떻게 읽고 쓸까?  (0) 2025.04.06
[CSAPP 3장 완전 정복] x86-64 어셈블리 필수 배경지식 핵심 정리  (0) 2025.04.06
[CSAPP 3장 완전 정복] 3.5 기계 수준의 연산, 어떻게 작동할까?  (0) 2025.04.05
'크래프톤 정글/컴퓨터구조(CSAPP)' 카테고리의 다른 글
  • [CSAPP 3장 완전 정복] 3.8.5 동적 배열(VLA), 주소 계산은 어떻게 달라질까?
  • [CSAPP 3장 완전 정복] 3.8 배열, 포인터, 주소 계산의 모든 것
  • [CSAPP 3장 완전 정복] 3.4 메모리와 레지스터, 정보를 어떻게 읽고 쓸까?
  • [CSAPP 3장 완전 정복] x86-64 어셈블리 필수 배경지식 핵심 정리
그냥사람_
그냥사람_
IT 관련 포스팅을 합니다. 크래프톤 정글 8기 정경호
  • 그냥사람_
    그냥코딩
    그냥사람_
  • 전체
    오늘
    어제
    • 글 전체보기 N
      • 크래프톤 정글 N
        • 로드 투 정글(입학시험)
        • CS기초(키워드, 개념정리)
        • 컴퓨터구조(CSAPP)
        • Code 정글(C언어)
        • Equipped in 정글(나만무) N
        • 마이 정글(WIL, 에세이)
      • 자료구조&알고리즘
        • 자료구조
        • 알고리즘
      • 일상
  • 블로그 메뉴

    • 홈
  • 링크

    • Github
  • hELLO· Designed By정상우.v4.10.3
그냥사람_
[CSAPP 3장 완전 정복] 3.7 함수 호출, 스택, 레지스터의 삼각관계
상단으로

티스토리툴바