home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

C言語系/memos/gcc/舞台裏を知りたいときのヒント集メモ

C言語系/memos/gcc/舞台裏を知りたいときのヒント集メモ

C言語系 / memos / gcc / 舞台裏を知りたいときのヒント集メモ
id: 843 所有者: msakamoto-sf    作成日: 2010-11-21 17:13:08
カテゴリ: 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

本サイト内の関連URL:

参考書籍:



gccの舞台裏を見たい

gccコマンドが隠蔽しているビルド過程を確認し、手動でGNUツールチェインを実行する際のヒント集。

"gcc -v"オプション

gccコマンドを"-v"オプション付きで実行すると、普段は隠されているビルド過程を出力させることが出来る。

$ 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"オプションと併用すると効果的。

$ 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-" オプション)

$ gcc -print-search-dirs
インストール: /usr/lib/gcc/i386-redhat-linux/4.1.2/
プログラム: =(省略)
ライブラリ: =(省略)

cppコマンドがインストールされている場合は、

$ cpp -print-search-dirs

でも同じ結果になる。

実行時に確認したい場合は、"-v"オプションを使うとよいだろう。

$ 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を追加してみる:

$ 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 <>"に追加してみる:

$ 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
$ 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()を確認する。

$ 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"オプションがわたっている。

$ 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:

/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"オプションで実行時リンカを指定している。

$ 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"でトレースしてみる。

$ 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

考資料:

"-dumpspecs"でダンプしたspecsファイルをカスタマイズし、 "-specs" オプションで指定することにより、アセンブラ(as)やリンカ(ld)に渡すコマンドラインオプションをカスタマイズすることが出来ます。
実際にダンプしてみると分かりますが、デフォルトのspecsはそれなりの分量があります。
それら全てを手直しする必要はありません。変更したい箇所だけを修正し、それ以外は削除してしまって構いません。削除されたものについては、デフォルトのspecsが適用されます。

specsファイルの調整が必要になる例:

  • 技術/Linux/uClibc/03, x86(32bit) PC環境でuClibcを試す - Glamenv-Septzen.net


プレーンテキスト形式でダウンロード
現在のバージョン : 2
更新者: msakamoto-sf
更新日: 2011-05-01 18:40:22
md5:b63cfabd7a8d58e15c89518160df8619
sha1:b4ec477cf2ce843e4834becfc41134b7ed3d5e09
コメント
コメントを投稿するにはログインして下さい。