リンカーとライブラリ

追加シンボルの定義

シンボルを入力ファイルから提供することに加えて、ユーザーは、リンク編集に、追加のシンボル参照または定義を指定できます。最も簡単な形式で、シンボル参照は、リンカーの -u オプションを使用して作成できます。より柔軟性の高いものは、リンカーの -M オプションと、それに関連した、シンボル参照と種々のシンボル定義を定義できる mapfile を使用して作成できます。

-u オプションを指定すると、リンク編集コマンド行からシンボル参照を作成するためのメカニズムが使用できます。このオプションは、リンク編集をすべてアーカイブから実行する場合に使用でき、また、複数のアーカイブから抽出するオブジェクトの選択における柔軟性を向上させることができます。アーカイブの抽出については、アーカイブ処理の項を参照してください。

たとえば、動的実行可能プログラムを、シンボル foobar への参照を実行する再配置可能オブジェクト main.o から生成するとします。この場合、lib1.a 内に組み込まれた再配置可能オブジェクト foo.o からシンボル定義 foo を入手し、さらに lib2.a 内に組み込まれた再配置可能オブジェクト bar.o からシンボル定義 bar を入手します。

ただし、アーカイブ lib1.aにも、シンボル bar を定義する再配置可能オブジェクトが組み込まれています。この再配置可能オブジェクトは、lib2.a に提供されたものとは機能的に異なると想定します。必要なアーカイブ抽出を指定する場合は、次のようなリンク編集を使用できます。


$ cc -o prog -L. -u foo -l1 main.o -l2

-u オプションは、シンボル foo への参照を生成します。この参照によって、再配置可能オブジェクト foo.o がアーカイブ lib1.a から抽出されます。シンボル bar への最初の参照は lib1.a が処理されてから生じる main.o 内で実行されます。このため、再配置可能オブジェクト bar.o はアーカイブ lib2.a から入手されます。


注 –

この単純な例では、lib1.a からの 再配置可能オブジェクト foo.o は、シンボル bar の直接的または間接的な参照は行いません。この参照を行なった場合、再配置可能オブジェクト bar.o は、その処理中に、 lib1.a から抽出されます。アーカイブを処理するリンカーの多重パスについては、アーカイブ処理 を参照してください。


より広範囲なシンボル定義のセットは、リンカーの -M オプションと関連する mapfile を使用して入手できます。これらの mapfile エントリの構文は次のとおりです。


[ name ] {
      scope:
            symbol [ = [ type ] [ value ] [ size ] [ extern ] ];
} [ dependency ];
name

このシンボル定義のセットのラベルは、もしあれば、イメージ内のバージョン定義を識別できます。第 5 章「アプリケーションバイナリインタフェースとバージョン管理」を参照してください。

scope

生成される出力ファイル内のシンボルのバインディングの可視性を示しています。mapfile で定義されたすべてのシンボルは、リンク編集プロセス中に、スコープ内で global (大域) として処理されます。つまり、これらのシンボルは、入力ファイルのいずれかから入手された、同じ名前の他のシンボルに対して解決されます。以下の定義と別名は、作成されるオブジェクト内におけるシンボルの可視性を定義します。

default / global

このスコープのシンボルは、ほかの外部オブジェクトから見えます。このタイプのシンボルに対するオブジェクト内からの参照は実行時に結合されるため、介入が可能となります。

protected / symbolic

このスコープのシンボルは、ほかの外部オブジェクトから見えます。これらのシンボルに対するオブジェクト内からの参照はリンク編集時に結合されるため、実行時の介入は防止されます。このスコープ定義には、シンボルに STV_PROTECTED 可視性が指定された場合と同じ効果があります。表 7–24を参照してください。

hidden / local

このスコープのシンボルは、ローカル結合されるシンボルに縮小されます。このスコープのシンボルは、ほかの外部オブジェクトから見えません。このスコープ定義には、シンボルに STV_HIDDEN 可視性が指定された場合と同じ効果があります。表 7–24を参照してください。

eliminate

このスコープのシンボルは hidden です。これらのシンボルテーブルのエントリは削除されます。

symbol

要求されたシンボルの名前です。この名前の後にシンボル属性 type valuesize、または extern のいずれかがついていない場合、シンボル参照が作成されます。この参照は、この項の最初に説明した -u オプションを使用して生成する参照とまったく同じものです。このシンボル名にシンボル属性が付いている場合には、シンボル定義は、関連する属性を使用して生成されます。

local スコープ内では、このシンボル名は、特別な「auto-reduction」(自動縮小) 指示語「*」として定義できます。この指示語を使用すると、すべての大域シンボル (mapfile 内に global と明示的に定義されていないもの) は、生成される動的オブジェクトファイル内でローカル結合されます。

type

シンボルのタイプ属性を示します。この属性は、datafunction、または COMMON のいずれかです。最初の 2 つのタイプ属性の結果は、絶対的なシンボル定義になります 。シンボルテーブルセクションを参照してください。 後者のタイプ属性の結果は、一時的シンボル定義になります。

value

シンボルの値属性を示し、Vnumber の書式です。

size

シンボルのサイズ属性を示し、Vnumber の書式です。

extern

シンボルが、作成されているオブジェクトに外部的に定義されていることを示します。このオプションを使用して、-z defs オプションで示された未定義シンボルを抑制できます。

