共有オブジェクトの操作
共有オブジェクトのリンク
共有オブジェクトはコマンドラインオプション --shared でリンク付けされます。‑‑shared(リンカオプション)を参照してください。
共有オブジェクトと実行可能ファイルの主要な違いを説明します。
共有オブジェクトは、未定義の外部シンボルを含めることができます。つまり共有オブジェクトで必要なシンボルが、内部で定義されていないケースです。これは、C/C++ での
externキーワードの動作に似ています。共有オブジェクトには、通常はターゲットプロセッサにロードされない補足セクション(ELFファイルヘッダー、動的シンボルテーブル、動的文字列テーブル)が含まれている必要があります。これらのセクションと他のいくつかのセクションは、動的リンカにはすべて必要です。これらはアプリケーションの一部であるため、ターゲット上のスペースを消費します。
共有オブジェクトには、すべてのアドレスが格納される一元化された場所、グローバルオフセットテーブル(GOT)があります。すべてのグローバルデータは、GOTを使用して共有オブジェクトの中からアクセスします。
共有オブジェクト内の呼び出しとジャンプでは相対アドレス指定が使用されます。この場合、共有オブジェクトがロードされるアドレスは関係ありません。共有オブジェクト外への呼び出しやジャンプにはGOTのアドレスを使用する必要があります。命令ではGOTを直接使用できないため、補助セクションであるプロシージャリンケージテーブル(PLT)が存在します。PLTは次のように動作します。
制御は最終のターゲットのPLT エントリに移行されます
PLTはGOTからアドレスを読み取ります
制御は最終のターゲットに移行されます
これにより、コードセクションは変更されないままにできます。ジャンプや呼び出しは対応するPLTエントリにリダイレクトされるだけです。これは、べニア関数が実行可能ファイルに対してどのように機能するかに似ています。
注記
標準のライブラリとサードパーティのライブラリを含む、すべての入力オブジェクトファイルは、‑‑sharedコンパイラオプションでビルドされなければなりません。
共有オブジェクトの配置
共有オブジェクトを生成するとき、コンテンツが配置される場所を完全に管理できません。共有オブジェクトは常にアドレス0でリンクされます。共有オブジェクトは常にメモリにロードされるので、これはオフセットやアドレスを取得しやすくします。シンボルが、共有オブジェクトのオフセット0x420で生成され、その共有オブジェクトが0x8000でロードされると、シンボルの値は0x8420になります。
共有オブジェクトを生成するときは、通常のplace inおよびplace atディレクティブは利用できません。共有オブジェクトには、define blockディレクティブを使用して定義する必要のあるブロックが4つあります。so_code、so_const、so_data、およびso_bssです。共有オブジェクトのリンカブロックのリファレンス情報を参照してください。
通常と同じように、ブロック内でブロックを使用できます。
define block so_code with fixed_order {
block myFirstBlock,
block mySecondBlock,
block myThirdBlock
};4つのブロックをすべて定義し(空のブロックを定義することも可能)、リンクされたアプリケーションにどのブロックにも一致しないセクションがない限り、共有オブジェクトは指定したレイアウトになります。
共有オブジェクトのロードとアンロード
共有オブジェクトが、dlopenのコールでロードされるとき、動的リンカは、新しい共有オブジェクトが提供したシンボルおよび動的リンカに必要なシンボル(未定義の外部のもの)を確認します。現在ロードされているシンボルとそのアドレスに関する情報を利用して、動的リンカは、GOTセクション内のアドレスを更新することによって、ロードされたオブジェクトと以前にロードされたすべての共有オブジェクトを更新します。
ロードは、lazyまたはeagerです。Eagerロードは、ロード時にすべてのシンボルアドレスを解決します。Lazyロードは、ロード時にすべてのデータシンボルを解決しますが、コードシンボルはアクセスされるまで解決されません。どちらのロードを使用するかは、dlopenへのコールでのフラグの使い方で通常決定されます。ILINKで生成されたすべての共有オブジェクトは、lazyおよびeagerロードの両方で機能します。
共有オブジェクトは、dlcloseへのコールでアンロードされます。これが発生すると、共有オブジェクトが提供したシンボルはシステムから削除されます。これにより、使用可能なシンボルに依存する他の共有オブジェクトの環境が無効になる可能性があることに注意してください。
共有オブジェクトの使用
dlopenを使用して共有オブジェクトがロードされた後、dlsym関数を使用して共有オブジェクトのコンテンツにアクセスできます。これを行う正確な方法については、お使いのオペレーティングシステムのドキュメントを参照してください。
Cインターフェースは、ヘッダーファイルdlfcn.h(IARは提供していません)にあります。
共有オブジェクト内のデータ変数へのアクセスは、次のようになります。
void * handle = dlopen("myObject.so", FLAGS);
int * dataPtr = (int *)dlsym(handle, "myVariable");
...
dlclose(handle);これは、共有オブジェクトmyObject.soのシンボルmyVariableへのポインタを取得します。
共有オブジェクトの関数へのアクセスは、次のようになります。
void * handle = dlopen("myObject.so", FLAGS);
typedef int (*function)(int, int);
function myFunc = (function)dlsym(handle, "myFunction");
...
dlclose(handle);これは関数ポインタを取得します。これにより、オブジェクトmyObject.so内の関数myFunctionへの関数ポインタ(2つのintパラメータを受け取り、intを返す関数)が取得されます。
FLAGSは、共有オブジェクトのロードの様々な側面を制御するシステム依存の値です。lazyおよびeagerロードの選択は、通常このフラグを使用して行われます。お使いのオペレーティングシステムのドキュメントを参照してください。
共有オブジェクトのデバッグ
コンパイラによって生成されたオブジェクトファイルには、通常のデバッグ情報があります。ILINKリンカには、共有オブジェクトのコンテンツのオフセット上にすべてのデバッグ情報を格納します(共有オブジェクトはいつもオフセット0で始まります)。
あるオフセット(ロードオフセット)で共有オブジェクトがメモリにロードされるとき、デバッガがロードオフセットですべてのデバッグ情報をオフセットできる限り、デバッグ情報は機能します。IAR C-SPY Debuggerは、特定のオフセットでデバッグファイルをオフセットできます。