JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
Oracle Solaris 11.1 リンカーとライブラリガイド     Oracle Solaris 11.1 Information Library (日本語)
このドキュメントの評価
search filter icon
search icon

ドキュメントの情報

はじめに

パート I リンカーおよび実行時リンカーの使用

1.  Oracle Solaris リンカーの紹介

2.  リンカー

3.  実行時リンカー

4.  共有オブジェクト

パート II クイックリファレンス

5.  リンカーのクイックリファレンス

パート III 詳細情報

6.  直接結合

7.  システムのパフォーマンスを最適化するオブジェクトの構築

8.  mapfile

9.  インタフェースおよびバージョン管理

10.  動的ストリングトークンによる依存関係の確立

11.  拡張性メカニズム

リンカーのサポートインタフェース

サポートインタフェースの呼び出し

32 ビットおよび 64 ビット環境

サポートインタフェース関数

サポートインタフェースの例

実行時リンカーの監査インタフェース

名前空間の確立

監査ライブラリの作成

監査インタフェースの呼び出し

ローカル監査の記録

大域監査の記録

監査インタフェースの対話

監査インタフェースの関数

監査インタフェースの例

監査インタフェースのデモンストレーション

監査インタフェースの制限

アプリケーションコードの実行

la_pltexit() の使用

スタックを直接検査する関数

実行時リンカーのデバッガインタフェース

制御プロセスとターゲットプロセス間の対話

デバッガインタフェースのエージェント

デバッガエクスポートインタフェース

エージェント操作インタフェース

エラー処理

読み込み可能オブジェクトの走査

イベント通知

プロシージャーのリンクテーブルのスキップ

動的オブジェクトのパッド

デバッガインポートインタフェース

パート IV ELF アプリケーションバイナリインタフェース

12.  オブジェクトファイル形式

13.  プログラムの読み込みと動的リンク

14.  スレッド固有ストレージ (TLS)

パート V 付録

A.  リンカーとライブラリのアップデートおよび新機能

B.  System V Release 4 (バージョン 1) Mapfile

索引

ドキュメントの品質向上のためのご意見をください
簡潔すぎた
読みづらかった、または難し過ぎた
重要な情報が欠けていた
内容が間違っていた
翻訳版が必要
その他
Your rating has been updated
貴重なご意見を有り難うございました!

あなたの貴重なご意見はより良いドキュメント作成の手助けとなります 内容の品質向上と追加コメントのためのアンケートに参加されますか?

実行時リンカーのデバッガインタフェース

実行時リンカーは、メモリーへのオブジェクトの割り当てやシンボルの結合を含む多数の操作を実行します。デバッグプログラムは、通常、これらの実行時リンカーの操作をアプリケーション解析の一部として記述する情報にアクセスする必要があります。これらのデバッグプログラムは、デバッガが解析するアプリケーションから独立したプロセスとして実行されます。

このセクションでは、ほかのプロセスから動的にリンクされたアプリケーションを監視、変更する「rtld-デバッガ」インタフェースについて説明します。このインタフェースのアーキテクチャーは、libc_db(3LIB) で使用されるモデルに準拠します。

「rtld-デバッガ」インタフェースを使用する場合は、少なくとも次の 2 つのプロセスが関与します。

「rtld-デバッガ」は、制御プロセスがデバッガであり、そのターゲットが動的実行可能なプログラムの場合に、もっともよく使用されます。

「rtld-デバッガ」インタフェースは、ターゲットプロセスに対して、次のアクティビティーを有効にします。

制御プロセスとターゲットプロセス間の対話

ターゲットプロセスを検査して操作できるようにするために、「rtld-デバッガ」インタフェースは、「エクスポート」されたインタフェース、「インポート」されたインタフェース、および「エージェント」を使用して、これらのインタフェース間で通信を行います。

制御プロセスは、librtld_db.so.1 によって提供される「rtld-デバッガ」インタフェースにリンクされて、このライブラリからエクスポートされたインタフェースを要求します。このインタフェースは、/usr/include/rtld_db.h に定義されています。次に、librtld_db.so.1 は制御プロセスからインポートされたインタフェースを要求します。「rtld-デバッガ」インタフェースは、この対話によって次の処理を実行できます。

