リンカーとライブラリ

デフォルトのシンボル検索モデル

dlopen(3DL) によって追加された各オブジェクトでは、実行時リンカーは、最初に動的実行プログラム内でシンボルを検索し、次に、プロセスの初期設定中に提供されたそれぞれのオブジェクト内を検索します。ただし、シンボルが検出されない場合には、実行時リンカーは、dlopen(3DL) によって入手されたオブジェクト内と、その依存関係内の検索を続行します。

たとえば、動的実行プログラム prog と共有オブジェクト B.so.1 を入手してみます。この 2 つには、それぞれ以下の単純な依存関係が付いています。


$ ldd prog
        A.so.1 =>        ./A.so.1
$ ldd B.so.1
        C.so.1 =>        ./C.so.1

prog が、dlopen(3DL) を使用して共有オブジェクト B.so.1 を入手した場合、共有オブジェクト B.so.1C.so.1 の再配置に必要なシンボルが、最初に prog 内で検索され、A.so.1B.so.1C.so.1 の順番に検索されます。このような単純なケースでは、dlopen(3DL) によって入手された共有オブジェクトは、アプリケーションの元のリンク編集の末尾に追加されたと考える方が簡単な場合があります。たとえば、上記のオブジェクトの参照を図示すると、次のようになります。

図 3-1 単一の dlopen() 要求

Graphic

dlopen(3DL) から入手されたオブジェクトによって要求されたシンボル検索は、影付きのブロックで示しています。このシンボル検索は、動的実行プログラム prog から、最後の共有オブジェクト C.so.1 へと進みます。

このシンボル検索は、読み込まれたオブジェクトに割り当てられた属性によって確立されます。動的実行プログラムとそれと同時に読み込まれたすべての依存関係には、大域シンボル可視性が割り当てられ、新しいオブジェクトにはワールドシンボルの検索範囲が割り当てられることを思い出してください。これによって、新しいオブジェクトは元のオブジェクト内を調べてシンボルを検索できます。また、新しいオブジェクトは、固有のグループを形成し、このグループ内では、各オブジェクトは局所シンボル可視性を持ちます。そのため、グループ内の各オブジェクトは、他のグループ構成要素内でシンボルを検索できます。

これらの新しいオブジェクトは、アプリケーションまたはその最初のオブジェクトの依存関係によって要求される、通常のシンボル検索には影響を与えません。たとえば、上記の dlopen(3DL) が実行されたあとで、A.so.1 に関数再配置が必要な場合、実行時リンカーの再配置シンボルの通常の検索は、progA.so.1 で実施されますが、そのあとで B.so.1 または C.so.1 は検索されません。

このシンボル検索は、読み込まれたときにオブジェクトに割り当てられた属性によって実行されます。動的実行プログラムとこれとともに読み込まれた依存関係に割り当てられたワールドシンボルの検索範囲では、局所シンボル可視性だけを提供する新しいオブジェクト内を検索できません。

これらのシンボル検索とシンボル可視性の属性は、そのプロセスのアドレススペースへの投入とオブジェクト間の依存の関係に基づいて、オブジェクト間の関係を保持します。指定された dlopen(3DL) に関連したオブジェクトを割り当てることにより、固有のグループでは、同じ dlopen(3DL) と関連したオブジェクトだけが、グループ内のオブジェクトと関連する依存関係の中の検索ができます。

このオブジェクト間の関係を定義するという概念は、複数の dlopen(3DL) を実行するアプリケーション内では、より明確になります。たとえば、共有オブジェクト D.so.1 に次の依存関係があるとします。


$ ldd D.so.1
        E.so.1 =>         ./E.so.1

このとき prog アプリケーションが、共有オブジェクト B.so.1 に加えて、この共有オブジェクトにも dlopen(3DL) を実行した場合は、オブジェクト間のシンボル検索の関係は、図 3-2 のように表すことができます。

図 3-2 複数の dlopen() 要求

Graphic

B.so.1D.so.1 の両方にシンボル foo の定義が組み込まれ、C.so.1E.so.1 にこのシンボルが必要とする再配置が組み込まれている場合、固有のグループに対するオブジェクトの関係によって、C.so.1B.so.1 の定義に結合され、E.so.1D.so.1 の定義に結合されます。このメカニズムは、dlopen(3DL) への複数の呼び出しにより入手されたオブジェクトの最も直感的な結合を提供するためのものです。

オブジェクトが、前述した処理の進行の中で使用される場合、それぞれの dlopen(3DL) が実施された順番は、結果として発生するシンボル結合には影響しません。ただし、複数のオブジェクトに共通の依存関係がある場合は、結果の結び付きは、dlopen(3DL) 呼び出しが実行された順番による影響を受けます。

次に、同じ共通依存関係を持つ共有オブジェクト O.so.1P.so.1 の例を示します。


$ ldd O.so.1 
        Z.so.1 =>        ./Z.so.1
$ ldd P.so.1 
        Z.so.1 =>        ./Z.so.1

この例では、prog アプリケーションは、各共有オブジェクトに dlopen(3DL) を使用しています。共有オブジェクト Z.so.1 が、O.so.1P.so.1 両方の共通依存関係であるため、この依存関係は 2 つの dlopen(3DL) 呼び出しに関連する両方のグループに割り当てられます。

図 3-3 共通依存関係を伴う複数の dlopen() 要求

Graphic

この結果、O.so.1P.so.1 の両方がシンボルの検索に Z.so.1 を使用できます。ここで重要なのは、dlopen(3DL) の順序に限って言えば、Z.so.1O.so.1P.so.1 の両方の中でシンボルを検索できることです。

そのため、O.so.1P.so.1 の両方に、Z.so.1 の再配置に必要なシンボル foo の定義が組み込まれている場合、実際に発生する結び付きを予期することはできません。それは、この結び付きが dlopen(3DL) 呼び出しの順序の影響を受けるからです。シンボル foo の機能が、シンボルが定義されている 2 つの共有オブジェクト間で異なる場合、Z.so.1 コードを実行したすべての結果は、アプリケーションの dlopen(3DL) の順序によって異なる可能性があります。