dependency

この定義が継承する version definition (バージョン定義) を示します。第 5 章「アプリケーションバイナリインタフェースとバージョン管理」を参照してください。

バージョン定義または自動縮小のいずれかの指示語が指定されている場合、バージョン情報が作成されるイメージ内に記録されます。このイメージが実行可能プログラムまたは共有オブジェクトである場合には、シンボル縮小も適用されます。

作成されるイメージが再配置可能オブジェクトである場合は、デフォルトにより、シンボル縮小は適用されません。この場合、シンボル縮小はバージョン情報の一部として記録されます。これらの縮小は、再配置可能オブジェクトが最終的に実行可能ファイルまたは共有オブジェクトの生成に使用されるときに適用されます。リンカーの -B reduce オプションを使用すると、再配置可能オブジェクトを生成するときに、強制的にシンボル縮小を実行できます。

バージョン情報の詳細については、第 5 章「アプリケーションバイナリインタフェースとバージョン管理」に記載してあります。


注 –

インタフェース定義を確実に安定させるためには、シンボル名の定義に対しワイルドカードによる拡張を行わないようにします。


この項では、この mapfile 構文を使用した例をいくつか示します。

次の例では、3 つのシンボル参照を定義する方法を示します。これらの参照を使用して、アーカイブの構成要素を抽出します。このアーカイブ抽出は、複数の -u オプションをリンク編集に指定することにより実現できますが、この例では、最終的なシンボルの範囲を、ローカルに縮小する方法も示しています。


$ cat foo.c
foo()
{
        (void) printf("foo: called from lib.a\n");
}
$ cat bar.c
bar()
{
        (void) printf("bar: called from lib.a\n");
}
$ cat main.c
extern  void    foo(), bar();

main()
{
        foo();
        bar();
}
$ ar -rc lib.a foo.o bar.o main.o
$ cat mapfile
{
        local:
                foo;
                bar;
        global:
                main;
};
$ cc -o prog -M mapfile lib.a
$ prog
foo: called from lib.a
bar: called from lib.a
$ nm -x prog | egrep "main$|foo$|bar$"
[28]    |0x00010604|0x00000024|FUNC |LOCL |0x0  |7      |foo
[30]    |0x00010628|0x00000024|FUNC |LOCL |0x0  |7      |bar
[49]    |0x0001064c|0x00000024|FUNC |GLOB |0x0  |7      |main

大域からローカルへのシンボル範囲の縮小の重要性については、シンボル範囲の縮小で説明しています。

次の例では、2 つの絶対シンボル定義を定義する方法を示します。そして、これらの定義を使用して、入力ファイル main.c からの参照を解決します。


$ cat main.c
extern  int     foo();
extern  int     bar;

main()
{
        (void) printf("&foo = %x\n", &foo);
        (void) printf("&bar = %x\n", &bar);
}
$ cat mapfile
{
        global:
                foo = FUNCTION V0x400;
                bar = DATA V0x800;
};
$ cc -o prog -M mapfile main.c
$ prog
&foo = 400 &bar = 800
$ nm -x prog | egrep "foo$|bar$"
[37]    |0x00000800|0x00000000|OBJT |GLOB |0x0  |ABS    |bar
[42]    |0x00000400|0x00000000|FUNC |GLOB |0x0  |ABS    |foo

入力ファイルから入手される場合、関数のシンボル定義またはデータ項目は、通常、データ記憶域の要素に関連しています。mapfile 定義は、このデータ記憶域を構成するためには不十分であるため、これらのシンボルは、絶対値として残しておく必要があります。

ただし、mapfile は、COMMON または一時的シンボルを定義する場合にも使用できます。他のタイプのシンボル定義とは違って、一時的シンボルは、ファイル内の記憶域を占有しませんが、実行時に割り当てる記憶域の定義は行います。そのため、このタイプのシンボル定義は、作成される出力ファイルの記憶域割り当ての一因となります。

一時的シンボルの特徴は、他のシンボルタイプとは異なり、その値の属性によって、その配列条件が示される点です。そのため、リンク編集の入力ファイルから入手される一時的定義の再配列に mapfile 定義を使用できます。

次の例では、2 つの一時的シンボルの定義を示しています。シンボル foo は、新しい記憶領域を定義しているのに対し、シンボル bar は、実際に、ファイル main.c 内の同じ一時的定義の配列を変更するために使用されます。


$ cat main.c
extern  int     foo;
int             bar[0x10];

main()
{
        (void) printf("&foo = %x\n", &foo);
        (void) printf("&bar = %x\n", &bar);
}
$ cat mapfile
{
        global:
                foo = COMMON V0x4 S0x200;
                bar = COMMON V0x100 S0x40;
};
$ cc -o prog -M mapfile main.c
ld: warning: symbol `bar' has differing alignments:
        (file mapfile value=0x100; file main.o value=0x4);
        largest value applied
$ prog
&foo = 20940
&bar = 20900
$ nm -x prog | egrep "foo$|bar$"
[37]    |0x00020900|0x00000040|OBJT |GLOB |0x0  |16     |bar
[42]    |0x00020940|0x00000200|OBJT |GLOB |0x0  |16     |foo

注 –

このシンボル解決の診断は、リンカーの -t オプションを使用すると表示されません。