インポートされたインタフェースは多数の proc_service ルーチンから構成されます。大半のデバッガは、このルーチンをすでに使用してプロセスを解析しています。これらのルーチンについては、「デバッガインポートインタフェース」を参照してください。

「rtld-デバッガ」インタフェースは、「rtld-デバッガ」インタフェースの要求により解析中のプロセスが停止することを前提としています。停止しない場合は、ターゲットプロセスの実行時リンカー内にあるデータ構造が、検査時に一貫した状態にない可能性があります。

librtld_db.so.1、制御プロセス (デバッガ)、およびターゲットプロセス (動的実行可能プログラム) 間の情報の流れを、次の図に示します。

図 11-1 「rtld-デバッガ」の情報の流れ

image:rtld-デバッガの情報の流れ。

注 - 「rtld-デバッガ」インタフェースは、実験的と見なされる proc_service インタフェース (/usr/include/proc_service.h) に依存します。「rtld-デバッガ」インタフェースは、展開時に、proc_service インタフェース内の変更を追跡しなければならないことがあります。


rtld-debugger インタフェースを使用する制御プロセスのサンプル実装は、/usr/demo/librtld_db の下の pkg:/solaris/source/demo/system パッケージにあります。このデバッガ rdb は、proc_service インポートインタフェースの使用例、およびすべての librtld_db.so.1 エクスポートインタフェースの必須呼び出しシーケンスを示します。次のセクションでは、「rtld-デバッガ」インタフェースについて説明します。さらに詳しい情報は、サンプルデバッガをテストして入手することができます。

デバッガインタフェースのエージェント

エージェントは、内部インタフェース構造を記述可能な不透明なハンドルを提供します。エージェントは、エクスポートインタフェースとインポートインタフェースとの間の通信メカニズムも提供します。「rtld-デバッガ」インタフェースは、いくつかのプロセスを同時に操作できるデバッガによる使用を目的としているため、これらのエージェントは、プロセスを特定するために使用されます。

struct ps_prochandle

制御プロセスによって、エクスポートインタフェースとインポートインタフェースの間で渡されるターゲットプロセスを特定するために作成される不透明な構造です。

struct rd_agent

「rtld-デバッガ」インタフェースによって、エクスポートインタフェースとインポートインタフェースの間で渡されるターゲットプロセスを特定するために作成される不透明な構造です。

デバッガエクスポートインタフェース

このセクションでは、/usr/lib/librtld_db.so.1 監査ライブラリによってエクスポートされるさまざまなインタフェースについて説明します。機能グループごとに分けて説明します。

エージェント操作インタフェース

rd_init()

この関数は、「rtld-デバッガ」バージョン要件を確立します。ベースとなるバージョンは、RD_VERSION1 として定義されています。現在の「バージョン」は常に RD_VERSION で定義されます。

rd_err_e rd_init(int version);

Solaris 8 10/00 リリースで追加されたバージョン RD_VERSION2 は、rd_loadobj_t 構造体を拡張するものです。詳細は、「読み込み可能オブジェクトの走査」rl_flags rl_bend および rl_dynamic フィールドを参照してください。

Solaris 8 01/01 リリースで追加されたバージョン RD_VERSION3 は、rd_plt_info_t 構造体を拡張するものです。詳細は、「プロシージャーのリンクテーブルのスキップ」pi_baddr および pi_flags フィールドを参照してください。

制御プロセスのバージョン要件が使用可能な「rtld-デバッガ」インタフェースよりも大きい場合は、RD_NOCAPAB が返されます。

rd_new()

この関数は、新しいエクスポートのインタフェースエージェントを作成します。

rd_agent_t *rd_new(struct ps_prochandle *php);

php は、制御プロセスによってターゲットプロセスを特定するために作成された cookie です。この cookie は、制御プロセスによってコンテキストを維持するために提供されるインポートされたインタフェースで使用されるものであり、「rtld-デバッガ」インタフェースに対して不透明です。

rd_reset()

この関数は、rd_new() に指定された同じ ps_prochandle 構造に基づくエージェント内の情報をリセットします。

rd_err_e rd_reset(struct rd_agent *rdap);

この関数は、ターゲットプロセスが再起動されると呼び出されます。

rd_delete()

この関数は、エージェントを削除し、それに関連するすべての状態を解放します。

