1. 컴파일 과정 개요
C 코드가 실행 가능한 프로그램으로 변환되는 과정은 다음 네 단계로 이루어진다:
- 전처리기 (Preprocessor)
#include, #define 등 매크로와 헤더 파일 처리
- 컴파일러 (Compiler)
- 어셈블러 (Assembler)
- 링커 (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 함수 호출과 스택
- 스택 프레임 구조:
- 호출자의 리턴 주소(push via
call)
- 이전 프레임 포인터(pushq
%rbp)
- 지역 변수 공간(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장은 고수준 언어와 머신 수준 코드 간의 구체적 연결 고리를 제공하여, 디버깅, 성능 최적화, 보안 분석 등 시스템 프로그래밍 전반에 필요한 기초를 다지는 장이다.