Go to main content
Oracle® Solaris 11.3 リンカーとライブラリガイド

印刷ビューの終了

更新: 2015 年 10 月
 
 

シンボル機能関数ファミリの作成

開発者は、関数の複数のインスタンス (それぞれは特定の機能セット向けに最適化) を 1 つのオブジェクト内に用意したいと考えることがよくあります。インスタンスの選択と使用が消費者に対して透過的であることが望まれます。外部インタフェースとして、汎用的なフロントエンドの関数を作成できます。この汎用インスタンスと最適化されたインスタンスを 1 つのオブジェクトに結合できます。タスクを処理するために汎用インスタンスはgetisax(2)を使用してシステムの機能を判断し、最適化された適切な関数インスタンスを呼び出すことができます。このモデルは適切に機能しますが、汎用性に欠け、実行時のオーバーヘッドが発生します。

シンボル機能はこのようなオブジェクトを作成するために別の方法を提供します。この方法はより簡単で効率が良く、さらにフロントエンドのコードを書く必要がありません。1 つの関数の複数のインスタンスを作成できます。また、さまざまな機能に関連付けることができます。これらのインスタンスと、いずれのシステムにも適した関数のデフォルトのインスタンスは、1 つの動的オブジェクトに結合できます。このファミリのシンボルの中でもっとも適したメンバーが、シンボルの機能情報を使用して、実行時リンカーによって選択されます。

次の例では、x86 オブジェクト foobar.mmx.o および foobar.sse.o が同じ関数 foo()bar() を保持しており、それぞれ MMXSSE の命令を使用するようにコンパイルされています。

$ elfdump -H foobar.mmx.o

Capabilities Section:  .SUNW_cap

 Symbol Capabilities:
    index  tag               value
      [1]  CA_SUNW_ID        mmx
      [2]  CA_SUNW_HW_1      0x40  [ MMX ]

  Symbols:
     index    value      size  type bind oth ver shndx    name
      [10]        0      0x21  FUNC LOCL  D    0 .text    foo%mmx
      [16]     0x24      0x1e  FUNC LOCL  D    0 .text    bar%mmx

$ elfdump -H foobar.sse.o

Capabilities Section:  .SUNW_cap

 Symbol Capabilities:
    index  tag               value
      [1]  CA_SUNW_ID        sse
      [2]  CA_SUNW_HW_1      0x800  [ SSE ]

  Capabilities symbols:
     index    value      size  type bind oth ver shndx    name
      [16]        0      0x2f  FUNC LOCL  D    0 .text    foo%sse
      [18]     0x48      0x30  FUNC LOCL  D    0 .text    bar%sse

これらの各オブジェクトは機能関数 foo%*() および bar%*() を指定する局所シンボルを含んでいます。また、各オブジェクトは関数 foo() および bar() への大域参照も定義します。foo() または bar() への内部参照はすべて、これらの大域参照を介して、外部参照のように再配置されます。

これら 2 つのオブジェクトは、foo() および bar() のデフォルトのインスタンスと結合できるようになりました。これらのデフォルトインスタンスは大域参照を満たし、どのオブジェクト機能とも互換性を持つ実装を提供します。これらのデフォルトインスタンスは各機能ファミリの先頭になります。オブジェクトの機能が存在しない場合、このデフォルトインスタンスも機能を要求してはいけません。実質的に、foo()bar() の 3 つのインスタンスが存在し、大域インスタンスはデフォルトを提供し、局所インスタンスは関連機能が使用できる場合に、実行時に使用される実装を提供します。

$ cc -o libfoobar.so.1 -G foobar.o foobar.sse.o foobar.mmx.o
$ elfdump -sN.dynsym libfoobar.so.1 | egrep "foo|bar"
     [2]     0x700    0x21  FUNC LOCL  D    0 .text    foo%mmx
     [4]     0x750    0x2f  FUNC LOCL  D    0 .text    foo%sse
     [8]     0x784    0x1e  FUNC LOCL  D    0 .text    bar%mmx
     [9]     0x7b0    0x30  FUNC LOCL  D    0 .text    bar%sse
    [15]     0x7a0    0x14  FUNC GLOB  D    1 .text    foo
    [17]     0x7c0    0x14  FUNC GLOB  D    1 .text    bar

動的オブジェクトの機能情報には機能シンボルが表示され、利用できる機能ファミリがわかります。

$ elfdump -H libfoobar.so.1

Capabilities Section:  .SUNW_cap

 Symbol Capabilities:
   index  tag               value
     [1]  CA_SUNW_ID        mmx
     [2]  CA_SUNW_HW_1      0x40  [ MMX ]

  Symbols:
   index    value     size  type bind oth ver shndx    name
     [2]    0x700     0x21  FUNC LOCL  D    0 .text    foo%mmx
     [8]    0x784     0x1e  FUNC LOCL  D    0 .text    bar%mmx

 Symbol Capabilities:
   index  tag               value
     [4]  CA_SUNW_ID        sse
     [5]  CA_SUNW_HW_1      0x800  [ SSE ]

  Symbols:
   index    value     size  type bind oth ver shndx    name
     [4]    0x750     0x2f  FUNC LOCL  D    0 .text    foo%sse
     [9]    0x7b0     0x30  FUNC LOCL  D    0 .text    bar%sse