void rd_delete(struct rd_agent *rdap);

エラー処理

次のエラー状態は、「rtld-デバッガ」インタフェース (rtld_db.h に定義) によって返されます。

typedef enum {
        RD_ERR,
        RD_OK,
        RD_NOCAPAB,
        RD_DBERR,
        RD_NOBASE,
        RD_NODYNAM,
        RD_NOMAPS
} rd_err_e;

次のインタフェースは、エラー情報を収集するために使用できます。

rd_errstr()

この関数は、エラーコード rderr を記述する記述エラー文字列を返します。

char *rd_errstr(rd_err_e rderr);
rd_log()

この関数は、ログ記録をオン (1) またはオフ (0) にします。

void rd_log(const int onoff);

ログ記録がオンの場合、制御プロセスによって提供されるインポートインタフェース関数 ps_plog() は、さらに詳しい診断情報によって呼び出されます。

読み込み可能オブジェクトの走査

実行時リンカーのリンクマップで維持される各オブジェクト情報の取得は、rtld_db.h に定義された次の構造を使用して実現されます。

typedef struct rd_loadobj {
        psaddr_t        rl_nameaddr;
        unsigned        rl_flags;
        psaddr_t        rl_base;
        psaddr_t        rl_data_base;
        unsigned        rl_lmident;
        psaddr_t        rl_refnameaddr;
        psaddr_t        rl_plt_base;
        unsigned        rl_plt_size;
        psaddr_t        rl_bend;
        psaddr_t        rl_padstart;
        psaddr_t        rl_padend;
        psaddt_t        rl_dynamic;
        unsigned long   rl_tlsmodid;
} rd_loadobj_t;

文字列ポインタを含めて、この構造で指定されるアドレスはすべてターゲットプロセス内のアドレスであり、制御プロセス自体のアドレス空間のアドレスでないことに注意してください。

rl_nameaddr

動的オブジェクトの名前を含む文字列へのポインタ。

rl_flags

リビジョン RD_VERSION2 では、動的に読み込まれる再配置可能オブジェクトは RD_FLG_MEM_OBJECT で識別されます。

rl_base

動的オブジェクトのベースアドレス。

rl_data_base

動的オブジェクトのデータセグメントのベースアドレス。

rl_lmident

リンクマップ識別子 (「名前空間の確立」を参照)。

rl_refnameaddr

動的オブジェクトが標準フィルタの場合は、「フィルティー」の名前を指定します。

rl_plt_baserl_plt_size

これらの要素は、下方互換性のために存在するものであり、現在は使用されていません。

rl_bend

オブジェクトのエンドアドレス (text + data + bss)。リビジョン RD_VERSION2 では、動的に読み込まれる再配置可能オブジェクトの場合、この要素は作成されたオブジェクトの最後を指します。このオブジェクトには、自身のセクションヘッダーが含まれています。

rl_padstart

動的オブジェクト前のパッドのベースアドレス (「動的オブジェクトのパッド」を参照)。

rl_padend

動的オブジェクト後のパッドのベースアドレス (「動的オブジェクトのパッド」を参照)。

rl_dynamic

このフィールドは RD_VERSION2 に追加されたもので、DT_CHECKSUM (表 13-8 を参照) のエントリへの参照を可能にするオブジェクトの動的セクションのベースアドレスを提供します。

rl_tlsmodid

このフィールドは、RD_VERSION4 に追加されたもので、スレッド固有ストレージ (TLS) 参照のモジュール識別子を提供します。このモジュール識別子は、オブジェクトに固有の短い整数です。この識別子は、問題となるオブジェクトのスレッドの TLS ブロックの基底アドレスを取得するために、libc_db の関数 td_thr_tlsbase() に渡すことができます。td_thr_tlsbase(3C_DB) を参照してください。

rd_loadobj_iter() ルーチンは、このオブジェクトデータ構造を使用して実行時リンカーのリンクマップリストの情報にアクセスします。

rd_loadobj_iter()

この関数は、ターゲットプロセスに現在読み込まれている動的オブジェクトすべてを反復します。

typedef int rl_iter_f(const rd_loadobj_t *, void *);
 
rd_err_e rd_loadobj_iter(rd_agent_t *rap, rl_iter_f *cb,
        void *clnt_data);

