C言語のコンパイルにおけるアセンブラ→実行ファイルまでの流れをまとめてみた
C言語のコンパイラの大まかな流れ
簡単なプログラムであればgcc test.cだけでコンパイルが可能だが、実際のコンパイルは以下の4つの手順を踏んでいる。
以下は、詳しく見ていく。
1、プリプロセッサでソースコードをコンパイラが解釈できるように直す。
プリプロセッサとは、C言語のソースコードをコンパイラが解釈できるように書き直すことだ。
例えば、C言語のコードには#includeや#defineなどのディレクティブ(Directive。日本語で「意味」と言う言葉)が用意されているが、プリプロセッサを行うことで「define MAXのMAXはこういう意味だよ」とか「includeで指定したファイルも読み込んでね」と言う風にコンパイラに教えることができ、これらの情報を基にコンパイラがコンパイルできるようなソースコードに作り直している。
今回の例では、以下のtest.cファイルを用意した。hello worldを表示するための簡単なコードだ。
#include <stdio.h> int main(void){ printf("hello world"); return 0; } ``` 上記のファイルを使って、コマンドラインで以下の様に書いて、プリプロセッサを行う。
gcc -E test.c
```
すると、以下の様な巨大なソースコードが作られる。(以下の例は結構省略したヤツ。)
# 1 "test.c" # 1 "<built -in>" # 1 "<command -line/>" # 1 "test.c" # 1 "c:\\mingw\\include\\stdio.h" 1 3 # 38 "c:\\mingw\\include\\stdio.h" 3 # 39 "c:\\mingw\\include\\stdio.h" 3 # 56 "c:\\mingw\\include\\stdio.h" 3 # 1 "c:\\mingw\\include\\_mingw.h" 1 3 # 55 "c:\\mingw\\include\\_mingw.h" 3 # 56 "c:\\mingw\\include\\_mingw.h" 3 # 66 "c:\\mingw\\include\\_mingw.h" 3 # 1 "c:\\mingw\\include\\msvcrtver.h" 1 3 # 35 "c:\\mingw\\include\\msvcrtver.h" 3 # 36 "c:\\mingw\\include\\msvcrtver.h" 3 # 67 "c:\\mingw\\include\\_mingw.h" 2 3 </built>
上記のコードを生成することで、コンパイラがC言語を解釈できるようになる。
参考記事:プリプロセッサでプログラムの質を向上させよう (1/4):目指せ! Cプログラマ(16) - @IT
参考記事:C言語 プリプロセッサ
また、gcc -E の -Eの部分の意味は定かではないが、おそらくexpand(拡大する)と言う意味ではないか、と言う意見がある。(ソースが少なすぎて困った)
参考記事:c - What does gcc -E mean? - Stack Overflow
2、1で作ったソースコードをアセンブラに直す
1の手順でプリプロセッサを行った後は、アセンブラファイルに書き直す。(別に1の手順を踏むことは必須ではない。1の手順を省略していきなりアセンブルしても、コンパイラが自動でプリプロセッサを行ってくれるからだ)
gcc -S test.c
上記の手順でtest.sと言うアセンブラファイルが生成される。
.file "test.c" .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "hello world\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: LFB10: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $16, %esp call ___main movl $LC0, (%esp) call _printf movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc LFE10: .ident "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0" .def _printf; .scl 2; .type 32; .endef
gcc -Sの-Sの意味は、「Strip the outputでは?(outputを引きちぎる)」と言う意見もある。(ソースが少ない)
参考記事:what does the option -s of gcc mean ?
3, 2のコードをオブジェクトファイル(機械語)に直す
アセンブラファイルが生成された後は、以下のようにコマンドを書く。
as -o test.o test.s
これでtest.oと言うオブジェクトファイル(機械語)が生成される。 また、ここではアセンブリをしたいのでgcc ではなく as で実行する。
4、実行ファイルに直す(exeとかoutとか)
最後にオブジェクトファイルを実行ファイルに直す。
gcc -o test test.o
これでWindowsであればtest.exe、Linuxであればtest.outが生成されてプログラムを実行できる。
gccには他にも色々なオプションが用意されているので、暇な時にチェックしよう。
参考記事:gcc
参考記事:Using the GNU Compiler Collection (GCC): Overall Options