1. 문제 제기 (Introduction & Problem Statement)
C언어로 작성된 hello.c 파일은 gcc hello.c -o hello 명령어 하나로 간단히 실행 파일이 된다. 개발자에게 이 과정은 익숙하지만, 내부적으로 소스 코드가 어떻게 기계가 이해하는 형태로 변환되며, 이 파일이 어떻게 메모리에 적재되어 CPU에 의해 실행되는지에 대한 이해는 시스템의 동작 원리를 파악하는 데 필수적이다.
본 아티클에서는 hello.c 프로그램을 예시로, 하나의 텍스트 파일이 실행 가능한 프로세스가 되기까지의 전체 파이프라인(전처리, 컴파일, 어셈블, 링킹)과 이를 처리하는 하드웨어(CPU, 메모리, 버스)의 상호작용을 CSAPP의 관점에서 단계별로 분석한다.
2. 기술 분석 및 해결 과정 (Technical Deep Dive)
2-1. 빌드 파이프라인: C 코드가 기계어가 되기까지
hello.c가 hello 실행 파일로 변환되는 과정은 컴파일 시스템에 의해 4단계로 수행된다.
1) 전처리 (Preprocessing)
- 입력:
hello.c(C 소스 파일) - 역할: 전처리기(cpp)가 소스 코드의
#으로 시작하는 지시문(e.g.,#include,#define)을 처리한다. 예를 들어#include <stdio.h>는stdio.h파일의 내용을 소스 코드에 삽입한다. - 결과:
hello.i(수정된 C 소스 파일)
- 입력:
2) 컴파일 (Compilation)
- 입력:
hello.i - 역할: 컴파일러(cc1)가 C 코드를 저수준의 기계 독립적인 언어인 어셈블리어로 번역한다.
- 결과:
hello.s(어셈블리 코드 파일)
- 입력:
3) 어셈블 (Assembly)
- 입력:
hello.s - 역할: 어셈블러(as)가 어셈블리 코드를 기계어(0과 1의 조합)로 변환하고, 이를 '재배치 가능한 목적 파일(relocatable object file)' 포맷으로 패키징한다.
- 결과:
hello.o(바이너리 목적 파일)
- 입력:
4) 링킹 (Linking)
- 입력:
hello.o및 라이브러리 파일(e.g.,printf함수가 포함된libc.so) - 역할: 링커(ld)가
hello.o와 필요한 라이브러리 목적 파일들을 하나로 합쳐 최종 실행 파일을 생성한다. 이 과정에서 각 목적 파일에 흩어져 있는 코드와 데이터의 주소가 결정된다. - 결과:
hello(실행 가능한 목적 파일)
- 입력:
2-2. 실행: 디스크 파일에서 메모리 프로세스로
생성된 hello 파일을 셸에서 ./hello로 실행하면 OS와 하드웨어는 다음과 같이 동작한다.
- 로딩(Loading): 셸은
hello파일을 디스크에서 읽어 주 메모리(DRAM)에 복사(적재)한다. 이 데이터 전송은 CPU를 거치지 않고 디스크 컨트롤러가 메모리에 직접 쓰는 DMA(Direct Memory Access) 방식을 사용하여 CPU의 부담을 줄인다. - 실행(Execution): 데이터 로드가 완료되면 CPU가 프로그램의
main함수부터 명령어를 실행한다.- CPU 내 PC(Program Counter) 레지스터는 다음에 실행할 명령어의 메모리 주소를 저장한다.
- CPU는 PC가 가리키는 주소의 명령어를 메모리에서 읽고(
Load), 해석한 뒤, ALU(산술논리연산장치)를 통해 연산을 수행(Operate)하고, 결과를 다시 레지스터나 메모리에 저장(Store)하는 사이클을 반복한다.
2-3. 성능의 핵심, 메모리 계층 구조 (Memory Hierarchy)
시스템 설계의 근본적인 문제 중 하나는 CPU의 연산 속도와 주 메모리의 접근 속도 간의 큰 격차, 즉 '프로세서-메모리 갭'이다. CPU가 매번 느린 주 메모리를 기다린다면 시스템 전체의 성능이 저하될 수밖에 없다.
이 문제를 해결하기 위해 컴퓨터는 '속도, 용량, 비용'을 고려한 저장장치 계층(Memory Hierarchy) 구조를 채택했다.
| 계층 | 장치 종류 | 특징 |
|---|---|---|
| L0 | 레지스터 | CPU 내부에 위치하며 가장 빠르지만 용량이 극히 작음 (수 KB) |
| L1/L2/L3 | 캐시 (SRAM) | CPU 칩 내/외부에 위치. 레지스터보다 느리지만 메모리보다 훨씬 빠름 (수 MB) |
| L4 | 주 메모리 (DRAM) | 실행에 필요한 코드/데이터를 저장. 캐시보다 느리지만 용량이 큼 (수 GB) |
| L5 | 디스크 (SSD/HDD) | 영구 저장을 위한 공간. 가장 느리지만 용량이 매우 큼 (수 TB) |
CPU는 데이터 요청 시, 가장 빠른 L1 캐시부터 확인한다. 데이터가 있으면(Cache Hit) 즉시 사용하고, 없으면(Cache Miss) 다음 계층(L2, L3, 주 메모리)으로 순차적으로 확인한다. 하위 계층에서 발견된 데이터는 상위 캐시로 복사되어 다음 접근 속도를 높인다.
이 구조는 프로그램이 한 번 접근한 데이터나 그 주변 데이터를 다시 접근할 확률이 높다는 지역성(Locality)의 원리에 기반하기에 효율적으로 동작할 수 있다.
3. 결론 및 고찰 (Conclusion & Takeaways)
- 핵심 요약:
hello.c의 실행은 단순 변환이 아닌, 컴파일 시스템에 의한 번역 파이프라인과 하드웨어의 실행 사이클, 그리고 성능 최적화를 위한 메모리 계층 구조가 상호작용한 결과다. - 향후 과제: 이 분석은 단일 프로그램의 실행에 초점을 맞췄다. 실제 OS 환경에서는 다수의 프로세스가 동시에 실행되는데, 이때 OS는 어떻게 CPU 자원을 분배하고 프로세스 간 전환(Context Switching)을 수행하는지, 그리고 프로세스 내의 실행 단위인 스레드는 메모리를 어떻게 공유하고 동시성 문제를 야기하는지에 대한 추가적인 탐구가 필요하다.
'Study > CSAPP' 카테고리의 다른 글
| [CSAPP] C언어에서 기계어까지: 레지스터, 데이터 이동, 스택의 모든 것 (0) | 2025.10.29 |
|---|---|
| [CSAPP] 정수 오버플로우와 부동소수점의 비밀: 컴퓨터는 어떻게 숫자를 다루는가? (0) | 2025.10.29 |
| [CSAPP] 비트와 바이트: 컴퓨터는 어떻게 숫자와 문자를 저장하고 해석하는가? (0) | 2025.10.22 |
| [CSAPP] 암달의 법칙과 추상화: 성능과 복잡성을 다루는 핵심 원리 (0) | 2025.10.21 |
| [CSAPP] 메모리 계층과 OS의 추상화: CPU는 어떻게 하드웨어를 효율적으로 사용하는가? (0) | 2025.10.21 |