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

印刷ビューの終了

更新: 2015 年 10 月
 
 

シンボル機能データ項目のファミリの作成

初期化されたデータの複数のインスタンス (各インスタンスはシステムに固有) を同じオブジェクト内で提供できます。しかし、このようなデータは、関数インタフェースを介して提供する方法が簡単で、お勧めです。シンボル機能関数ファミリの作成を参照してください。実行可能ファイル内に初期化データの複数のインスタンスを提供するには、特別な配慮が必要です。

次の例では、foo.c 内のデータ項目 foo を初期化して、マシン名の文字列を指しています。このファイルはさまざまなマシン用にコンパイルでき、各インスタンスはマシン機能で特定されます。このデータ項目への参照は、ファイル bar.cbar() から行われます。次に共有オブジェクト foobar.so.1 が、foo の 2 つの機能インスタンスと bar() を結合することで作成されます。

$ cat foo.c
char *foo = MACHINE;
$ cat bar.c
#include <stdio.h>

extern char *foo = MACHINE;

void bar()
{
        (void) printf("machine: %s\n", foo);
}

$ elfdump -H foobar.so.1

Capabilities Section:  .SUNW_cap

 Symbol Capabilities:
   index  tag               value
     [1]  CA_SUNW_ID        sun4u
     [2]  CA_SUNW_MACH      sun4u

  Symbols:
   index    value     size  type bind oth ver shndx          name
     [1]  0x108d4      0x4  OBJT LOCL  D    0 .data          foo%sun4u

 Symbol Capabilities:
   index  tag               value
     [4]  CA_SUNW_ID        sun4v
     [5]  CA_SUNW_MACH      sun4v

  Symbols:
   index    value     size  type bind oth ver shndx          name
     [2]  0x108d8      0x4  OBJT LOCL  D    0 .data          foo%sun4v

アプリケーションは bar() を参照できます。実行時リンカーはベースとなるシステムに関連する foo のインスタンスに結合します。

$ uname -m
sun4v
$ main
machine: sun4v

このコードが適切に動作するには、コードが位置独立になるようにコンパイルされる必要があります。共有可能なオブジェクト内のコードではこれは一般的です。位置独立のコードを参照してください。位置独立のデータ参照は間接参照であるため、実行時リンカーは必要な参照を検索して、データセグメントの要素を更新できます。データセグメントのこの再配置更新では、テキストセグメントが読み取り専用として保持されます。

しかし、実行可能ファイル内のコードは位置依存であることが一般的です。また、実行可能ファイル内のデータ参照はリンク編集時に結合されます。実行可能ファイル内では、実行時リンカーがシンボル機能ファミリから選択できるように、シンボル機能のデータ参照は、大域データ項目を介して解決されない状態のままである必要があります。前の例の bar.c にある bar() からの参照が位置依存コードとしてコンパイルされた場合、実行可能ファイルのテキストセグメントは実行時に再配置される必要があります。デフォルトでは、この状態は重大なリンク時エラーとなります。

$ cc -o main main.c bar.c foo.o foo.1.o foo.2.o ...
warning: Text relocation remains                referenced
    against symbol                  offset      in file
foo                                 0x0         bar.o
foo                                 0x8         bar.o

このエラー状態を解決する 1 つの方法は、bar.c を位置独立としてコンパイルすることです。ただし、この方法を正常に動作させるには、シンボル機能データ項目への実行可能ファイル内からの参照をすべて位置独立でコンパイルする必要がある点に注意してください。

データはシンボル機能メカニズムを使用してアクセスできますが、データ項目をオブジェクトへの公開インタフェースの一部にすることは問題となる可能性があります。より柔軟な別のモデルは、シンボル機能関数に各データ項目をカプセル化することです。この関数が、データをアクセスするための唯一の手段を提供します。シンボル機能関数にデータを隠すことによって、データを静的に定義し、非公開のままに維持できるという重要なメリットが得られます。前の例は、シンボル機能関数を使用するようにコーディングできます。

$ cat foobar.c
cat bar.c
#include <stdio.h>

static char *foo = MACHINE;

void bar()
{
        (void) printf("machine: %s\n", foo);
}
$ elfdump -H main

Capabilities Section:  .SUNW_cap

 Symbol Capabilities:
   index  tag               value
     [1]  CA_SUNW_ID        sun4u
     [2]  CA_SUNW_MACH      sun4u

  Symbols:
   index    value     size  type bind oth ver shndx          name
     [1]  0x1111c     0x1c  FUNC LOCL  D    0 .text          bar%sun4u

 Symbol Capabilities:
   index  tag               value
     [4]  CA_SUNW_ID        sun4v
     [5]  CA_SUNW_MACH      sun4v

  Symbols:
   index    value     size  type bind oth ver shndx          name
     [2]  0x11138     0x1c  FUNC LOCL  D    0 .text          bar%sun4v

$ uname -m
sun4v
$ main
machine: sun4v