컴파일러 드라이버

2025. 8. 4. 23:44·CS:APP

gcc와 같은 컴파일러 드라이버는 단순히 컴파일만 하는 게 아니라, 여러 단계를 자동으로 실행해주는 “드라이버(driver)” 역할을 한다.


gcc는 다음 단계를 순서대로 수행한다

*gcc -Og -o main main.c sum.c*
# 또는 (main.c만 컴파일 시)
*gcc main.c -o main*

  1. 전처리기 (cpp)
    • #include <stdio.h> 같은 헤더 포함
    • #define, #ifdef 등 전처리 지시어(매크로) 처리
    • 결과: .i 파일 (순수 C 코드)
      • 똑같은 C 코드지만, 모든 include가 펼쳐진 상태
      • // 예시 출력 int main() { printf("Hello, world\n"); }
  2. gcc -E main.c -o main.i
  3. 컴파일러 (cc1)
    • .i → .s : 어셈블리 코드로 변환
    • 결과: .s 파일 (x86-64 어셈블리)
    • "예시 출력" main: pushq %rbp movq %rsp, %rbp ... call printf
  4. # .s 파일이 나오는 결과자체는 같음 cc1 main.i -o main.s # .i -> .s gcc -S main.c # .c -> .s
  5. 어셈블러 (as)
    • .s → .o : 기계어 바이너리로 변환
    • 결과: 리로케이션 가능한 오브젝트 파일
      • 형식은 ELF지만, 단독 실행 불가능
      • 내부 심볼 테이블(.symtab), 코드 섹션(.txt) 등을 포함
  6. as main.s -o main.o
  7. 링커 (ld)
    • 외부 라이브러리(libc, printf, …)까지 결합
    • 주소 재배치, 심볼 해결, 실행 헤더 추가
    • .o + .o + ... → 실행 가능한 ELF 파일(a.out 또는 지정한 이름)
      • 커널이 읽을 수 있도록 헤더 정리
      • 실행 시 .text, .data, .heap, .stack 등으로 메모리 매핑될 준비 완료
  8. ld main.o -o main

💡 예시 흐름

# 내부적으로는 이런 일들이 순서대로 벌어짐
cpp main.c → main.i
cc1 main.i → main.s
as main.s → main.o
ld main.o sum.o → main (ELF 실행 파일)
확인하고 싶은 것 명령어
전처리 결과만 보기 gcc -E main.c
어셈블리 코드 보기 gcc -S main.c
오브젝트 파일 만들기 gcc -c main.c
디버깅용 ELF 만들기 gcc -g main.c
ELF 구조 보기 readelf -a main / objdump -d main

ELF?

Executable and Linkable Format
유닉스 계열 시스템에서 실행파일, 오브젝트 파일, 공유 라이브러리, 코어 덤프 등을 표현하기 위한 표준 바이너리 포맷임

역할

C로 프로그램을 만들 때 .c → .o → 실행파일 순 생성,

그 중 .o (오브젝트 파일)이나 a.out, main 같은 실행파일이 ELF 포맷으로 저장

ELF는 다음을 포함한 바이너리 구조를 정의:

요소 설명 ELF 섹션 예시
코드 실행할 기계어 명령어 .text
데이터 전역 변수/상수 등 .data, .bss, .rodata
심볼(Symbol) 함수/변수 이름, 주소 등의 테이블 .symtab, .strtab
재배치(Relocation) 함수 호출/주소 참조를 링크 시점에 수정할 정보 .rel.text, .rela.data
디버깅 정보 gdb 같은 도구가 사용할 함수명/소스위치 .debug_info, .line, .stab
ELF 섹션 구분 설명
.text 실제 실행되는 기계어 코드
.data 초기화된 전역 변수
.bss 초기화되지 않은 전역 변수 (공간만 잡음)
.rodata 읽기 전용 상수 데이터 (ex. 문자열)
.symtab 심볼 테이블 (함수 이름, 변수 이름 등)
.rel.text 재배치 정보 (링커가 주소 수정할 때 사용)

ELF 파일의 예

int g = 10;      // .data
int h;           // .bss
char *s = "hi";  // .rodata

int main() {     // .text
  return g;
}

이걸 gcc main.c -o main으로 컴파일하면,

main이라는 ELF 실행파일이 생성


확인해보기

1. 파일 포맷 확인

file main
main: ELF 64-bit LSB executable, x86-64, ...

2. ELF 내부 확인 (요약 정보)

readelf -h main

또는

objdump -x main

왜 중요한가?

이유 설명
리눅스 커널이 읽는 구조 실행할 때 커널은 ELF 헤더를 보고 어디에 어떤 섹션을 매핑할지 결정함
디버깅 가능 gdb, strace 같은 도구는 ELF 심볼 테이블을 이용해 디버깅
동적 링킹 정보 어떤 .so(공유 라이브러리)를 사용하는지도 ELF에 저장
보안 분석에 필수 바이너리 분석, 리버스 엔지니어링, 펌웨어 해킹에서도 ELF를 직접 다룸

728x90

'CS:APP' 카테고리의 다른 글

실행 가능 목적파일의 로딩  (0) 2025.08.09
ELF, Executable and Linkable Format (재배치 가능 목적파일)  (0) 2025.08.08
함수는 추상화의 결과다 - CS:APP 3.7 프로시저 호출  (0) 2025.04.08
스택은 사실 아래로 자란다(push,pop) - CS:APP 3.4.4  (0) 2025.04.07
[C, Assembly] movq 예제  (0) 2025.04.07
'CS:APP' 카테고리의 다른 글
  • 실행 가능 목적파일의 로딩
  • ELF, Executable and Linkable Format (재배치 가능 목적파일)
  • 함수는 추상화의 결과다 - CS:APP 3.7 프로시저 호출
  • 스택은 사실 아래로 자란다(push,pop) - CS:APP 3.4.4
ahpicl64
ahpicl64
in the clouds
  • ahpicl64
    구름
    ahpicl64
  • 전체
    오늘
    어제
    • 분류 전체보기 (95)
      • WIL (4)
      • Jungle (36)
      • AWS (2)
      • SQL (2)
      • CS:APP (17)
      • Algorithm (10)
      • K8s (7)
      • 자료 구조 (10)
      • Spring (4)
      • React (0)
      • 운영체제 (1)
      • 기타등등 (2)
      • 이야기 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    S3
    트러블슈팅
    알고리즘
    부하테스트
    Spring
    EC2
    python
    컴퓨터시스템
    CloudFront
    AWS
    queue
    DevOps
    어셈블리
    github actions
    k8s
    DB
    IAM
    Spring boot
    CSAPP
    자료구조
  • 02-21 06:16
  • hELLO· Designed By정상우.v4.10.3
ahpicl64
컴파일러 드라이버
상단으로

티스토리툴바