ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • GCC 동작 과정
    지식 조각들/컴퓨터 2018. 8. 13. 21:18

    목차


    서론

    운영 체제의 컴파일러와 링커가 어떻게 동작하는지 학습한 후, 내가 사용하는 컴파일러인 GCC가 어떻게 동작하는지 궁금해졌다. 그래서 간단하게 GCC의 동작 과정을 알아보기로 결심했다. GCC 동작 과정은 [여기][여기]를 보면서 공부했다.

    GCC란

    GCC(GNU Compiler Collection)는 GNU 컴파일러 모음으로 GNU 프로젝트의 일환인 컴파일러이다. 원래는 GNU C Compiler의 약자였지만 C++, JAVA 등 여러 언어를 컴파일 할 수 있게 되면서 현재의 이름으로 바뀌게 되었다. GCC는 컴파일러 모음이기 때문에 단순히 컴파일 과정뿐만 아니라 전처리 과정, 어셈블 과정, 링킹 과정과 같이 실행 파일(binary file)을 만드는데 필요한 작업을 모두 수행한다.

    GCC 동작 과정

    1. 전처리 과정 : 전처리기인 cpp0에 의해 .i 파일 생성

    2. 컴파일 과정 : C 컴파일러인 cc1를 통해.s 파일 생성

    3. 어셈블 과정 : 어셈블러인 as에 의해서 .o 파일 생성

    4. 링킹 과정 : 링커인 collect2를 통해서 실행 파일 생성


    GCC가 수행하는 동작들을 직접 확인하려면 아래와 같은 명령어를 수행하면 된다.

    $ gcc -v -save-temps -o 실행파일명 소스코드명

    -v는 컴파일되는 과정을 화면으로 출력하는 옵션이며, -save-temps는 컴파일 과정 중 생성되는 파일들을 모두 유지하는 옵션이다. 이 명령어를 수행하면 총 네 개의 파일이 생성된 것을 확일 할 수 있다.

    전처리 과정

    전처리 과정은 크게 두 부분으로 나눌 수 있다.

    • 헤더 파일 삽입
    • 매크로 치환 및 적용
    전처리기는 #include 구문을 만나면 해당되는 헤더 파일을 찾아 그 파일의 내용을 삽입한다. 헤더 파일 삽입이 끝난 후 매크로 치환 작업이 시작된다. #define 된 부분은 심볼 테이블에 저장되고 심볼 테이블에 들어있는 문자열과 같은 문자열을 만나면 치환한다. 그 외 다른 전처리기 매크로들도 함께 처리된다.

    컴파일 과정

    컴파일 과정에서 사용된 사진들은 모두 [여기]에서 가져온 것이다. 해당 링크를 타고 들어가면 더 자세한 컴파일 과정 설명을 볼 수 있다. (만약 사진이 문제가 된다면 바로 삭제하겠습니다!)

    컴파일 과정을 요약하면 위와 같다. 지금부터 Front-end, Middle-end, Back-end에서 어떠한 일들을 하는지 살펴보자.

    컴파일 과정1 : Front-end

    Front-end 부분에서는 소스 코드가 올바르게 작성되었는지 확인하는 과정을 거친다. 그 후 소스 코드를 트리 형태로 표현한 자료 구조인 GIMPLE 트리를 생성한다.

    1. 어휘 분석 : 소스 코드를 의미 있는 최소 단위인 token으로 나눈다.
    2. 구문 분석 : 토큰으로 파스 트리(parse tree)를 만들면서 문법적 오류를 검출한다.
    3. 의미 분석 : 파스 트리를 이용해 문법적 오류는 없지만 의미상 오류가 있는지 검사한다. 예를 들어 함수의 매개변수를 잘못 사용했다거나 변수의 자료형이 불일치하는 것 등이 있다.
    4. 중간 표현 생성 : 언어 독립적인 특성을 제공하기 위해 GIMPLE 트리를 생성한다.

    컴파일 과정2 : Middle-end

    Middle-end 부분에서는 GIMPLE 트리를 SSA(Static Single Assignment) 형태로 변환한 후 아키텍처 비종속적인 최적화를 수행한다. 그 후 고급 언어와 어셈블리 언어의 중간 형태인 RTL(Register Transfer Language)을 생성한다.

    컴파일 과정3 : Back-end

    Back-end에서는 RTL optimizer에 의해 아키텍처 비종속적인 최적화가 이루어진다. 그와 동시에 아키텍처 종속적인 최적화도 수행된다. 모든 최적화를 마치게 되면 code generator에 의해 어셈블리 언어로 구성된 .s 파일이 만들어진다.

    어셈블 과정

    어셈블러에 의해 생성되는 목적 코드인 .o 파일은 어셈블된 프로그램의 명렁어와 데이터가 들어있는 ELF 바이너리 포맷 구조를 갖는다.

    as는 목적 코드 파일의 최상단에 ELF 헤더를 붙인다. ELF 헤더에 대한 자세한 정보들을 보려면 readelf를 통해서 볼 수 있다. ELF 헤더 다음에는 명령어를 붙인다. 그 후 데이터(전역변수 및 내부에서 사용된 문자열)가 들어가게 된다. 이 후 컴파일한 GCC 컴파일러의 버전 문자열이 들어간다. 그리고 나머지 기타 섹션인 심볼 테이블(symbol table)과 재배치 테이블(relocation table) 섹션이 들어간다. 자세한 내용은 [여기]를 참조하자.

    링킹 과정

    소스 코드에는 사용되었지만 직접 정의하지 않은 함수를 불러오기 위해 진행되는 작업이다. 이 작업이 끝나면 최종적으로 실행 파일이 만들어진다.

    '지식 조각들 > 컴퓨터' 카테고리의 다른 글

    LINUX 메모리 보호 기법  (0) 2018.08.19
    Dynamic Memory Allocation  (0) 2018.08.14
    Static Memory Allocation  (0) 2018.08.13
Designed by Tistory.