リンカーとライブラリ

初期設定および終了セクション

動的オブジェクトは、実行時の初期設定と終了プロセスのためのコードを提供することができます。このコードは、関数ポインタの配列、または単一コードブロックのうちいずれか 1 つの方法で使用されます。これらの各セクションタイプは、入力再配置可能オブジェクトの同類のセクションの連結から構築されます。

.preinit_array.init_array、および .fini_array セクションは、それぞれ実行時の初期設定前、初期設定、および終了関数の配列を提供します。動的オブジェクトを作成する際、実行時リンカーによって呼び出されるように、リンカーはこれらの配列を .dynamic タグの DT_PREINIT_ARRAYDT_PREINIT_ARRAYSZDT_INIT_ARRAYDT_INIT_ARRAYSZDT_FINI_ARRAYDT_FINI_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");
}

main()
{
     (void) printf("main()¥n");
     return (0);
}

$ cc -o main -zinitarray=foo -zfiniarray=bar main.c
$ main
initializing: foo()
main()
finalizing: bar()

初期設定および終了セクションの作成は、アセンブラを使用して直接実行できます。あるいは、コンパイラの中にはその宣言を単純化するための特別なプリミティブを提供しているものもあります。たとえば、次の #pragmas を含んだ同じ例の結果、関数 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(3DL) を使用してメモリーをダンプできる動的オブジェクトとともに組み込まれている場合は、データの初期設定は独立させることをお勧めします。