複雑な解析
複雑な解析は、同じ名前を持つ 2 つのシンボルが、異なる属性とともに検出された場合に発生します。この場合、リンカーは最も適切なシンボルを選択し、そのシンボル、対立する属性、およびそのシンボル定義を取り出したファイルの ID を示す警告メッセージを生成します。次の例では、データ項目の配列の定義が指定された 2 つのファイルで、サイズの必要条件が異なっています。
$ cat foo.c
int array[1];
$ cat bar.c
int array[2] = { 1, 2 };
$ cc -dn -r -o temp.o foo.c bar.c
ld: warning: symbol `array' has differing sizes:
(file foo.o value=0x4; file bar.o value=0x8);
bar.o definition taken
|
シンボルの整列必要条件が異なる場合には、同様の診断プログラムが作成されます。この 2 つのケースの場合、リンカーの -t オプションを使用すると、診断プログラムを抑制できます。
この他の属性形式の違いに、シンボルのタイプがあります。次の例では、シンボル bar()は、データ項目と関数の両方として定義されています。
$ cat foo.c
bar()
{
return (0);
}
$ cc -o libfoo.so -G -K pic foo.c
$ cat main.c
int bar = 1;
main()
{
return (bar);
}
$ cc -o main main.c -L. -lfoo
ld: warning: symbol `bar' has differing types:
(file main.o type=OBJT; file ./libfoo.so type=FUNC);
main.o definition taken
|
注 - この文脈では、シンボルのタイプは ELF で使用されるタイプです。このシンボルタイプは、単純な形式であることを除けば、プログラミング言語で使用されるデータ型には関連していません。
前述の例のような場合には、再配置可能オブジェクトと共有オブジェクト間で解析が発生したときには、再配置可能オブジェクトの定義がとられます。または、2 つの共有オブジェクト間で解析が発生した場合には、最初の共有オブジェクトの定義がとられます。このような解析が異なる結合間 (ウィークまたは大域) で発生すると、警告メッセージも同時に作成されます。
リンカーの -t オプションを使用しても、シンボルタイプ間の不一致は抑制できません。
重大な解析
解析できないシンボルの重複によって、重大なエラー状態が発生します。この場合、シンボルを入手したファイルの名前と同時に、そのシンボル名を指摘した適切なエラーメッセージが表示されて、出力ファイルは生成されません。この重大なエラー状態によってリンカーは停止しますが、すべての入力ファイルの処理が、まず最初に完了します。この要領で、重大な解析エラーをすべて識別できます。
最も一般的な、重大エラー状態は、2 つの再配置可能オブジェクトが両方とも同じ名前のシンボルを定義していて、どちらのシンボルもウィーク定義ではない場合に発生します。
$ cat foo.c
int bar = 1;
$ cat bar.c
bar()
{
return (0);
}
$ cc -dn -r -o temp.o foo.c bar.c
ld: fatal: symbol `bar' is multiply-defined:
(file foo.o and file bar.o);
ld: fatal: File processing errors. No output written to int.o
|
foo.c と bar.c には、シンボル bar に対する重複する定義があります。リンカーは、どちらを優先すべきか判別できないため、通常はエラーメッセージを出力して終了します。リンカーの -z muldefs オプションを使用すると、このエラー状態を防ぐことができ、リンカーが、最初のシンボル定義を優先するように設定できます。
未定義シンボル
すべての入力ファイルを読み取り、シンボル解析がすべて完了すると、リンカーは、シンボル定義に結合されていないシンボル参照の内部シンボルテーブルを検索します。これらのシンボル参照は、未定義シンボルと呼ばれます。これらの未定義シンボルがリンク編集処理に及ぼす影響は、生成される出力ファイルのタイプや、場合によってはシンボルのタイプによって異なります。
実行可能ファイルの作成
リンカーが実行可能ファイルを作成しているときは、リンカーのデフォルトの動作は、シンボルを定義されないままにする必要がある適切なエラーメッセージを表示してリンク編集を終了させることです。次のように、再配置可能オブジェクト内のシンボル参照が、シンボル定義と絶対に一致しない場合に、シンボルは定義されないままの状態になります。
$ cat main.c
extern int foo();
main()
{
return (foo());
}
$ cc -o prog main.c
Undefined first referenced
symbol in file
foo main.o
ld: fatal: Symbol referencing errors. No output written to prog
|
これと同様の方法で、共有オブジェクトが動的実行可能プログラムを作成するために使用されているときに、共有オブジェクト内のシンボル参照が、シンボル定義と絶対に一致しない場合は、このシンボル参照も未定義シンボルになります。
$ cat foo.c
extern int bar;
foo()
{
return (bar);
}
$ cc -o libfoo.so -G -K pic foo.c
$ cc -o prog main.c -L. -lfoo
Undefined first referenced
symbol in file
bar ./libfoo.so
ld: fatal: Symbol referencing errors. No output written to prog
|
上記の例のような場合に、未定義シンボルを許可するには、リンカーの -z nodefs オプションを使用することにより、重大なエラー状態を防ぐことができます。
注 - -z nodefs オプションを使用する場合は、注意が必要です。処理の実行中に使用できないシンボル参照が要求されると、重大な実行時再配置エラーが発生します。このエラーは、アプリケーションを最初に実行してテストする際に検出できる可能性があります。しかし、実行パスがより複雑であるとエラー状態の検出に時間がかかり、時間とコストが浪費される場合があります。
シンボルは、再配置可能オブジェクト内のシンボル参照が、暗黙の内に定義された共有オブジェクト内のシンボル定義に結合されている場合にも、未定義シンボルのままになる場合があります。たとえば、上記の例で使用したファイル main.c および foo.c に以下のように続く場合です。
$ cat bar.c
int bar = 1;
$ cc -o libbar.so -R. -G -K pic bar.c -L. -lfoo
$ ldd libbar.so
libfoo.so => ./libfoo.so
$ cc -o prog main.c -L. -lbar
Undefined first referenced
symbol in file
foo main.o (symbol belongs to implicit \
dependency ./libfoo.so)
ld: fatal: Symbol referencing errors. No output written to prog
|
prog は、libbar.so への「明示的な」参照を使用して構築されます。また、libbar.so には libfoo.so への依存性があるため、prog から libfoo.so への暗黙的な参照が確立します。
main.c は、libfoo.so によって作成されたインタフェースへの特定の参照を実行するため、prog は、実際に libfoo.so に依存性を持つことになります。ただし、生成される出力ファイル内に記録されるのは、明示的な共有オブジェクトの依存関係だけです。そのため、libbar.so の新しいバージョンが開発され、libfoo.so への依存性がなくなった場合、prog は実行に失敗します。
この理由から、このタイプのバインディングは重大であると考えられ、暗黙的な参照は、prog のリンク編集中にライブラリを直接参照することにより、明示的に実行される必要があります。この例で示した重大なエラーメッセージ内に必要な参照のヒントがあります。



