[C++] 컴파일 과정
Table of Contents
전처리 단계 #
- 소스 파일에 있는 문자들을 해석한다.
\문자를 해석한다.- 소스 파일을 다음과 같이 분리한다.
- 주석(comment) → 공백 문자 하나로 변경
- 공백 문자
- 전처리 토큰(Preprocessing token) → 컴파일러 토큰의 근간이 된다.
- 헤더 이름
- 식별자
- 문자, 문자열 리터럴
- 연산자들(
+,##)
- 전처리기 실행
#include에 지정된 파일의 내용을 복사한다.#define에 정의된 매크로를 사용해서 코드를 치환한다.#if,#ifndef와 같은 구문들을 실행해서 코드를 치환한다.#pragma와 같은 컴파일러 명령문들을 해석한다.
- 소스 코드 문자 셋에서 실행 문자 셋(Execution character set)의 문자들로 변경한다.
- 인접한 문자열을 합친다.
컴파일 단계 #
- 전처리된 소스 코드 파일(
*.i)을 어셈블리어 파일(*.s)로 변환하는 과정이다.
- 해석 유닛 생성(Translation Unit)
- 전처리기 토큰들이 컴파일 토큰으로 변환이 되고, 컴파일 토큰들은 컴파일러에 의해 해석되어서 TU가 생성된다.
- TU는 각 소스 파일 별로 하나씩 존재하게 된다.
- 유일 정의 규칙(One Definition Rule)
- 각 TU에 존재하는 모든 변수, 함수, 클래스, enum, 템플릿 등의 정의(Definition)는 유일 해야 하고 inline 이 아닌 모든 함수의 변수들의 정의는 전체 프로그램에서 유일해야 한다.
- 네임 맹글링(Name mangling)
- 함수, 변수에게 규칙에 맞는 새 이름을 생성해서 링커가 구분할 수 있게 해주는 것이다.
- 예를 들어, 함수를 오버로딩해서 같은 이름을 가지는 함수가 여러 개일 경우 함수 이름만으로는 구분이 어려워진다. 따라서 컴파일러마다의 규칙을 통해 고유한 새 이름을 지어주는 것이다.
어셈블 단계 #
- 이후 어셈블러가 목적 파일(
*.o) 파일을 생성한다. - 이 목적 파일을 재배치 가능한 목적 파일(Relocatable object file) 이라고 한다.
오브젝트 파일 포멧 #
| 이름 | 설명 |
|---|---|
| 오브젝트 파일 헤더 (Object File Header) |
오브젝트 파일의 기초 정보를 가지고 있는 헤더 |
| 텍스트 섹션 (Text Section) |
.text기계어로 변환된 코드가 들어 있는 부분 |
| 데이터 섹션 (Data Section) |
.rodata(읽기 전용 값), .data(초기화된 전역변수), .bss(초기화되지 않은 전역변수)데이터 영역 변수들(전역 변수, 정적 변수)이 들어 있는 부분 |
| 심볼 테이블 섹션 (Symbol Table Section) |
.symtab소스 코드에서 참조되는 심볼(변수, 함수 등)들의 이름과 주소가 정의되어 있는 부분 해당 오브젝트 파일의 심볼 정보만 가지고 있어야 하기 때문에 다른 파일에서 참조되고 있는 심볼 정보의 경우 심볼 테이블에 저장할 수 없다. |
| 재배치 정보 섹션 (Relocation Information Section) |
.rel.text, .rel.data링킹 전까지 심볼의 위치를 확정할 수 없으므로 심볼의 위치가 확정 나면 바꿔야 할 내용을 적어놓은 부분 |
| 디버깅 정보 섹션 (Debugging Information Secion) |
.debug, .line 디버깅에 필요한 정보가 있는 부분 |
링킹 단계 #
- 컴파일러가 생성한 목적 파일들과 외부 라이브러리 파일들을 모아서 하나의 실행 파일로 만든다.
- 심볼 해석(Symbol Resolution)
- 여러 파일에서 같은 이름의 심볼을 사용할 수 있기에, 같은 이름을 쓰는 모든 심볼에 대해 오로지 하나의 정의에 대응되는지를 확인한다.
- 예를 들어, 여러 파일에 같은 전역 변수인
int count가 있으면 에러를 발생시킨다.
- 메모리 재배치(Relocation)
- 목적 파일에 정의된 심볼들의 위치를 확정시킨다.
- 목적 파일의 재배치 테이블을 참고해서 심볼들이 최종적으로 메모리에 올바르게 배치되도록 한다.
링크 방식 #
- 라이브러리(Library)란?
- 프로그램이 동작하기 위해 필요한 외부 목적 코드들이다.
- 예를 들어,
iostream헤더파일을include했다면, 이 프로그램이 실행하기 위해서는iostream라이브러리가 있어야 하겠다.
- 바인딩(Binding)이란?
- 하나를 다른 것으로 매핑시키는 것을 의미한다.
- 프로그램 내에서 변수, 배열, 라벨, 절차 등의 명칭, 즉 식별자(identifier)가 그 대상인 메모리 주소, 데이터형 또는 실제값으로 배정되는 것이다.
- 정적 라이브러리(Static Library)
- 필요한 라이브러리들이 (링킹 과정에서) 완성된 프로그램 안에 포함된다.
- 즉, 링크 타임에 바인딩된다.
- 동적 라이브러리(Dynamic Library)
- 여러 개의 프로그램에서 똑같은 라이브러리가 필요하다고 모두 포함하면 프로그램 크기가 너무 커질 것이다. 메모리에 하나만 올려 놓고 공유하면 어떨까?
- 프로그램이 동적 라이브러리의 주소만 갖고 있다가, 런타임에 해당 주소에 가서 참조하는 방식이다.
- 즉, 런타임 타임에 바인딩된다.
- OS 메모리 관리 관련 포스팅
References & Further information #
- https://modoocode.com/320
- https://sanghoon23.tistory.com/74
- https://velog.io/@junttang/SP-7.1-Fundamentals-of-Linking
- https://bradbury.tistory.com/226