본문 바로가기

카테고리 없음

C++ 면접 질문) "빌드 시 컴파일러에서 일어나는 과정에 대해 설명해주세요."

빌드 과정은 크게 전처리, 컴파일, 어셈블, 링크 단계로 나뉩니다.

 

전처리 단계에서 컴파일러는 다음과 같은 일을 합니다:

  • 소스 코드 내 #로 시작하는 전처리 지시문 처리 하여 전처리된 코드 생성
#include <iostream> // iostream 이라는 파일 내용을 다시 전처리 후 복붙

#define VALUE 10 // 코드 내 모든 "VALUE" 가 "10" 으로 다시 타이핑됨
const int value = VALUE; // 예) const int value = 10 으로 변경됨

#ifdef, #ifnedf, #endif 등 // 조건부로 일부 코드를 컴파일러가 못 보게 함.
#ifndef HEADER_GUARD_H // 예) 헤더가드
#define HEADER_GUARD_H
#endif // HEADER_GUARD_H

 

컴파일 단계에서 컴파일러는 다음과 같을 일을 합니다:

  • 전처리된 코드를 어셈블리 코드 (.s 또는 .asm) 로 변환
  • 어셈블리 코드 구성:
    • 명령어와 데이터로 구성됨
    • 크게 다음 section 으로 나눔
      • .text: 명령어 세션
      • .data: 정적 데이터
      • .bss: 초기화 안된 공간만 할당된 데이터
      • .rodata: 읽기 전용 데이터
    • section 에 있는 데이터는 고정된 프로세스 메모리에 위치
  • 하드웨어 종속적인 어셈블리 코드 생성 (x86, ARM, RISC-V)

어셈블리 단계에서 컴파일러 (어셈블러) 는 다음과 같은 일을 합니다:

  • 어셈블리 코드를 기계어로 변환하여 오브젝트 파일 (.o 또는 .obj) 생성
  • 오브젝트 파일 구성:
    • CPU 실행 코드 (기계어)
    • 심볼 정보 (메타데이터): 추후 링커가 사용하기 위한 정보 기록
      • 변수 이름, 주소, 크기, 타입
      • 함수 이름, 주소 등
      • 클래스 이름, 주소 등
      • 외부 심볼 정보
  • 오브젝트 파일 형식은 OS 종속적:
    • linux는 ELF 형식을 따름
    • windows는 COFF 형식을 따름
    • 오브젝트 파일 형식이 있고 실행 파일 형식이 존재함

링크 단계에서는 컴파일러 (링커) 는 다음과 같은 일을 합니다:

  • 실행 파일의 메모리 레이아웃 구성: 실행 프로그램을 켰을 때 의도된 프로세스 메모리 배치
    • 여러 오브젝트 파일 내 각 section 별 크기랑 위치 분석해 section 별 공간 재배치
    • 심볼 테이블 병합:
      • 여러 오브젝트 파일의 심볼 테이블 병합
      • 외부 심볼 정보를 읽어들여서 미해결 심볼 최신화
    • 참조 주소 업데이트 (주소 재배치):
      • 실제 심볼이 올라온 주소를 기입
    • 동적 라이브러리 내용 (.dynamic) 추가:
      • 추후 로더에 의해 올라오는 코드 찾아가기 위함
    • 엔트리 포인트 기입:
      • 추후 로더가 어디서부터 실행해야 할지 알기 위해
  • 위 메모리 레이아웃을 기반으로 실행 파일 생성
  • 메모리 레이아웃 형식도 OS 종속적:
    • linux 로더는 실행 파일을 ELF 형식이라고 가정하고 실행
  • 오브젝트 파일과 실행 파일의 차이점:
    • 오브젝트 파일:
      • 링커에 사용되기 위함
      • 재배치 가능
      • 미해결 심볼 포함
    • 실행 파일:
      • 로더에 사용되기 위함
      • 심볼 모두 해결