各反復時に、cb によって指定されたインポート関数が呼び出されます。clnt_data は、cb 呼び出しにデータを渡すために使用できます。各オブジェクトに関する情報は、スタックが割り当てられた volatile rd_loadobj_t 構造へのポインタによって返されます。

cb ルーチンからの戻りコードは、rd_loadobj_iter() によってテストされ、次の意味を持ちます。

  • 1 – リンクマップの処理を継続する。

  • 0 – リンクマップの処理を停止して、制御プロセスに制御を返す。

rd_loadobj_iter() は、正常だと RD_OK を返します。RD_NOMAPS が返される場合、実行時リンカーは、まだ初期リンクマップを読み込みません。

イベント通知

制御プロセスは、実行時リンカーの適用範囲内で発生する特定のイベントを追跡できます。これらのイベントは次のとおりです。

RD_PREINIT

実行時リンカーは、すべての動的オブジェクトを読み込んで再配置し、読み込まれた各オブジェクトの .init セクションの呼び出しを開始します。

RD_POSTINIT

実行時リンカーは、すべての .init セクションの呼び出しを終了して、基本実行可能プログラムに制御を渡します。

RD_DLACTIVITY

実行時リンカーは、動的オブジェクトを読み込みまたは読み込み解除のために呼び出されます。

これらのイベントは、次のインタフェース (sys/link.hrtld_db.h に定義) を使用して監視できます。

typedef enum {
        RD_NONE = 0,
        RD_PREINIT,
        RD_POSTINIT,
        RD_DLACTIVITY
} rd_event_e;
 
/*
 * Ways that the event notification can take place:
 */
typedef enum {
        RD_NOTIFY_BPT,
        RD_NOTIFY_AUTOBPT,
        RD_NOTIFY_SYSCALL
} rd_notify_e;
 
/*
 * Information on ways that the event notification can take place:
 */
typedef struct rd_notify {
        rd_notify_e     type;
        union {
                psaddr_t        bptaddr;
                long            syscallno;
        } u;
} rd_notify_t;

イベントを追跡する関数を次に示します。

rd_event_enable()

この関数は、イベント監視を有効 (1) または無効 (0) にします。

rd_err_e rd_event_enable(struct rd_agent *rdap, int onoff);

注 - パフォーマンス上の理由から、現在、実行時リンカーはイベントの無効化を無視します。制御プロセスは、このルーチンへの最後の呼び出しが原因で指定のブレークポイントに到達しないと、想定することはできません。


rd_event_addr()

この関数は、制御プログラムへの指定イベントの通知方法を指定します。

rd_err_e rd_event_addr(rd_agent_t *rdap, rd_event_e event,
        rd_notify_t *notify);

イベントの種類によっては、制御プロセスの通知は、notify->u.syscallno で特定される害のない簡単なシステム呼び出しの呼び出しや、notify->u.bptaddr で指定されるアドレスでのブレークポイントの実行で行われます。システム呼び出しの追跡または実際のブレークポイントの設定は、制御プロセスが行う必要があります。

イベントが発生した場合は、rtld_db.h に定義された次のインタフェースによって追加情報を取得できます。

typedef enum {
        RD_NOSTATE = 0,
        RD_CONSISTENT,
        RD_ADD,
        RD_DELETE
} rd_state_e;
 
typedef struct rd_event_msg {
        rd_event_e      type;
        union {
                rd_state_e      state;
        } u;
} rd_event_msg_t;

rd_state_e の値を次に示します。

RD_NOSTATE

使用可能な追加状態情報はありません。

RD_CONSISTANT

リンクマップは安定した状態にあってテスト可能です。

RD_ADD

動的オブジェクトは削除処理中であり、リンクマップは安定した状態ではありません。リンクマップは、RD_CONSISTANT 状態に達するまでテストできません。

RD_DELETE

動的オブジェクトは削除処理中であり、リンクマップは安定した状態ではありません。リンクマップは、RD_CONSISTANT 状態に達するまでテストできません。

rd_event_getmsg() 関数を使用して、このイベント状態情報を取得します。

rd_event_getmsg()

この関数は、イベントに関する追加情報を提供します。

rd_err_e rd_event_getmsg(struct rd_agent *rdap, rd_event_msg_t *msg);

