| 総合手引 | セクション 5 | English | オプション |
#include <sys/types.h>
#include <nlist.h>
#include <link.h>
あるプログラムを実行可能とする処理が、 システムリソースの使用を最適化しつつ正しく完了するよう、 複数のユーティリティが協調して働きます。 コンパイラは PIC コードを出力し、 それから ld(1) によって共有ライブラリが作られます。 コンパイラはまた、初期化される各データアイテムのサイズ情報を アセンブラディレクティブ .size を用いて記録します。 PIC コードは、ある間接テーブルを通じてデータ変数にアクセスする点で 従来のコードと異なっています。 この表はグローバルオフセットテーブルと呼ばれ、 慣習によって、予約名 _GLOBAL_OFFSET_TABLE_ によってアクセス可能です。 ここで用いられるメカニズムの詳細は機種依存ですが、通常は そのマシンのレジスタ 1 本がこの用途に予約されます。 このような仕組みの背景にある合理性は、 実際のロードアドレスとは独立したコードを生成することです。 実行時には、アドレス空間において様々な共有オブジェクトがロードされるアドレス に応じて、グローバルオフセットテーブルに含まれる値のみ変更すればよいのです。
同様に、大域的に定義された関数の呼び出しは、 コアイメージのデータセグメント中に置かれている プロシージャリンケージテーブル (PLT) を通じて間接的に行われます。 これもまた、実行時にテキストセグメントを修正せずに済ませるためのものです。
リンクエディタがグローバルオフセットテーブルとプロシージャリンケージテーブルを 配置するのは、 複数の PIC オブジェクトファイルを結合して プロセスのアドレス空間にマップするのに適した 1 つのイメージにする時です。 リンクエディタはまた、実行時のリンクエディタが必要とする全てのシンボルを集め、 それらをイメージのテキストとデータのビット列と共にストアします。 もう 1 つの予約シンボル _DYNAMIC は、実行時のリンク構造が存在することを示すのに用いられます。 _DYNAMIC が 0 にリロケートされる場合は、実行時リンクエディタを起動する 必要はありません。 もし _DYNAMIC が非 0 なら、_DYNAMIC は、必要なリロケーション情報と シンボル情報の位置を引き出すことができるデータ構造を指しています。 これは特に、スタートアップモジュール crt0 で利用されます。 慣習として、_DYNAMIC 構造体は、 それが属するイメージのデータセグメントの最初に置かれます。
シンボル _DYNAMIC は _dynamic 構造体を参照します:
struct _dynamic {
int d_version;
struct so_debug *d_debug;
union {
struct section_dispatch_table *d_sdt;
} d_un;
struct ld_entry *d_entry;
};
| d_version | |
| このフィールドは異なったバージョンのダイナミックリンク実装用に 提供されています。 ld(1) 及び ld.so(1) が理解する現在のバージョン番号は、 SunOS 4.x リリースで用いられている LD_VERSION_SUN (3) と、 FreeBSD 1.1 以来使用されている LD_VERSION_BSD (8) です。 | |
| d_un | |
| d_version に応じたデータ構造を参照します。 | |
| so_debug | |
| このフィールドは、 共有オブジェクトのシンボルテーブルをアクセスするためのフックを デバッガに提供します。 この共有オブジェクトは、 実行時リンクエディタの処理の結果ロードされたものです。 | |
section_dispatch_table 構造体がメインとなる "ディスパッチャ" テーブルであり、 イメージ内で様々なシンボル情報やリロケーション情報が置かれるセグメントへの オフセットを保持します。
struct section_dispatch_table {
struct so_map *sdt_loaded;
long sdt_sods;
long sdt_filler1;
long sdt_got;
long sdt_plt;
long sdt_rel;
long sdt_hash;
long sdt_nzlist;
long sdt_filler2;
long sdt_buckets;
long sdt_strings;
long sdt_str_sz;
long sdt_text_sz;
long sdt_plt_sz;
};
| sdt_loaded | |
| ロードされた最初のリンクマップ (後述) へのポインタ。 このフィールドは ld.so によって設定されます。 | |
| sdt_sods | |
| この オブジェクトが必要とする共有オブジェクト記述子の (リンク) リストの先頭。 | |
| sdt_filler1 | |
| 使用しないで下さい (SunOS では ライブラリの検索ルールを指定するのに使用されていました)。 | |
| sdt_got | |
| このイメージ中でのグローバルオフセットテーブルの位置。 | |
| sdt_plt | |
| このイメージ中でのプロシージャリンケージテーブルの位置。 | |
| sdt_rel | |
| 実行時のリロケーションを指定する relocation_info 構造体 ( a.out(5) 参照) の配列の位置。 | |
| sdt_hash | |
| このオブジェクトのシンボルテーブルでシンボル検索を高速化するための ハッシュテーブルの位置。 | |
| sdt_nzlist | |
| シンボルテーブルの位置。 | |
| sdt_filler2 | |
| 現在使用されていません。 | |
| sdt_buckets | |
| sdt_hash 中のバケット数。 | |
| sdt_strings | |
| sdt_nzlist に対応するシンボル文字列テーブルの位置。 | |
| sdt_str_sz | |
| 文字列テーブルのサイズ。 | |
| sdt_text_sz | |
| このオブジェクトのテキストセグメントのサイズ。 | |
| sdt_plt_sz | |
| プロシージャリンケージテーブルのサイズ。 | |
sod 構造体は、それを含むオブジェクトのリンクエディット処理を完了するのに 必要な共有オブジェクトを記述します。 そのようなオブジェクトのリスト ( sod_next で連結されます) は section_dispatch_table 構造体の sdt_sods によって指し示されます。
struct sod {
long sod_name;
u_int sod_library : 1,
sod_reserved : 31;
short sod_major;
short sod_minor;
long sod_next;
};
| sod_name | |
| このリンクオブジェクトを記述する文字列の、 テキストセグメントにおけるオフセット。 | |
| sod_library | |
| もし設定されていれば、 sod_name は ld.so が検索することになるライブラリを指定します。 そのパス名は、あるディレクトリ群 ( ldconfig(8) 参照) で libamp;<sod_name>amp;.so.n.m にマッチする共有オブジェクトを検索することで得られます。 もし設定されていなければ、 sod_name は希望する共有オブジェクトに対するフルパス名を指し示す必要があります。 | |
| sod_major | |
| ロードすべき共有オブジェクトのメジャーバージョン番号を指定します。 | |
| sod_minor | |
| ロードすべき共有オブジェクトの希望するマイナーバージョン番号を指定します。 | |
プロセスのアドレス空間にロードされる共有オブジェクト全てを追跡するために、 実行時リンクエディタは リンクマップ と呼ばれる構造体のリストを管理しています。 これらの構造体は実行時にのみ用いられ、 実行可能ファイルや共有ライブラリのテキストあるいはデータセグメントには ありません。
struct so_map {
caddr_t som_addr;
char *som_path;
struct so_map *som_next;
struct sod *som_sod;
caddr_t som_sodbase;
u_int som_write : 1;
struct _dynamic *som_dynamic;
caddr_t som_spd;
};
| som_addr | |
| このリンクマップに対応する共有オブジェクトがロードされるアドレス。 | |
| som_path | |
| ロードされるオブジェクトのフルパス名。 | |
| som_next | |
| 次のリンクマップへのポインタ。 | |
| som_sod | |
| この共有オブジェクトのロードをつかさどる sod 構造体。 | |
| som_sodbase | |
| 最近のバージョンの実行時リンカでは捨てられています。 | |
| som_write | |
| このオブジェクトのテキストセグメント (の一部分) が現在書き込み可能である 場合にセットされます。 | |
| som_dynamic | |
| このオブジェクトの _dynamic 構造体へのポインタ。 | |
| som_spd | |
| 実行時リンクエディタが管理するプライベートデータと連結するためのフック。 | |
サイズ付きシンボル記述。 これは単に nlist 構造体にフィールド (nz_size) を 1 つ追加したものです。 共有オブジェクトのデータセグメントにあるアイテムの サイズ情報を伝達するのに用いられます。 この構造体の配列は共有オブジェクトのテキストセグメントに存在し、 そのアドレスは section_dispatch_table の sdt_nzlist フィールドで指定されます。
struct nzlist {
struct nlist nlist;
u_long nz_size;
#define nz_un nlist.n_un
#define nz_strx nlist.n_un.n_strx
#define nz_name nlist.n_un.n_name
#define nz_type nlist.n_type
#define nz_value nlist.n_value
#define nz_desc nlist.n_desc
#define nz_other nlist.n_other
};
| nlist | |
| ( nlist(3) 参照)。 | |
| nz_size | |
| このシンボルで表現されるデータのサイズ。 | |
実行時のリンクエディットで行われるシンボル検索を高速化するため、 共有オブジェクトのテキストセグメントにハッシュテーブルが含まれています。 section_dispatch_table の sdt_hash フィールドは rrs_hash 構造体を指し示します:
struct rrs_hash {
int rh_symbolnum; /* シンボル番号 */
int rh_next; /* 次のハッシュエントリ */
};
| rh_symbolnum | |
| 共有オブジェクトのシンボルテーブル ( ld_symbols で与えられます) での当該シンボルのインデックス。 | |
| rh_next | |
| 衝突が起きたとき、このフィールドはこのハッシュテーブルのバケットにおける 次のエントリのオフセットを保持します。 最終バケット要素の場合は 0 となります。 | |
struct rt_symbol {
struct nzlist *rt_sp;
struct rt_symbol *rt_next;
struct rt_symbol *rt_link;
caddr_t rt_srcaddr;
struct so_map *rt_smp;
};
| rt_sp | |
| シンボル記述。 | |
| rt_next | |
| 次の rt_symbol の仮想アドレス。 | |
| rt_link | |
| ハッシュバケットにおける次の要素。 ld.so の内部で用いられます。 | |
| rt_srcaddr | |
| 共有オブジェクト中での初期化済データのソース位置。 | |
| rt_smp | |
| この実行時シンボルが記述するデータの元のソースとなる共有オブジェクト。 | |
so_debug 構造体は、 実行時リンクエディットの結果、当該プロセスのアドレス空間にロードされた あらゆる共有オブジェクトの情報を得るために、 デバッガによって利用されます。 実行時リンクエディタはプロセスの初期化処理の一部として実行されるため、 共有オブジェクトからシンボルにアクセスしようとするデバッガは、 crt0 からリンクエディタが呼ばれた後でのみそれが可能となります。 ダイナミックリンクされているバイナリは so_debug 構造体を持っています。この構造体の場所は _dynamic 中の d_debug フィールドで指示されます。
struct so_debug {
int dd_version;
int dd_in_debugger;
int dd_sym_loaded;
char *dd_bpt_addr;
int dd_bpt_shadow;
struct rt_symbol *dd_cc;
};
| dd_version | |
| このインタフェースのバージョン番号。 | |
| dd_in_debugger | |
| 当該プログラムがデバッガの制御下にあることを実行時リンカに知らせるために デバッガによってセットされます。 | |
| dd_sym_loaded | |
| 共有オブジェクトをロードすることで実行時リンカがシンボルを追加した場合、 実行時リンカによってセットされます。 | |
| dd_bpt_addr | |
| デバッガに制御を移すために実行時リンカによってセットされる ブレークポイントアドレス。 このアドレスは、_main 呼び出しの前に、スタートアップモジュール crt0.o によってある適切な場所に決定されます。 | |
| dd_bpt_shadow | |
| アドレス dd_bpt_addr にあった元の機械命令を保持します。 デバッガは、プログラム実行を再開する前にこの機械命令を元に戻すことに なっています。 | |
| dd_cc | |
| デバッガが必要とする可能性のある、実行時にアロケートしたシンボルの リンクリストへのポインタ。 | |
ld_entry 構造体は ld.so 中のサービスルーチン一式を定義します。
struct ld_entry {
void *(*dlopen)(char *, int);
int (*dlclose)(void *);
void *(*dlsym)(void *, char *);
char *(*dlerror)(void);
};
crt_ldso 構造体は、crt0 中のスタートアップコードと ld.so との間のインタフェースを定義します。
struct crt_ldso {
int crt_ba;
int crt_dzfd;
int crt_ldfd;
struct _dynamic *crt_dp;
char **crt_ep;
caddr_t crt_bp;
char *crt_prog;
char *crt_ldso;
struct ld_entry *crt_ldentry;
};
#define CRT_VERSION_SUN 1
#define CRT_VERSION_BSD_2 2
#define CRT_VERSION_BSD_3 3
#define CRT_VERSION_BSD_4 4
| crt_ba | |
| crt0 によって ld.so がロードされた仮想アドレス。 | |
| crt_dzfd | |
| SunOS では、このフィールドは " /dev/zero" へのオープンされたファイル記述子を保持し、 0 クリアされたデマンドページを得ます。 FreeBSD ではこのフィールドは -1 を保持します。 | |
| crt_ldfd | |
| ld.so をロードするために crt0 が用いる、オープンされたファイル記述子 を保持します。 | |
| crt_dp | |
| main の _dynamic 構造体へのポインタ。 | |
| crt_ep | |
| 環境文字列へのポインタ。 | |
| crt_bp | |
| メインプログラムがデバッガで実行される場合、 実行時リンカがブレークポイントを置くアドレス。 so_debug を参照してください。 | |
| crt_prog | |
| crt0 で決定されるメインプログラムの名前 (CRT_VERSION_BSD3 のみ)。 | |
| crt_ldso | |
| crt0 でマップされる実行時リンカのパス (CRT_VERSION_BSD4 のみ)。 | |
hints_header 構造体及び hints_bucket 構造体は、通常 " /var/run/ld.so.hints" に置かれるライブラリヒントのレイアウトを定義します。 ライブラリヒントは、ファイルシステム中で共有オブジェクトイメージの在処を すばやく見つけるために ld.so によって利用されます。 ヒントファイルの構成は "a.out" とそれほど異なりません。つまりヒントファイルは、 固定長ハッシュバケットのオフセットとサイズを決定するためのヘッダと、 共通の文字列プールを持っています。
struct hints_header {
long hh_magic;
#define HH_MAGIC 011421044151
long hh_version;
#define LD_HINTS_VERSION_1 1
long hh_hashtab;
long hh_nbucket;
long hh_strtab;
long hh_strtab_sz;
long hh_ehints;
};
| hh_magic | |
| ヒントファイルのマジックナンバ。 | |
| hh_version | |
| インタフェースのバージョン番号。 | |
| hh_hashtab | |
| ハッシュテーブルのオフセット。 | |
| hh_strtab | |
| 文字列テーブルのオフセット。 | |
| hh_strtab_sz | |
| 文字列テーブルのサイズ。 | |
| hh_ehints | |
| ヒントファイルで利用可能な最大オフセット。 | |
/*
* ヒントファイルのハッシュテーブル要素
*/
struct hints_bucket {
int hi_namex;
int hi_pathx;
int hi_dewey[MAXDEWEY];
int hi_ndewey;
#define hi_major hi_dewey[0]
#define hi_minor hi_dewey[1]
int hi_next;
};
| hi_namex | |
| ライブラリを指定する文字列のインデックス。 | |
| hi_pathx | |
| ライブラリのフルパス名を表す文字列のインデックス。 | |
| hi_dewey | |
| 共通ライブラリのバージョン番号。 | |
| hi_ndewey | |
| hi_dewey 中の有効エントリ数。 | |
| hi_next | |
| ハッシュ衝突の際の次のバケット。 | |
| LINK (5) | October 23, 1993 |
| 総合手引 | セクション 5 | English | オプション |
このマニュアルページサービスについてのご意見は Ben Bullock にお知らせください。 Privacy policy.
| “ | Some people, when confronted with a problem, think “I know, I'll use regular expressions.” Now they have two problems. | ” |
| — Jamie Zawinski | ||