#navi_header|C言語系| gccコマンドの裏側を知りたいときのヒント集メモ。 使用環境: CentOS 5.x gcc-4.1.2-48.el5 libgcc-4.1.2-48.el5 cpp-4.1.2-48.el5 binutils-2.17.50.0.6-6.el5 binutils-devel-2.17.50.0.6-14.el5 #more|| 本サイト内の関連URL: - C言語系/memos/gcc - Glamenv-Septzen.net -- http://www.glamenv-septzen.net/view/479 - C言語系/memos/gcc/関数の属性機能("__attribute__") - Glamenv-Septzen.net -- http://www.glamenv-septzen.net/view/577 参考書籍: #amazon||> ||< ---- #outline|| ---- * gccの舞台裏を見たい gccコマンドが隠蔽しているビルド過程を確認し、手動でGNUツールチェインを実行する際のヒント集。 ** "gcc -v"オプション gccコマンドを"-v"オプション付きで実行すると、普段は隠されているビルド過程を出力させることが出来る。 #pre||> $ gcc -v -o foo foo.c Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure --prefix=/usr (...省略...) /usr/libexec/gcc/i386-redhat-linux/4.1.2/cc1 \ -quiet -v foo.c -quiet -dumpbase foo.c \ -mtune=generic -auxbase foo -version \ -o /tmp/ccHJGC4y.s 存在しないディレクトリ "/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../i386-redhat-linux/include" を無視します #include "..." の探索はここから始まります: #include <...> の探索はここから始まります: /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり GNU C version 4.1.2 20080704 (Red Hat 4.1.2-48) (i386-redhat-linux) compiled by GNU C version 4.1.2 20080704 (Red Hat 4.1.2-48). GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64436 Compiler executable checksum: 625231d1211c3689652276225f4f5c88 as -V -Qy -o /tmp/ccup2RC0.o /tmp/ccHJGC4y.s GNU assembler version 2.17.50.0.6-6.el5 (i386-redhat-linux) using BFD version 2.17.50.0.6-6.el5 20061020 /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 \ --eh-frame-hdr -m elf_i386 \ --hash-style=gnu \ -dynamic-linker /lib/ld-linux.so.2 \ -o foo \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. \ /tmp/ccup2RC0.o \ -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ -lc -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o ||< ** ヘッダーファイルのインクルード状況を確認したい("-H"オプション) プリプロセスだけを行う"-E"オプションと併用すると効果的。 #pre||> $ gcc -H -E -o foo.i foo.c . /usr/include/stdio.h .. /usr/include/features.h ... /usr/include/sys/cdefs.h .... /usr/include/bits/wordsize.h ... /usr/include/gnu/stubs.h .... /usr/include/bits/wordsize.h .... /usr/include/gnu/stubs-32.h .. /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h .. /usr/include/bits/types.h ... /usr/include/bits/wordsize.h ... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ... /usr/include/bits/typesizes.h .. /usr/include/libio.h ... /usr/include/_G_config.h .... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h .... /usr/include/wchar.h ..... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ..... /usr/include/bits/wchar.h .... /usr/include/gconv.h ..... /usr/include/wchar.h ...... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ..... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h ... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stdarg.h .. /usr/include/bits/stdio_lim.h .. /usr/include/bits/sys_errlist.h ||< 複数のインクルードPATHを調整する場面で役立つだろう。 ** システムヘッダーのインクルードPATHを確認・調整したい("-print-search-dirs", "-I", "-I-" オプション) #pre||> $ gcc -print-search-dirs インストール: /usr/lib/gcc/i386-redhat-linux/4.1.2/ プログラム: =(省略) ライブラリ: =(省略) ||< cppコマンドがインストールされている場合は、 $ cpp -print-search-dirs でも同じ結果になる。 実行時に確認したい場合は、"-v"オプションを使うとよいだろう。 #pre||> $ gcc -v -E -o foo.i foo.c (省略) #include "..." の探索はここから始まります: #include <...> の探索はここから始まります: /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり ||< "-I"オプションを指定して、"#include <...>"の検索PATHを追加してみる: #pre||> $ gcc -v -I/tmp -E -o foo.i foo.c (省略) #include "..." の探索はここから始まります: #include <...> の探索はここから始まります: /tmp /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり ||< "-I-"オプションを活用し、"/tmp"を"#include """ にのみ追加し、"/home"を"#include <>"に追加してみる: #pre||> $ gcc -v -I/tmp -I- -I/home -E -o foo.i foo.c (省略) #include "..." の探索はここから始まります: /tmp #include <...> の探索はここから始まります: /home /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり ||< 上記オプションは"cpp"コマンドでも同様に利用可能。 ** "-print-prog-name", "-print-file-name", "-print-libgcc-file-name"オプション "cc1", "collect2"など、gccが舞台裏で起動しているgccツールのフルパスを取得する: $ gcc -print-prog-name=cc1 /usr/libexec/gcc/i386-redhat-linux/4.1.2/cc1 $ gcc -print-prog-name=collect2 /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 gccのランタイムライブラリファイルのフルパスを取得する: | $ gcc -print-libgcc-file-name | /usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc.a | | $ gcc -print-file-name=crti.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o | | $ gcc -print-file-name=crt1.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o | | $ gcc -print-file-name=crtbegin.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o | | $ gcc -print-file-name=crtend.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o | | $ gcc -print-file-name=crtn.o | /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o | ** リンク時にリンクされるファイルのPATHを確認したい("ld -t") binutilsのlinkerであるldコマンドの"-t"オプションを使う。 -t : trace link files #pre||> $ gcc -c -o foo.o foo.i $ gcc -o foo -Wl,-t foo.o /usr/bin/ld: mode elf_i386 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o foo.o -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /lib/libc.so.6 (/usr/lib/libc_nonshared.a)elf-init.oS /lib/ld-linux.so.2 -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o ||< ** リンカのデフォルト検索PATHを確認したい("ld --verbose") ld --verbose でリンカスクリプト表示、SEARCH_DIR()を確認する。 #pre||> $ ld --verbose GNU ld version 2.17.50.0.6-6.el5 20061020 Supported emulations: elf_i386 i386linux using internal linker script: ================================================== /* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SEARCH_DIR("/usr/i386-redhat-linux/lib"); \ SEARCH_DIR("/usr/local/lib"); \ SEARCH_DIR("/lib"); \ SEARCH_DIR("/usr/lib"); SECTIONS { ... ||< ** 静的リンクの舞台裏を確認してみる(gcc "-static"オプション) 静的リンクを行うにはgccの "-static" オプションを使う。 舞台裏を見てみると、"collect2"に"-static"オプションがわたっている。 #pre||> $ gcc -c -o foo.o foo.c $ gcc -v -static -o foo foo.o (...) /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 \ -m elf_i386 \ --hash-style=gnu \ -static \ -o foo \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbeginT.o \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. \ foo.o \ --start-group \ -lgcc \ -lgcc_eh \ -lc \ --end-group \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o ||< "--start-group", "--end-group"については"info ld"参照。 "-t"でトレースしてみる。表示量が大きいので、ファイルに落とす。 $ gcc -Wl,-t -static -o foo foo.o > list.txt list.txt: #pre||> /usr/bin/ld: mode elf_i386 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbeginT.o foo.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)libc-start.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)check_fds.o ... (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)dl-sym.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a)unwind-dw2.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a)unwind-dw2-fde-glibc.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a)unwind-c.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)stack_chk_fail_local.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)dl-iteratephdr.o (/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libc.a)stack_chk_fail.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o ||< libgcc_eh.aなど、gcc側のビルトインライブラリからもリンクされていることが分かる。 ** 動的リンクの舞台裏を確認してみる "-static"オプションを指定しなければ、デフォルトの動的リンクとなる。 "-dynamic-linker"オプションで実行時リンカを指定している。 #pre||> $ gcc -v -o foo foo.o (...) /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 \ --eh-frame-hdr \ -m elf_i386 \ --hash-style=gnu \ -dynamic-linker /lib/ld-linux.so.2 \ -o foo \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2 \ -L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. \ foo.o \ -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ -lc \ -lgcc \ --as-needed \ -lgcc_s \ --no-as-needed \ /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o \ /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o ||< "--as-needed", "--no-as-needed"については"info ld"参照。 "-t"でトレースしてみる。 #pre||> $ gcc -Wl,-t -o foo foo.o /usr/bin/ld: mode elf_i386 /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o foo.o -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /lib/libc.so.6 (/usr/lib/libc_nonshared.a)elf-init.oS /lib/ld-linux.so.2 -lgcc_s (/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so) /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o ||< ** gcc全体の振る舞い・デフォルト設定を調査・カスタマイズしたい gcc全体の振る舞いや、各ツールチェインに渡すデフォルトパラメータを調査・カスタマイズするには ''specs'' ファイルを調べます。 specsファイルとは、ドライバプログラムであるgccの振る舞いを決定するファイルです。Makefileに似た構造のテキストファイルで、アセンブルやリンクなど各タスクにおけるコマンドラインを定義していくことが出来ます。 gcc3以前はデフォルトのspecsがファイルとしてインストールされていたようですが、gcc4以降はプログラム内部に組み込まれたようで、デフォルトのspecsを取得するには "-dumpspecs" オプションを指定します。 $ gcc -dumpspecs > specs.default 考資料: - GCC 4.1.2 関連オンラインマニュアル -- http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Spec-Files.html - gcc 4: no specs file -- http://www.linuxquestions.org/questions/linux-from-scratch-13/gcc-4-no-specs-file-341034/ - 5.8. ツールチェーンの調整 -- http://lfsbookja.sourceforge.jp/6.7.ja/chapter05/adjusting.html - 猫科研究所(felid labo) - GCCのspecsとは -- http://up-cat.net/GCC%25A4%25CEspecs%25A4%25C8%25A4%25CF.html "-dumpspecs"でダンプしたspecsファイルをカスタマイズし、 "-specs" オプションで指定することにより、アセンブラ(as)やリンカ(ld)に渡すコマンドラインオプションをカスタマイズすることが出来ます。 実際にダンプしてみると分かりますが、デフォルトのspecsはそれなりの分量があります。 それら全てを手直しする必要はありません。変更したい箇所だけを修正し、それ以外は削除してしまって構いません。削除されたものについては、デフォルトのspecsが適用されます。 specsファイルの調整が必要になる例: - 技術/Linux/uClibc/03, x86(32bit) PC環境でuClibcを試す - Glamenv-Septzen.net -- http://www.glamenv-septzen.net/view/949 --- "gccに渡す "crtX.o" オプションを省略するには" の項を参照。 #navi_footer|C言語系|