[C언어] 컴파일 과정(Compile Process) 4단계 자세한 설명
컴파일 과정
Visual Studio에서 우리는 실행할때 F5(또는 Ctrl+F5)를 눌러서 우리가 만든 소스코드를 실행시켜봤죠? 우리는 너무 쉽게 프로그램을 실행시킨다고 생각할 수 있지만 의외로 몇몇 단계를 거치고 있습니다.
이번 시간에는 컴퓨터 실행파일이 어떻게 생겨나는지에 대해서 알아보도록 합시다.
우리가 실행파일을 생성하는데까지는 아래와 같은 과정을 거치게 됩니다. 어? program.c와 program.exe는 알겠는데 나머지 파일들은 무엇일까요?
이 파일들의 정체를 알아내기 위해서 잠시 리눅스를 사용하도록 하겠습니다. 여러분들은 어떤 파일에 어떤 내용들이 기록되는지에 대해서 눈여겨 보면 될 것 같네요.
다음의 소스코드가 어떻게 실행파일로 변하는지 알아보지요.
#include <stdio.h> #define A 10 #define B 20 int main(){ int a=A; int b=B; int c=a+b; printf("%d + %d = %d\n",a,b,c); }
전처리기(Preprocessor)
전처리기 구문(#으로 시작하는 구문)을 처리하는 것이 바로 전처리기라고 하는데요. 일반적으로 #으로 시작하는 부분을 거의 항상 사용합니다. 그것이 언제냐면 바로 #include지요. 너무나도 소중한 printf를 사용하기 위해서는 항상 #include <stdio.h>를 항상 명시해주어야 하죠.
#include를 통해서 stdio.h의 내용이 그대로 들어오게 됩니다!
또한 위의 코드에서 우리는 #define A 10 과 같은 줄을 볼 수 있는데요. 여기서 전처리기는 A라는 부분을 단순히 10으로 치환합니다.
자. 그렇다면 전처리 과정을 끝낸 program.i는 어떻게 변할까요?
gcc -E program.c -o program.i
위의 명령어로 program.i의 내용을 살펴봅시다.
program.i
# 1 "program.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "program.c"
보세요. stdio.h의 내용이 main위의 그대로 들어오지요? 또한 #define A 10과 같은 내용은 없어지고 A가 10으로 치환된것을 알 수 있습니다.
전처리기는 너무나도 단순한 역할을 하는 군요.
중요한것은 전처리기가 컴파일 단계 맨 처음 단계라는 것을 기억하셔야합니다. 그래야지 전처리를 통한 조건부 컴파일을 이해하게 됩니다.
컴파일러(Compiler)
이제 전처리기를 거쳤으니 컴파일러로 컴파일해줍니다. 컴파일러는 고수준언어를 저수준언어로 나타내는 역할을 수행합니다. 저수준언어라는 것은 기계어와 가장 가까운 언어입니다.
이제 program.i로부터 어떻게 program.s가 생겨나는지 보도록 합시다.
gcc -S program.i -o program.s
program.s
.file "program.c"
.section .rodata
.LC0:
.string "%d + %d = %d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $10, -4(%rbp)
movl $20, -8(%rbp)
movl -8(%rbp), %eax
movl -4(%rbp), %edx
addl %edx, %eax
movl %eax, -12(%rbp)
movl -12(%rbp), %ecx
movl -8(%rbp), %edx
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-16)"
.section .note.GNU-stack,"",@progbits
뭐 저도 잘 모르겠습니다. 그냥 저수준언어로 변한것 밖에는 모르겠네요.
근데 "%d + %d = %d\n" 는 우리가 printf에 썼던 문자열이라는 것을 알 수 있네요.
이것이 컴파일러가 하는 역할입니다. 이제 파일을 오브젝트파일로 변환하는 어셈블러를 보도록 합니다.
어셈블러(Assembler)
이제 완전히 기계어로 바꾸어 주는 역할을 합니다. 우리가 읽을 수 없거든요. 다음의 명령어를 통해서 기계어 파일을 만들고 확인해보도록 하죠.
gcc -c program.s -o program.o
program.o
^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@È^B^@^@^@^@^@^@^@^@^@^@@^@^@^@^@^@@^@^M^@
^@UH<89>åH<83>ì^PÇEü
^@^@^@ÇEø^T^@^@^@<8b>Eø<8b>Uü^AÐ<89>Eô<8b>Mô<8b>Uø<8b>Eü<89>Æ¿^@^@^@^@¸^@^@^@^@è^@^@^@^@ÉÃ%d + %d = %d
^@^@GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-16)^@^@^@^@^@^@^@^@^T^@^@^@^@^@^@^@^AzR^@^Ax^P^A^[^L^G^H<90>^A^@^@^\^@^@^@^\^@^@^@^@^@^@^@=^@^@^@^@A^N^P<86>^BC^M^Fx^L^G^H^@^@^@^@.symtab^@.strtab^@.shstrtab^@.rela.text^@.data^@.bss^@.rodata^@.comment^@.note.GNU-stack^@.rela.eh_frame^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^D^@ñÿ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^D^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^E^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^G^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^H^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^F^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^K^@^@^@^R^@^A^@^@^@^@^@^@^@^@^@=^@^@^@^@^@^@^@^P^@^@^@^P^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@program.c^@main^@printf^@^@-^@^@^@^@^@^@^@
^@^@^@^E^@^@^@^@^@^@^@^@^@^@^@7^@^@^@^@^@^@^@^B^@^@^@
^@^(못 읽겠지?) 뭔가 비웃는것 같은 문자만 있네요. 네, 몰라요.
컴퓨터만 알고 있습니다.
hexdump로 볼까요?
hexdump -C program.o
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 00 00 00 00 00 00 00 00 c8 02 00 00 00 00 00 00 |................|
00000030 00 00 00 00 40 00 00 00 00 00 40 00 0d 00 0a 00 |....@.....@.....|
00000040 55 48 89 e5 48 83 ec 10 c7 45 fc 0a 00 00 00 c7 |UH..H....E......|
00000050 45 f8 14 00 00 00 8b 45 f8 8b 55 fc 01 d0 89 45 |E......E..U....E|
00000060 f4 8b 4d f4 8b 55 f8 8b 45 fc 89 c6 bf 00 00 00 |..M..U..E.......|
00000070 00 b8 00 00 00 00 e8 00 00 00 00 c9 c3 25 64 20 |.............%d |
00000080 2b 20 25 64 20 3d 20 25 64 0a 00 00 47 43 43 3a |+ %d = %d...GCC:|
00000090 20 28 47 4e 55 29 20 34 2e 38 2e 35 20 32 30 31 | (GNU) 4.8.5 201|
000000a0 35 30 36 32 33 20 28 52 65 64 20 48 61 74 20 34 |50623 (Red Hat 4|
000000b0 2e 38 2e 35 2d 31 36 29 00 00 00 00 00 00 00 00 |.8.5-16)........|
000000c0 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 |.........zR..x..|
000000d0 1b 0c 07 08 90 01 00 00 1c 00 00 00 1c 00 00 00 |................|
000000e0 00 00 00 00 3d 00 00 00 00 41 0e 10 86 02 43 0d |....=....A....C.|
000000f0 06 78 0c 07 08 00 00 00 00 2e 73 79 6d 74 61 62 |.x........symtab|
00000100 00 2e 73 74 72 74 61 62 00 2e 73 68 73 74 72 74 |..strtab..shstrt|
00000110 61 62 00 2e 72 65 6c 61 2e 74 65 78 74 00 2e 64 |ab..rela.text..d|
00000120 61 74 61 00 2e 62 73 73 00 2e 72 6f 64 61 74 61 |ata..bss..rodata|
00000130 00 2e 63 6f 6d 6d 65 6e 74 00 2e 6e 6f 74 65 2e |..comment..note.|
00000140 47 4e 55 2d 73 74 61 63 6b 00 2e 72 65 6c 61 2e |GNU-stack..rela.|
00000150 65 68 5f 66 72 61 6d 65 00 00 00 00 00 00 00 00 |eh_frame........|
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000170 00 00 00 00 00 00 00 00 01 00 00 00 04 00 f1 ff |................|
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000190 00 00 00 00 03 00 01 00 00 00 00 00 00 00 00 00 |................|
000001a0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 03 00 |................|
000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001c0 00 00 00 00 03 00 04 00 00 00 00 00 00 00 00 00 |................|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 05 00 |................|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 03 00 07 00 00 00 00 00 00 00 00 00 |................|
00000200 00 00 00 00 00 00 00 00 00 00 00 00 03 00 08 00 |................|
00000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000220 00 00 00 00 03 00 06 00 00 00 00 00 00 00 00 00 |................|
00000230 00 00 00 00 00 00 00 00 0b 00 00 00 12 00 01 00 |................|
00000240 00 00 00 00 00 00 00 00 3d 00 00 00 00 00 00 00 |........=.......|
00000250 10 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 |................|
00000260 00 00 00 00 00 00 00 00 00 70 72 6f 67 72 61 6d |.........program|
00000270 2e 63 00 6d 61 69 6e 00 70 72 69 6e 74 66 00 00 |.c.main.printf..|
00000280 2d 00 00 00 00 00 00 00 0a 00 00 00 05 00 00 00 |-...............|
00000290 00 00 00 00 00 00 00 00 37 00 00 00 00 00 00 00 |........7.......|
000002a0 02 00 00 00 0a 00 00 00 fc ff ff ff ff ff ff ff |................|
000002b0 20 00 00 00 00 00 00 00 02 00 00 00 02 00 00 00 | ...............|
000002c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000300 00 00 00 00 00 00 00 00 20 00 00 00 01 00 00 00 |........ .......|
00000310 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000320 40 00 00 00 00 00 00 00 3d 00 00 00 00 00 00 00 |@.......=.......|
00000330 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000340 00 00 00 00 00 00 00 00 1b 00 00 00 04 00 00 00 |................|
00000350 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
00000360 80 02 00 00 00 00 00 00 30 00 00 00 00 00 00 00 |........0.......|
00000370 0b 00 00 00 01 00 00 00 08 00 00 00 00 00 00 00 |................|
00000380 18 00 00 00 00 00 00 00 26 00 00 00 01 00 00 00 |........&.......|
00000390 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000003a0 7d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |}...............|
000003b0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
000003c0 00 00 00 00 00 00 00 00 2c 00 00 00 08 00 00 00 |........,.......|
000003d0 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000003e0 7d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |}...............|
000003f0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000400 00 00 00 00 00 00 00 00 31 00 00 00 01 00 00 00 |........1.......|
00000410 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000420 7d 00 00 00 00 00 00 00 0e 00 00 00 00 00 00 00 |}...............|
00000430 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000440 00 00 00 00 00 00 00 00 39 00 00 00 01 00 00 00 |........9.......|
00000450 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............|
00000460 8b 00 00 00 00 00 00 00 2e 00 00 00 00 00 00 00 |................|
00000470 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000480 01 00 00 00 00 00 00 00 42 00 00 00 01 00 00 00 |........B.......|
00000490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000004a0 b9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000004b0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
000004c0 00 00 00 00 00 00 00 00 57 00 00 00 01 00 00 00 |........W.......|
000004d0 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000004e0 c0 00 00 00 00 00 00 00 38 00 00 00 00 00 00 00 |........8.......|
000004f0 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000500 00 00 00 00 00 00 00 00 52 00 00 00 04 00 00 00 |........R.......|
00000510 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
00000520 b0 02 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00000530 0b 00 00 00 08 00 00 00 08 00 00 00 00 00 00 00 |................|
00000540 18 00 00 00 00 00 00 00 11 00 00 00 03 00 00 00 |................|
00000550 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000560 f8 00 00 00 00 00 00 00 61 00 00 00 00 00 00 00 |........a.......|
00000570 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000580 00 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 |................|
00000590 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000005a0 60 01 00 00 00 00 00 00 08 01 00 00 00 00 00 00 |`...............|
000005b0 0c 00 00 00 09 00 00 00 08 00 00 00 00 00 00 00 |................|
000005c0 18 00 00 00 00 00 00 00 09 00 00 00 03 00 00 00 |................|
000005d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000005e0 68 02 00 00 00 00 00 00 17 00 00 00 00 00 00 00 |h...............|
000005f0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000600 00 00 00 00 00 00 00 00 |........|
00000608
그냥 보지마세요. 머리만 아픕니다.
아 그냥 기계만 해석할 수 있는 언어구나~ 아시면 됩니다.
링커(Linker)
링커는 이름이 말해주듯 연결해주는 역할을 합니다. 여러개의 오브젝트파일을 하나로 합치거나 라이브러리를 합칠때 링커가 필요하다는 거지요.
우리는 일반적으로 개발할때 협업을 합니다. 그래서 위와 같이 오브젝트 파일(.o)라던가 라이브러리 파일이 여럿 존재할 수 있는데 하나의 소프트웨어를 만들기 위해서는 위의 파일들을 합쳐야하는 거죠. 이해되셨나요?
이제 실행파일을 만들어봅시다.
gcc program.o -o program.exe
그 후 실행을 시키면
./program.exe
10 + 20 = 30
정상적으로 실행이 되는 것을 확인할 수 있습니다.
뭔가 복잡해보이지만 이러한 과정을 아는 개발자와 모르는 개발자와는 차이가 있다는 것을 알아두세요.
끝!