Capabilities Chain Section:  .SUNW_capchain

 Capabilities family: foo
  chainndx  symndx      name
         1  [15]        foo
         2  [2]         foo%mmx
         3  [4]         foo%sse

 Capabilities family: bar
  chainndx  symndx      name
         5  [17]        bar
         6  [8]         bar%mmx
         7  [9]         bar%sse

実行時、foo()bar() へのすべての参照は、まず大域シンボルに結合されます。しかし、実行時リンカーはこれらの関数が機能ファミリの先頭のインスタンスであることを認識しています。実行時リンカーは各ファミリメンバーを検査して、より適した機能関数が使用できるかどうかを判断します。この処理には 1 回限りのコストがかかり、関数の最初の呼び出し時に発生します。foo() および bar() への後続の呼び出しは、最初の呼び出しで選択された関数のインスタンスに直接結合されます。この関数の選択は実行時リンカーのデバッグ機能を使用すると確認できます。

次の例では、ベースとなるシステムが MMX または SSE をサポートしていません。foo() の先頭のインスタンスには特別な機能のサポートは必要ないため、どの再配置参照も満たします。

$ LD_DEBUG=symbols  main
....
debug: symbol=foo;  lookup in file=./libfoo.so.1  [ ELF ]
debug:   symbol=foo[15]:  capability family default
debug:   symbol=foo%mmx[2]:  capability specific (CA_SUNW_HW_1):  [ 0x40  [ MMX ] ]
debug:   symbol=foo%mmx[2]:  capability rejected
debug:   symbol=foo%sse[4]:  capability specific (CA_SUNW_HW_1):  [ 0x800  [ SSE ] ]
debug:   symbol=foo%sse[4]:  capability rejected
debug:   symbol=foo[15]:  used

次の例では、MMX は使用できますが、SSE は使用できません。MMX が使用できる foo() のインスタンスは、どの再配置参照も解決します。

$ LD_DEBUG=symbols  main
....
debug: symbol=foo;  lookup in file=./libfoo.so.1  [ ELF ]
debug:   symbol=foo[15]:  capability family default
debug:   symbol=foo%mmx[2]:  capability specific (CA_SUNW_HW_1):  [ 0x40  [ MMX ] ]
debug:   symbol=foo%mmx[2]:  capability candidate
debug:   symbol=foo%sse[4]:  capability specific (CA_SUNW_HW_1):  [ 0x800  [ SSE ] ]
debug:   symbol=foo%sse[4]:  capability rejected
debug:   symbol=foo[2]:  used

機能関数インスタンスのファミリはプロシージャーのリンクテーブルエントリからアクセスできる必要があります。プロシージャーのリンクテーブル (プロセッサ固有)を参照してください。このプロシージャーリンクの参照には、実行時リンカーが関数を解決する必要があります。このプロセス中、実行時リンカーは関連のシンボル機能情報を処理して、使用できる関数インスタンスファミリから最適な関数を選択できます。

シンボル機能が使用されないときに、リンカーがプロシージャーのリンクテーブルエントリを必要としないでコードへの参照を解決できる場合があります。たとえば、動的実行可能ファイル内では、実行可能ファイル内に存在する関数への参照が、リンク編集時に内部的に結合できます。共有オブジェクト内に隠されて保護されている関数も、リンク編集時に内部的に結合できます。この場合、一般的に、実行時リンカーはこれらの関数への参照の解決に関与する必要はありません。

しかし、シンボル機能が使用された場合、関数はプロシージャーのリンクテーブルエントリから解決される必要があります。このエントリが必要なのは、実行時リンカーが読み取り専用のテキストセグメントを維持しながら、適切な関数を選択することに関与するためです。このメカニズムでは、機能関数へのすべての呼び出しが、プロシージャーのリンクテーブルエントリを介した間接参照になります。この間接参照は、シンボル機能が使用されない場合は必要ない可能性があります。このため、機能関数を呼び出すコストと、機能関数を使用して得られるデフォルトに対する性能の改善との間に小さいトレードオフがあります。


注 -  機能関数はプロシージャーのリンクテーブルエントリを介してアクセスする必要がありますが、この関数は隠された、または保護されたものとして定義できます。実行時リンカーはこれらの可視性に従って、関数への結合を制限します。この動作により、シンボル機能が関数と関連付けられていないときに作成される結合と同じ結合になります。隠された関数は外部オブジェクトから結合できません。保護された関数へのオブジェクト内からの参照は、同じオブジェクト内でのみ結合されます。