次の表は、異なる各イベントタイプで可能な状態を示しています。

RD_PREINIT
RD_POSTINIT
RD_DLACTIVITY
RD_NOSTATE
RD_NOSTATE
RD_CONSISTANT
RD_ADD
RD_DELETE

プロシージャーのリンクテーブルのスキップ

「rtld-デバッガ」インタフェースは、制御プロセスが、プロシージャーのリンクのテーブルエントリをスキップオーバーする機能を提供します。デバッガなどの制御プロセスが、関数に介入するようにとの要求をはじめて受けると、プロシージャーのリンクテーブル処理は、制御を実行時リンカーに渡して関数定義を検索します。

次のインタフェースを使用すると、制御プロセスで実行時リンカーのプロシージャーのリンクテーブル処理にステップオーバーできます。制御プロセスは、ELF ファイルで提供される外部情報に基づいて、プロシージャーのリンクのテーブルエントリに遭遇する時期を判定できます。

ターゲットプロセスは、プロシージャーのリンクのテーブルエントリに介入すると、rd_plt_resolution() インタフェースを呼び出します。

rd_plt_resolution()

この関数は、現在のプロシージャーのリンクテーブルエントリの解決状態と、それをスキップする方法に関する情報を返します。

rd_err_e rd_plt_resolution(rd_agent_t *rdap, paddr_t pc,
        lwpid_t lwpid, paddr_t plt_base, rd_plt_info_t *rpi);

pc は、プロシージャーのリンクテーブルエントリの最初の命令を表します。lwpidlwp 識別子を提供し、plt_base はプロシージャーのリンクテーブルのベースアドレスを提供します。これらの 3 つの変数は、各種のアーキテクチャーがプロシージャーのリンクテーブルを処理するため十分な情報を提供します。

rpi は、rtld_db.h 内の次のデータ構造に定義された、プロシージャーのリンクのテーブルエントリに関する詳しい情報を提供します。

typedef enum {
        RD_RESOLVE_NONE,
        RD_RESOLVE_STEP,
        RD_RESOLVE_TARGET,
        RD_RESOLVE_TARGET_STEP
} rd_skip_e;
 
typedef struct rd_plt_info {
        rd_skip_e       pi_skip_method;
        long            pi_nstep;
        psaddr_t        pi_target;
        psaddr_t        pi_baddr;
        unsigned int    pi_flags;
} rd_plt_info_t;

#define RD_FLG_PI_PLTBOUND     0x0001

rd_plt_info_t 構造体の要素を次に示します。

pi_skip_method

プロシージャーのリンクテーブルエントリがどのように扱われるかを示します。rd_skip_e 値内の 1 つに設定されます。

pi_nstep

RD_RESOLVE_STEP または RD_RESOLVE_TARGET_STEP が返された時にステップオーバーする命令がいくつあるかを示します。

pi_target

RD_RESOLVE_TARGET_STEP または RD_RESOLVE_TARGET が返された時にブレークポイントを設定するアドレス指定します。

pi_baddr

RD_VERSION3 で追加された、プロシージャーのリンクテーブルの宛先アドレス。pi_flags フィールドの RD_FLG_PI_PLTBOUND フラグが設定されると、この要素は解決された (結合された) 宛先アドレスを示します。

pi_flags

RD_VERSION3 で追加されたフラグフィールド。フラグ RD_FLG_PI_PLTBOUND は、pi_baddr フィールドで取得できる宛先アドレスへ解決された (結合された) プロシージャーのリンクエントリを示します。

次のシナリオは rd_plt_info_t 戻り値から考えられます。

動的オブジェクトのパッド

実行時リンカーのデフォルト動作は、オペレーティングシステムに依存して、もっとも効率的に参照できる場所に動的オブジェクトを読み込みます。制御プロセスの中には、ターゲットプロセスのメモリーに読み込まれたオブジェクトの周りにパッドがあることによって、利益を受けるものがあります。このインタフェースを使用すると、制御プロセスは、このパッドを要求できます。

rd_objpad_enable()

この関数は、ターゲットプロセスによって続けて読み込まれたオブジェクトのパッドを有効または無効にします。パッドは読み込まれたオブジェクトの両側で行われます。

rd_err_e rd_objpad_enable(struct rd_agent *rdap, size_t padsize);

