컴파일 과정을 간단하게 살펴보자면,

전처리 Pre-processing 주석 제거, 매크로 인라인화 등의 작업 수행
                 ↓↓↓
컴파일 Compile 컴파일러가 C 소스코드를 컴파일하여 어셈블리어 코드로 변환
                 ↓↓↓
어셈블리 Assembly 어셈블러가 어셈블리어 코드를 기계어 코드로 변환
                 ↓↓↓
링크 Linking 링커가 기계어 코드와 공유 라이브러리를 합쳐서 최종 실행파일 생성

출처 : https://medium.com/@laura.derohan/compiling-c-files-with-gcc-step-by-step-8e78318052

 

 

 

좀 더 확장해서 보면,

1. 코드 에디터(Editor)를 이용해서 C File 을 작성한다.

2. 컴파일러(Compiler)가 C File 을 ASM File 로 컴파일한다. 이 때 오류가 발생하면 에러 메시지를 띄운다.

3. 어셈블러(Assembler)가 ASM File 을 Object File(기계어 파일)로 변환한다.

4. 링커(Linker)가 .o 파일과 라이브러리들을 합쳐서 실행가능한 기계어 파일(Executable Object File)을 생성한다.

5. 로더(Loader)가 Disk 의 내용을 Memory 로 올린다.

 

 

 

이 과정을 직접 리눅스 환경에서 shell 명령어 해석기를 이용하여 실습해보기

// 에디터로 c file 생성
vi hello.c

// 컴파일러로 ASM file 생성
// 이 때, -S 옵션은 컴파일러만 수행하게 하도록 한다. 이 옵션을 안붙이면 실행파일 생성까지 바로 끝난다.
gcc -S hello.c

// 어셈블러로 .o file(object file; 바이너리 파일) 생성
as -o hello.o hello.s

// 링커로 실행파일 만들기
/usr/lib/gcc/i486-linux-gnu/3.4.6/collect2 /usr/lib/i486-linux-gnu/crt1.o /usr/lib/i386-linux-gnu/crti.o /usr/lib/i386-linux-gnu/crtn.o /usr/lib/gcc/i486-linux-gnu/3.4.6/crtbegin.o /usr/lib/gcc/i486-linux-gnu/3.4.6/crtend.o hello.o -lc -dynamic-linker /lib/ld-linux.so.2

// 로딩한 후 최종적으로 실행하기
./a.out

 

 

이 때, 컴퓨터 시스템에서 로더 Loader 가 필요한 이유를 좀 더 살펴보자.

CPU는 바이트(bite) 단위 접근이 가능한데, Disk의 경우 섹터(sector) 단위 접근만을 지원한다. 따라서 바이트(bite) 단위 접근을 지원하는 DRAM으로 로더가 로딩을 해주는 작업이 필요하다. 결국 Disk 는 sector 단위, DRAM과 CPU는 bite 단위라는 접근 인터페이스의 차이 때문이다.

+ Recent posts