Oracle® Solaris 11.2 リンカーとライブラリガイド

印刷ビューの終了

更新: 2014 年 7 月
 
 

同じ名前の多重定義シンボルの削除

同じ名前の多重定義シンボルは、シンボルに関連付けられた実装が状態を保持していると、直接結合された環境内で問題となる可能性があります。典型的にはデータシンボルが違反していますが、状態を保持する関数も問題になる場合があります。

直接結合された環境では、同じシンボルの複数のインスタンスに結合できます。このため、もともとプロセス内ではインスタンスが 1 つであることを意図していた別々の状態変数を、結合している別々のインスタンスが操作できます。

たとえば、2 つの共有オブジェクトが同じデータ項目 errval を含むものとします。また、2 つの関数 action()inspect() が別々の共有オブジェクトに存在するものとします。これらの関数は、値 errval をそれぞれ読み書きします。

デフォルトの検索モデルの場合、errval の 1 つの定義がその他の定義に割り込みます。action()inspect() の両方の関数は、errval の同じインスタンスに結合されます。このため、action() によって errval にエラーコードが書き込まれた場合、inspect() がこのコードを読み込んで、このエラー条件に従って動作します。

しかし、action() および inspect() を含むオブジェクトが、errval をそれぞれで定義した別々の依存関係に結合されたものと仮定します。直接結合された環境では、これらの関数は errval の別々の定義に結合されます。エラーコードは action() によって errval の 1 つのインスタンスに書き込まれ、その一方で inspect()errval のもう一方の初期化されていない定義を読み込みます。その結果、inspect() では、処理対象となるエラー条件を検出しません。

一般的に、データシンボルの複数のインスタンスは、シンボルがヘッダーで宣言された場合に発生します。

int bar;

このデータ宣言では、ヘッダーを含むコンパイル単位ごとに、データ項目が作成されることになります。その結果生じる一時的なデータ項目によって、シンボルの複数のインスタンスが別々の動的オブジェクトに定義される場合があります。

しかし、データ項目を明示的に外部として定義することで、データ項目への参照は、ヘッダーを含むコンパイル単位ごとに作成されます。

extern int bar;

その結果、これらの参照を実行時に 1 つのデータインスタンスに解決できます。

シンボル実装を削除するときに、そのインタフェースの保持が必要な場合があります。同じインタフェースの複数のインスタンスは、既存のすべてのインタフェースを保持しながら、1 つの実装にすることができます。このモデルは、FILTER mapfile キーワードを使用して個々のシンボルフィルタを作成することで実現できます。このキーワードは、SYMBOL_SCOPE/SYMBOL_VERSION 指令で説明されています。

個々のシンボルフィルタを作成することが有効なのは、シンボルの実装が削除されたオブジェクト内で、依存関係がそのシンボルの検出を期待している場合です。

たとえば、関数 error()A.so.1B.so.1 の 2 つの共有オブジェクトに存在するものとします。シンボルの重複を削除するには、A.so.1 から実装を削除する必要があります。しかし、別の依存関係が A.so.1 から得られる error() に依存しています。次の例は、A.so.1 での error() の定義を示しています。mapfile を使用すると、B.so.1 に指定されたこのシンボルのフィルタを残したまま、error() の実装を削除できます。

$ cc -o A.so.1 -G -Kpic error.c a.c b.c ....
$ elfdump -sN.dynsym A.so.1 | fgrep error
     [3]     0x300    0x14  FUNC GLOB  D    0 .text      error
$ cat mapfile
$mapfile_version 2
SYMBOL_SCOPE {
        global:
                error { TYPE=FUNCTION; FILTER=B.so.1 };
};
$ cc -o A.so.2 -G -Kpic -M mapfile a.c b.c ....
$ elfdump -sN.dynsym A.so.2 | fgrep error
     [3]         0       0  FUNC GLOB  D    0 ABS        error
$ elfdump -y A.so.2 | fgrep error
     [3]  F       [0] B.so.1         error

関数 error() は大域であり、A.so.2 のエクスポートされたインタフェースのままです。しかし、このシンボルへの実行時結合はフィルティー B.so.1 になります。文字「F」はこのシンボルのフィルタ特性を表しています。

既存のインタフェースを保持したまま 1 つの実装にするこのモデルは、複数の Oracle Solaris ライブラリで使用されています。たとえば、以前に libc.so.1 に定義された多くの数値演算インタフェースは、現在は libm.so.2 の推奨される関数実装を指しています。