padsize メモリーに読み込まれたオブジェクトの前後両方で維持されるパッドのサイズをバイト数で指定します。このパッドは、mmapobj(2) 要求からのメモリー割り当てとして予約されています。実際には、ターゲットプロセスの仮想アドレス空間の、読み込み済みオブジェクトに隣接する領域が予約されます。これらの領域は、制御プロセスによってあとで使用できます。

padsize を 0 にすると、後のオブジェクトに対するオブジェクトパッドは無効になります。


注 - mmapobj(2) を使用して取得した予約は、proc(1) 機能や rd_loadobj_t で提供されるリンクマップ情報を参照することでレポートできます。


デバッガインポートインタフェース

制御プロセスが librtld_db.so.1 に対して提供しなければならないインポートインタフェースは、/usr/include/proc_service.h に定義されています。これらの proc_service 関数のサンプル実装状態は、rdb デモデバッガにあります。「rtld-デバッガ」インタフェースは、使用可能な proc_service インタフェースのサブセットだけを使用します。「rtld-デバッガ」インタフェースの今後のバージョンでは、互換性のない変更を作成することなく、追加 proc_service インタフェースを利用できる可能性があります。

次のインタフェースは、現在、「rtld-デバッガ」インタフェースによって使用されています。

ps_pauxv()

この関数は、auxv ベクトルのコピーへのポインタを返します。

ps_err_e ps_pauxv(const struct ps_prochandle *ph, auxv_t **aux);

auxv ベクトル情報は、割り当てられた構造にコピーされるため、このポインタの存続期間は、ps_prochandle が有効な間になります。

ps_pread()

この関数は、ターゲットプロセスからデータを読み取ります。

ps_err_e ps_pread(const struct ps_prochandle *ph, paddr_t addr,
        char *buf, int size);

ターゲットプロセス内のアドレス addr から、size バイトが buf にコピーされます。

ps_pwrite()

この関数は、ターゲットプロセスにデータを書き込みます。

ps_err_e ps_pwrite(const struct ps_prochandle *ph, paddr_t addr,
        char *buf, int size);

buf から size バイトが、ターゲットプロセスのアドレス addr にコピーされます。

ps_plog()

この関数は、「rtld-デバッガ」インタフェースから追加診断情報によって呼び出されます。

void ps_plog(const char *fmt, ...);

この診断情報をどこに記録するか、または記録するかどうかは、制御プロセスが決めます。ps_plog() の引数は、printf(3C) 形式に従います。

ps_pglobal_lookup()

この関数は、ターゲットプロセス内のシンボルを検索します。

ps_err_e ps_pglobal_lookup(const struct ps_prochandle *ph,
        const char *obj, const char *name, ulong_t *sym_addr);

ターゲットプロセス ph 内のオブジェクト obj 内で、シンボル name が検索されます。シンボルが検出されると、シンボルのアドレスが sym_addr に保存されます。

ps_pglobal_sym()

この関数は、ターゲットプロセス内のシンボルを検索します。

ps_err_e ps_pglobal_sym(const struct ps_prochandle *ph,
        const char *obj, const char *name, ps_sym_t *sym_desc);

ターゲットプロセス ph 内のオブジェクト obj 内で、シンボル name が検索されます。シンボルが検出されると、シンボルの記述子が sym_desc に保存されます。

「rtld-デバッガ」インタフェースがアプリケーションまたは実行時リンカー内のシンボルを検出してから、リンクマップを作成する必要があるイベントでは、obj に対する次の予約値を使用できます。

#define PS_OBJ_EXEC ((const char *)0x0)  /* application id */
#define PS_OBJ_LDSO ((const char *)0x1)  /* runtime linker id */

制御プロセスは、次の擬似コードを使用して、これらのオブジェクト用の procfs ファイルシステムを利用できます。

ioctl(.., PIOCNAUXV, ...)       - obtain AUX vectors
ldsoaddr = auxv[AT_BASE];
ldsofd = ioctl(..., PIOCOPENM, &ldsoaddr);
 
/* process elf information found in ldsofd ... */
 
execfd = ioctl(.., PIOCOPENM, 0);
 
/* process elf information found in execfd ... */

ファイル記述子が見つかったら、ELF ファイルは、制御プログラムによってそのシンボル情報をテストできます。