概要
GCCを使ってソースコードから実行形式を作成するまでの流れをみてみた。
環境
x86_64
centos7
gcc4.8.3
helloWorld
#include <stdio.h>
int main(){
printf("Hello world!!");
}
GCC
コンパイルしてみる
# gcc hello.c -Wall -v
組み込み spec を使用しています。
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/lto-wrapper
ターゲット: x86_64-redhat-linux
configure 設定: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.3-20140911/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.3-20140911/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
スレッドモデル: posix
gcc バージョン 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC)
COLLECT_GCC_OPTIONS='-Wall' '-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/cc1 -quiet -v hello.c -quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello -Wall -version -o /tmp/ccyCCZPY.s
GNU C (GCC) version 4.8.3 20140911 (Red Hat 4.8.3-9) (x86_64-redhat-linux)
compiled by GNU C version 4.8.3 20140911 (Red Hat 4.8.3-9), GMP version 5.1.1, MPFR version 3.1.1, MPC version 1.0.1
warning: GMP header version 5.1.1 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
存在しないディレクトリ "/usr/lib/gcc/x86_64-redhat-linux/4.8.3/include-fixed" を無視します
存在しないディレクトリ "/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../x86_64-redhat-linux/include" を無視します
#include "..." の探索はここから始まります:
#include <...> の探索はここから始まります:
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/include
/usr/local/include
/usr/include
探索リストの終わりです。
GNU C (GCC) version 4.8.3 20140911 (Red Hat 4.8.3-9) (x86_64-redhat-linux)
compiled by GNU C version 4.8.3 20140911 (Red Hat 4.8.3-9), GMP version 5.1.1, MPFR version 3.1.1, MPC version 1.0.1
warning: GMP header version 5.1.1 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 0cfa3e41c61de51fe5b3d2388f47f98a
hello.c: 関数 ‘main’ 内:
hello.c:5:1: 警告: 制御が非 void 関数の終りに到達しました [-Wreturn-type]
}
^
COLLECT_GCC_OPTIONS='-Wall' '-v' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccYhWWtz.o /tmp/ccyCCZPY.s
GNU アセンブラ バージョン 2.23.52.0.1 (x86_64-redhat-linux)、BFD バージョン version 2.23.52.0.1-30.el7_1.2 20130226 を使用
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.3/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.3/:/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-Wall' '-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64
-dynamic-linker /lib64/ld-linux-x86-64.so.2
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/crtbegin.o
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.3
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64
-L/lib/../lib64
-L/usr/lib/../lib64
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../..
/tmp/ccYhWWtz.o
-lgcc --as-needed -lgcc_s --no-as-needed
-lc
-lgcc --as-needed -lgcc_s --no-as-needed
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crtn.o
組み込みスペック
A specs file is plain text used to control the default behavior for the "gcc" front-end.
普通内部に持って行て、外部で持てば上書きできるみたい。そういうものみたい。
COLLECT_LTO_WRAPPER
GCCが使うプラグインで、作業を効率的にするために内部で使用しているみたい。
configure 設定:
GCCをビルドした時のconfigureの設定がみれるみたい。
コンパイル
/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/cc1
がコンパイラの実体。-oで指定されている/tmp/ccyCCZPY.s
にコンパイルされたアセンブラが出力される。
/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/cc1
-quiet -v hello.c -quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello -Wall -version -o /tmp/ccyCCZPY.s
アセンブラ
コンパイルで出力されたアセンブラファイル/tmp/ccyCCZPY.s
を入力値としてオブジェクトファイル/tmp/ccYhWWtz.o
を出力する。
as -v --64 -o /tmp/ccYhWWtz.o /tmp/ccyCCZPY.s
リンカ
/usr/libexec/gcc/x86_64-redhat-linux/4.8.3/collect2
がリンカの実体。
アセンぶりしたオブジェクトファイル/tmp/ccYhWWtz.o
と様々なオブジェクトとリンクして実行形式を作成する。
ダイナミックリンカ指定
GCCは特に何も指定しなければ、共有ライブラリをダイナミックリンクする。なのでプログラム実行時にリンクしてくれるダイナミックリンカを指定している。-staticを指定すれば共有ライブラリも静的にリンクする。ダイナミックリンク→動的なリンカ
-dynamic-linker /lib64/ld-linux-x86-64.so.2
暗黙的にリンクするやつ
下のこれらがCのmainの前に呼ばれて色々準備したり、プログラムが終了するまえに呼ばれて後始末する。これは普通に静的にリンクされるはず。
- crtn.o
- crtend.o
- crtbegin.o
- crti.o
- crt1.o
他にもライブラリをリンクする
-l
-lの後についたxxxを取り出してダイナミックリンクの場合はlibxxx.soを静的リンクの場合はlibxxx.aをリンクする。ダイナミックリンクの場合でもsoがなければ.aを探すみたい。
今回xxxはcでダイナミックリンクなのでlibc.so
(標準Cライブラリ)をリンクする
したみたいな感じ。(動的リンクされるはず)
ldd a.out
linux-gate.so.1 => (0xb776e000)
libc.so.6 => /lib/libc.so.6 (0x49cbd000)
/lib/ld-linux.so.2 (0x49c95000)
-L
ライブラリの検索場所を指定
まとめ
コンパイラは以下の順番で実行形式を作成している。(んープリプロセッサの指定がないような。。)
- プリプロセス
- コンパイル
- アセンブル
- リンク
GCCは内部で様々な作業をしてくれる。コンパイラ狭義の意味としての実体はcc1になる。ただしリンクまで行うことをコンパイルとも呼ぶし、ビルドとも呼ぶ。helloworldするだけのCをコンパイルするだけでも様々なオブジェクトをリンクしていることがわかる。