CSAPP 3.2장 "Program Encodings" 요약

낚시하는 곰·2025년 4월 5일

krafton jungle

목록 보기
43/52

1. 컴파일 과정 개요

C 코드가 실행 가능한 프로그램으로 변환되는 과정은 다음 네 단계로 이루어진다:

  1. 전처리기 (Preprocessor)
    • #include, #define 등 매크로와 헤더 파일 처리
  2. 컴파일러 (Compiler)
    • C 소스 코드를 어셈블리 코드(.s)로 변환
  3. 어셈블러 (Assembler)
    • 어셈블리 코드를 오브젝트 파일(.o)로 변환
  4. 링커 (Linker)
    • 여러 오브젝트 파일과 라이브러리를 하나의 실행 파일로 결합

2. 3.2.1 머신 수준 코드 (Machine‑Level Code)

  • ISA (Instruction Set Architecture)
    • CPU가 이해하고 실행할 수 있는 명령어 집합과 레지스터, 메모리 모델 등을 정의하는 인터페이스
    • 예: x86‑64, ARM, RISC‑V
  • 가상 메모리 모델
    • 주소는 가상이지만, 하드웨어와 OS가 실제 물리 메모리와 매핑
  • 머신 상태 요소
    • 프로그램 카운터 %rip (다음 명령어 주소)
    • 범용 레지스터 16개 (정수 및 주소 저장)
    • 조건 코드 레지스터 (마지막 연산 상태)
    • 벡터 레지스터 (SIMD 연산용)
    • 메모리: 단순 바이트 배열, 타입 정보 없음

3. 3.2.2 코드 예시 (Code Examples)

long mult2(long, long);

void multstore(long x, long y, long *dest) {
    long t = mult2(x, y);
    *dest = t;
}
  • 어셈블리 (mstore.s)
    multstore:
        pushq %rbx
        movq  %rdx, %rbx
        call  mult2
        movq  %rax, (%rbx)
        popq  %rbx
        ret
  • 기계어 바이트 시퀀스
    53 48 89 d3 e8 00 00 00 00 48 89 03 5b c3
  • 핵심 포인트
    • C 코드 정보는 어셈블리와 기계어 변환 과정에서 대부분 사라짐
    • 함수 호출, 레지스터 사용, 스택 조작(pushq/popq) 등이 실제 바이트 단위로 실행됨

4. 주요 개념 Q&A 요약

4.1 ISA

  • CPU와 소프트웨어 사이의 계약서 역할
  • 명령어 집합, 레지스터, 메모리 모델, 데이터 타입, 인터럽트 처리 포함
  • 이해 시 컴파일러 최적화, 디버깅, 보안 분석에 필수

4.2 레지스터 역할과 종류

  • 역할: 메모리보다 빠른 CPU 내부 저장소
  • 함수 인자 전달 레지스터:
    • 1~6번째 인자: %rdi, %rsi, %rdx, %rcx, %r8, %r9
  • 특수 목적 레지스터: %rsp(스택 포인터), %rbp(프레임 포인터), %rip(명령어 포인터)
  • 레지스터 수가 많은 이유: 성능 향상, 병렬 처리, 호출 규약, 특수 목적 분리

4.3 메모리와 타입

  • 메모리는 단순 바이트 배열
  • 타입 정보는 컴파일러가 해석 방식(읽기/쓰기 크기, 명령어 선택)을 결정
  • 동일한 비트 패턴이 int 또는 float로 해석 시 전혀 다른 값이 됨

4.4 Signed vs Unsigned

  • signed: 음수와 양수 표현 (-2^{n-1} ~ 2^{n-1}-1)
  • unsigned: 0부터 양수만 (0 ~ 2^n-1)
  • 2의 보수 방식 사용
  • 혼합 연산 시 자동 형 변환으로 예상치 못한 결과 발생 주의

4.5 함수 호출과 스택

  • 스택 프레임 구조:
    1. 호출자의 리턴 주소(push via call)
    2. 이전 프레임 포인터(pushq %rbp)
    3. 지역 변수 공간(subq로 확보)
  • 명령어:
    • pushq: 레지스터 값을 스택에 저장, %rsp 8 감소
    • popq: 스택에서 8바이트 꺼내 레지스터에 저장, %rsp 8 증가
    • leave: mov %rbp, %rsp + pop %rbp
    • ret: 스택에서 리턴 주소 꺼내 이동
  • 스택 오버플로우:
    • 무한 재귀 또는 큰 지역 변수로 스택 공간 초과 시 발생
    • 메모리 충돌 및 보안 취약점 가능

4.6 컴파일러의 타입 정보 활용

  • 정확한 명령어 선택: 정수 vs 부동소수점 연산
  • 메모리 접근 크기 결정: char/int/long 크기
  • 타입 검사: 컴파일 타임 에러 탐지
  • 최적화: 불필요 변환 제거, 레지스터·FPU 활용
  • 호환성: 함수 호출 규약 일관성 유지

5. 결론

3.2장은 고수준 언어와 머신 수준 코드 간의 구체적 연결 고리를 제공하여, 디버깅, 성능 최적화, 보안 분석 등 시스템 프로그래밍 전반에 필요한 기초를 다지는 장이다.

profile
취업 준비생 낚곰입니다!! 반갑습니다!!

0개의 댓글