[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
ある種の言語では、コンパイルされたコードには コンストラクタ
が含まれる。コンストラクタは、初期化ルーチンとも呼ばれることもあり、
プログラムの起動時にそのプログラムのデータを初期化する関数である。
この関数は、プログラムが「開始」するまえに呼ばれる必要がある。
つまり、main
の前に呼ばれる必要がある。
いくつかの言語では、コンパイルを行なうと、 終了ルーチンとも呼ばれる デストラクタを生成する。 デストラクタは、プログラムが終了するときに呼び出されなくてはならない。
初期化と終了関数を動作させるためには、コンパイラがアセンブラコードに 何らかの出力を行なって、これらの関数が適切な時期に呼び出されるように しなければならない。
GCC 現在サポートしている、初期化関数と終了関数の実行方法には 大きく分けて二つの方法がある。 どちらの方法も、それぞれさらに二種類に分けられる。 構成方法のほとんどは、この4つの方法全部に共通している。
リンカは、これらの関数のリストを二つ構築しなければならない。
一つは、初期化関数のリストであり、__CTOR_LIST__
と呼ばれる。
もう一つは、終了関数のリストであり、__DTOR_LIST__
と呼ばれる。
どちらのリストも無視される関数ポインタが先頭に置かれる。 (この関数ポインタには、環境によって、0、1、あるいは後ろに置かれる関数 ポインタの数のどれかの値が置かれる。) この後に、0個以上のコンストラクタ(あるいはデストラクタ)への関数ポインタ の並びが続く。最後に、値が 0 の関数ポインタが置かれる。
オペレーティング・システムや実行形式ファイル形式に依存して、 ‘crtstuff.c’ か ‘libgcc2.c’ のどちらかが、起動時と終了時に これらのリストを走査する。 コンストラクタは、リスト中の順番とは逆の順序で呼び出される。 デストラクタは、リストの順番で呼び出される。
静的なコンストラクタを扱う最適な方法は、セクションに任意の名前を付ける ことができるオブジェクトファイル形式でしか使えない。 あるセクションがコンストラクタのリストのために取られる。 そして、もう一つ別のセクションがデストラクタのために取られる。 伝統的に、この二つのセクションは、‘.ctors’ と ‘.dtors’ と 呼ばれる。初期化関数を定義しているオブジェクトファイルは、 その関数を指すワードをコンストラクタセクションに置く。 リンカがこれらのワードをまとめ上げ、一つの連続した ‘.ctors’ セクション を作る。終了関数も同様に扱われる。
この方法を使うには、マクロ ASM_OUTPUT_CONSTRUCTOR
と
ASM_OUTPUT_DESTRUCTOR
に適切な定義を与える必要がある。
それには、普通は ‘svr4.h’ をインクルードすれば良い。
任意のセクションを使えるなら、さらに ‘crtstuff.c’ 中の
コードの呼ばれ方により、二つの変種がある。
プログラムの起動時に実行される 初期化 セクションをサポートしている
システムでは、‘crtstuff.c’ の中身がコンパイルされて、
そのセクションの中に入る。
プログラムは、gcc
ドライバにより以下のようにリンクされる。
ld -o output_file crtbegin.o … crtend.o -lgcc |
ある関数(__do_global_ctors
) の先頭が、
‘crtbegin.o’ の初期化セクションに現れる。
この関数の残りの部分は ‘crtend.o’ の初期化セクションに現れる。
リンカは、初期化セクションのこの二つの部分を合わせて、関数全体を
作る。この中間にリンクされるユーザのオブジェクトファイルが
どれもコードに寄与するなら、そのコードは __do_global_ctors
の
本体の一部として実行される。
この方法を使うには、マクロ INIT_SECTION_ASM_OP
を適切に
定義しなくてはならない。
初期化セクションが使えないときは、INIT_SECTION_ASM_OP
は
定義しないこと。
そうすると、__do_global_ctors
は他の全ての関数と同様、
テキストセクションの中に作られ、‘libgcc.a’ に置かれる。
GCC が main
という名前の関数をコンパイルするときは、
その関数のプロローグコードの直後の最初の実行可能なコードとして、
__main
を呼び出す手続きを挿入する。
関数 __main
は、‘libgcc2.c’ で定義されており、
単に ‘__do_global_ctors’ を呼び出す。
ファイル形式が任意個数のセクションをサポートしていない場合は、
また二つの変種がある。一番簡単な方法の場合は、GNU リンカ(GNU ld
)
と a.out 形式を使わなければならない。
この場合、ASM_OUTPUT_CONSTRUCTOR
を定義して、
‘N_SETT’ 型の .stabs
エントリを一個作るようにする。
この ‘N_SETT’ 型のエントリは、__CTOR_LIST__
という名前を
参照しており、初期化コードを含む void 型の関数のアドレスを、その
値として持っている。
GNU リンカはこれを、その値をある「集合」に追加する要求として
認識する。この値は累積され、最終的には上記の形式のベクトルとして
実行形式ファイルに置かれる。
このベクトルの前には個数(無視される)が置かれ、ベクトルの最後の要素は
ゼロとなる。
ASM_OUTPUT_DESTRUCTOR
も同様に扱われる。
初期化セクションが使えないので、INIT_SECTION_ASM_OP
が
ないと、main
は上記のように __main
を呼び出すように
コンパイルされ、初期化処理を開始する。
最後の変種では、任意個数のセクションも GNU リンカも使わない。
ダイナミックリンクを行ないたい場合と ECOFF のように、GNU リンカがサポート
していないファイル形式を使うときには、これが好ましい方法である。
この場合、ASM_OUTPUT_CONSTRUCTOR
は N_SETT
を
作り出さない。初期化関数と終了関数は単にその名前により認識される。
このため、リンクの段階で、collect2
という余分のプログラムを
必要とする。このプログラムは、GNU CC と合わせて使うときは、リンカ
のふりをする。
collect2
は、通常のリンカを実行させることで自分の仕事を
行なう。ただし、初期化関数と終了関数のベクトルを含むよう調整も
行なう。
これらの関数は上記のように __main
を経由して呼び出される。
これらのコンフィギュレーションの選択肢から選び出す作業は、 オペレーティングシステム依存のファイルを ‘config’ サブディレクトリに 置くことで簡素化される。 ここに置くファイルで関係するパラメータを全て定義する。 普通は、そのうちの一個のファイルを読者の固有の 機種依存のコンフィギュレーションファイルに含めれば充分である。 オペレーティング依存のファイルには以下のものがある。
`a.out' 形式を使用するオペレーティングシステム向けのファイル。
`MachO' 形式を使用するオペレーティングシステム向けのファイル。
System V Release 3、それに `COFF' 形式を使用する類似のシステム向けのファイル。
System V Release 4、それに `ELF 形式を使用する類似のシステム向けのファイル。
VMS システム向けのファイル。
This document was generated
using texi2html 1.78.