gcc 의 컴파일 과정을 간략히 정리 해 봅니다.

gcc 는 사실 컴파일러 자체를 말하는 것은 아니고, 컴파일 과정에 필요한 여러가지 기능들을 호출하는 역할을 합니다.
따라서 gcc 는 c 언어 뿐만 아니라 다른 언어들도 컴파일이 가능 합니다. 일련의 과정에 다른 언어를 컴파일하는
녀석들을 호출만 해주면 되기 때문입니다.

[컴파일 과정]
전처리 과정 -> 어셈블리 소스파일로 컴파일과정 -> 인스트럭션 코드 생성 과정 -> 링크 과정 

1. 전처리 ( ccp0 ) 
    ★ 소스파일에 포함된 (#include) 파일들을 불러와 현재컴파일할 파일에 복사해서 붙여 넣는다.
     * 결과물 : test.i 

2. 어셈블리 코드로 컴파일 (cc1) 
    ★ 실제 컴파일러라 할 수 있다.
    ★ 어휘분석 -> 구문분석 -> 의미분석 -> 중간언어생성 -> 코드최적화 -> 목적코드생성 의 과정을 거친다.
☆ 어휘 분석 : 전처리 과정에서 생성된 test.i 파일을 문법적 의미가 있는 최소 단위 (토큰) 로 나눈다.
☆ 구문 분석 : 문법석 오류가 있는지 검사 한 후 파서트리를 만든다.
☆ 의미 분석 : 문법상 문제가 아닌 의미상 문제, 즉 선언되지 않은 변수의 사용이나 자료형 불일치,
                    함수 인자개수 등의 문제를 검사 한다.
☆ 중간언어 생성 : 어셈블리 코드로 만들기 전에 최적화를 위해 RTL(Register Transfer Language) 라는
                          lips 언어와 유사한 코드로 생성한다.
    -> 결과물 : test.rtl
☆ 코드 최적화 : 코드의 사이즈를 줄이고, 속도를 높이기 위해 최적화를 진행 한다. gcc 컴파일의 대부분의
                       시간이 소요되며 아래 두단계를 거친다.
    - 중간코드 최적화 
1) 지역 최적화 : 연산강도 경감, 상수계산등의 최적화
2) 전역 최적화 : 사용되지 않는 코드제거
3) 루프 최적화 : 사용하지 않는 루프제거, 루프결합
    - 목적코드 최적화
1) 최대한 메모리보다 레지스트를 사용하게 하고, 효율적인 인스트럭션을 선택하여 메모리 접근을 최적화 한다.
 ☆ 목적코드 생성
    -  최적화된 rtl 코드를 어셈블리 코드로 변환 한다. 
    - 어셈블리코드는 cpu 마다 정해진 인스트럭션(기계어)과 1:1 로 매칭된 코드 이다.
    -> 결과물 : test.s

3. 기계어 코드 생성(as)
    ★ .s 인 어셈블리 코드를 .o 인 오브젝트 파일로 바꾼다.
    ★ 생성된 오브젝트 파일은 ELF(Executable and Linking) 바이너리 파일 구조 규약을 따르며, 
        이유는 여러 오브젝트 파일을 링크 할 때 파일의 구조가 다르다면 불가능 하기 때문임. 바이너리 포멧은 
         a.out  / ELF / COFF 등이 유닉스 시스템 에서 쓰였으며, 현재는 ELF 가 대부분 사용된다. 
         윈도우 시스템 에서는 COFF , PE 가 쓰인다.
        ☆ ELF 파일 구조는 맨위에 ELF 파일헤더, 프로그램 헤더 Table, 섹선1 ~ n , 섹션 헤더 테이블로 구된다. 
        ☆ ELF 파일 헤더를 제외하고 나머지는 컴파일된 파일 마다 다를 수 있으며, 인스트럭션과 데이터, 
            GCC컴파일러 버전 등이 기록 된다.

4. 링크 (collect2)
    ★ 여러개의 오브젝트 파일을 하나로 링크하는 과정이며, 주로 라이브러리의 링크가 이루어 진다.
        ☆ 정적 라이브러리 : 링크시에 라이브러리를 포함해서 실행 파일을 만든다. 따라서 다른 프로그램에서도
                                     같은 라이브러리를 사용 한다면, 중복되기 때문에 용량을 많이 차지 하게 되지만,
                                     링크가 완료된 상태이므로 속도는 빠르다.
        ☆ 동적 라이브러리(공유 라이브러리) : 링크시 라이브러리의 포함 여부만 기록하고, 실제 동작할 때 메모리에
                                     라이브러리를 로드하여 사용한다. 
                                     다른 프로그램에서 같은 라이브러리를 사용 할 경우 메모리에 이미 로드된 것을 사용 하므로,
                                     공유 한다는 의미에서 공유 라이브러리 라고도 한다. 
                                     따라서 단 한개의 프로그램이라도 이 라이브러리를 사용 하고 있으면, 메모리에 상주 하며,
                                     아무 프로그램도 사용 하지 않는다면, 메모리에서 제거 된다. 
                                     실행시 로드되므로 속도는 다소 느릴 수 있으나 중복로드 되지 않아 메모리 사용이 효율 적이다.  
-> 결과물 : 실행 파일 

자료 참조 : 유닉스.리눅스 프로그래밍 필수 유틸리티 (한빛미디어)