컴파일 과정



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"

....
extern int printf (const char *__restrict __format, ...);
...

int main(){
 int a=10;
 int b=20;
 int c=a+b;
 printf("%d + %d = %d\n",a,b,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


정상적으로 실행이 되는 것을 확인할 수 있습니다.


뭔가 복잡해보이지만 이러한 과정을 아는 개발자와 모르는 개발자와는 차이가 있다는 것을 알아두세요.


끝!

블로그 이미지

사용자 REAKWON

와나진짜

댓글을 달아 주세요