컴파일이란
C같은 고오옹오오오오급 언어를 기계어로 바꿔줘서 컴퓨터가 실행할 수 있도록 해준다.
우리가 흔히 이야기 하는 컴파일 과정은
전처리 -> 컴파일 -> 어셈블러 -> 링커 과정을 거친다.
전처리기
전처리기 부분을 살펴보자
전처리기 과정은 주석을 제거하고 define 등을 치환하고 헤더파일을 삽입해준다.
gcc에서는 다음과 같이 볼 수 있다.

이렇게 소스 파일을 만들고 전처리기 과정을 거쳐 보겠다.
컴파일은
gcc -E -o [파일명].i [파일소스].c
하면된다.

전처리기를 처음 열어보면 뭔가 많이 있다..
전처리기의 역할중 하나인 헤더파일 삽입인데 처음 소스에 #include <stdio.h>가 있다.
때문에 전처리기는 우선 디렉토리를 검색해 stdio.h를 찾는다.
그리고 stdio.h안에도 헤더파일이 삽입되어있을텐데 그럴경우 다시 디렉토리를 검사해 그 헤더파일을 삽입한 후에 나머지 stdio.h을 삽입한다.
마지막 부분에 내려가면 우리의 main소스가 있을것이다.

우선, 주석이 사라진것을 볼수 있다.
그리고 #define mineral 50으로 설정해주고 printf 2번째 인자에 mineral이라고 적었었는데 50으로 치환되어 있는 사실을 확인 할 수 있다.
컴파일
컴파일 과정은 간단하게 어셈코드로 변환하는 작업이다.
컴파일은 전단부 중단부 후단부 셋으로 나눠서 작업이 된다.
각각의 역할을 간단하게 말하다면,
전단부의 역할은 소스코드에서 에러가 있는지 체크한다.
중단부의 역할은 아키텍처와 상관없는 최적화를 시키는 것이다.(SSA를 기반으로 최적화)
후단부의 역할은 해당 아키텍처와 관련있는 최적화를 시킨다. 그리고 어셈블리어로 변환 시켜준다.
아키텍처는 (i386, arm, amd64 등이 있다. )
gcc 로 컴파일 이후를 볼라면
gcc -S -o [파일명].s [파일소스].c
를 입력하면 된다.

짠 우리가 보기 편한 어셈블리어 코드로 보여주는 것을 확인 할 수 있었다.
컴파일 과정에서는 에러 검사도 한다고 했다.
그렇다면 에러 있는 소스는 전처리기 과정이 될까?
확인하기 위해 일부로 에러있는 코드를 만들어 보았다.

보면 printf첫번째에 세미콜론(;)이빠져있는 것을 확인 할 수 있다.
그럼 이제 컴파일 해보자

전처리기 과정은 성공하지만 컴파일 과정에서 에러를 표출해주는 것을 확인할 수 있었다.
어셈블러
어셈블러는 오브젝트 파일을 만들어 준다.(기계어) 오브젝트 파일은 ELF의 구조를 가진다.
쉽게 설명하면 코드영역은 코드영역, bss 등등으로 나누어준다.
컴파일은
gcc -c -o [파일명].o [소스 파일명].c

링커
링킹과정은 어셈블러를 거친 오브젝트 파일들과 라이브러리들을 링크시키고 실행가능한 실행 파일이 만들어진다.
gcc -o [파일이름] [파일 소스명].c

오브젝트파일과 실행파일의 차이점
오브젝트파일과 실행파일 둘다 ELF구조를 가지는데 왜 실행파일만 실행이 되는지 의문이였고
둘의 관계가 시스템 처음 공부할 때는 어려웠었다.
둘의 가장 큰 차이점은 오브젝트파일에는 주소 정보가 확실하지 않다.
말로하는것보다 보는게 더 편하기 때문에
readelf -S(segment 확인)을 통해서 비교해보자

오브젝트 파일의 세그먼트

실행파일의 세그먼트
오브젝트 파일의 address부분을 보면 전부다 0이라는 사실을 알 수 있을것이다.
하지만 실행파일에는 올바른 주소가 적혀 있다.
여기서 링킹과정이 거칠때
오브젝트파일들을 합쳐서 주소를 정한다는 사실을 추가적으로 알수 있다.