動的オブジェクトは、実行時の初期設定と終了処理のためのコードを提供することができます。動的オブジェクトの初期設定コードは、処理中に動的オブジェクトが読み込まれるたびに、1 回ずつ実行されます。動的オブジェクトの終了コードは、動的オブジェクトが処理から読み取り解除されるか、または処理の終了のたびに 1 回ずつ実行されます。このコードは、関数ポインタの配列、または単一コードブロックのうちいずれか 1 つのセクションタイプで組み込まれます。どちらのセクションタイプも、入力再配置可能オブジェクトの同類のセクションを連結して構築されます。
セクション .preinitarray、.initarray、および .finiarray はそれぞれ、実行時の「初期設定前」、初期設定、および終了関数の配列を提供します。動的オブジェクトを作成する際、リンカーはこれらの配列を .dynamic タグペアである DT_PREINIT_[ARRAY/ARRAYSZ]、DT_INIT_[ARRAY/ARRAYSZ]、および DT_FINI_[ARRAY/ARRAYSZ] でそれぞれ識別します。これらのタグは関連するセクションを識別して、セクションを実行時リンカーによって呼び出されるようにします。「初期設定前」の配列は、動的実行可能ファイルにのみ適用可能です。
これらの配列に割り当てられる関数は、作成されるオブジェクトから提供する必要があります。
.init と .fini セクションは、それぞれ実行時の初期設定と終了時のコードブロックを提供します。通常コンパイラドライバは、入力ファイルリストの冒頭部分と末尾に付加するファイルを使用して .init と .fini セクションを供給します。コンパイラが提供するこれらのファイルには、再配置可能オブジェクトの .init コードと .fini コードをそれぞれ独立した関数内にカプセル化する効果があります。これらの関数は、予約シンボル名 _init と _fini によりそれぞれ識別されます。動的オブジェクトを作成する際、リンカーはこれらのシンボルを .dynamic タグの DT_INIT と DT_FINI でそれぞれ識別します。これらのタグは関連するセクションを識別して、実行時リンカーによって呼び出されるようにします。
初期設定および終了コードの実行時の詳細は、「初期設定および終了ルーチン」を参照してください。
初期設定と終了関数の登録をリンカーから直接実行するには、-z initarray オプションと -z finiarray オプションを使用します。たとえば、次のコマンドの結果、関数 foo() のアドレスが .initarray 要素に配置され、関数 bar() のアドレスが .finiarray 要素に配置されます。
$ cat main.c #include <stdio.h> void foo() { (void) printf("initializing: foo()\n"); } void bar() { (void) printf("finalizing: bar()\n"); } void main() { (void) printf("main()\n"); } $ cc -o main -zinitarray=foo -zfiniarray=bar main.c $ main initializing: foo() main() finalizing: bar() |
初期設定および終了セクションの作成は、アセンブラを使用して直接実行できます。しかし、ほとんどのコンパイラは、その宣言を単純化するための特別なプリミティブを提供しています。たとえば、上記のコード例は、次に示す #pragma 定義を使用して書き直すことができます。これらの定義の結果、foo() に対する呼び出しが .init セクション内に配置され、bar() に対する呼び出しが .fini セクション内に配置されます。
$ cat main.c #include <stdio.h> #pragma init (foo) #pragma fini (bar) ....... $ cc -o main main.c $ main initializing: foo() main() finalizing: bar() |
初期設定コードと終了コードが複数の再配置可能オブジェクトに分散されると、アーカイブライブラリと共有オブジェクトに組み込まれた場合とで、異なる動作をする可能性があります。アーカイブを使用したアプリケーションのリンク編集は、アーカイブ内の一部オブジェクトしか抽出しない可能性があります。これらのオブジェクトは、アーカイブのメンバー全体に分散されている初期設定と終了コードの一部しか提供しない可能性があります。そして実行時に、コードのこの部分だけが実行されます。同じアプリケーションを共有オブジェクトを使用して構築した場合は、実行時に依存先が読み込まれると、累積された初期設定コードと終了コードのすべてが実行されます。
実行時にプロセス内で初期設定および終了コードをどのような順序で実行すべきかを判断することは、依存関係の分析を伴う複雑な問題を含んでいます。この分析を簡単にするには、初期設定および終了コードの内容を制限します。自己完結型の初期設定および終了コードを単純化すると、実行時の動作が予想可能になります。詳細については、「初期設定と終了の順序」を参照してください。
初期設定コードが、dldump(3C) を使ってメモリーをダンプできる動的オブジェクトとともに組み込まれている場合、データの初期設定だけを別個に行なってください。