リーディングプログラマーの自己育成リンク、パッケージング、およびライブラリ(18:第7章:ダイナミックリンク(2)遅延バインディングPLT)
1.ダイナミックリンクのパフォーマンスが低い2つの理由
- グローバルおよびスタティックデータアクセスの場合は、複雑なGOTポジショニングを実行してから間接アドレッシング
を実行する必要があり、モジュール間の呼び出しの場合は、最初にGOTを実行してから間接ジャンプを実行する必要があります。 - ダイナミックリンクのリンク作業は実行時に完了します。つまり、プログラムが実行を開始すると、ダイナミックリンカーはリンク作業を実行する必要があります。
ダイナミックリンカーは必要な共有オブジェクトを見つけてロードし、シンボル検索やアドレスの再配置などの作業を実行します。
上記の2つの理由により、動的リンクが静的リンクよりも遅くなります。
2.遅延バインディングの実装
2.1バインディングの遅延の理由
ダイナミックリンクでは、プログラムモジュール間に多数の関数参照があり、その中にグローバル変数はほとんどありません。グローバル変数の
数が多いとモジュール間の結合が増えるため、
ダイナミックリンクライブラリはプログラムが実行を開始する前に多くの時間を消費します。シンボル検索とモジュール間の関数参照の再配置を実行します。
一部のエラー関数や一部の関数関数など、プログラムで使用されない関数が多いため
、最初にすべての関数をリンクすると無駄になります。
2.2初めて使用する場合のみの遅延バインディングの思考バインディング
遅延バインディング
実際にはすべての関数を最初からリンクするのは無駄なので、ELFは遅延バインディングと呼ばれる方法を採用しています。
基本的な考え方は、初めて使用するときに関数をバインドし、使用しない場合はバインドしないことです。
したがって、プログラムの最初では、モジュール間の関数呼び出しはバインドされていませんが、動的リンカーが使用されている場合はバインドを行います。
2.3バインディングの遅延の利点
プログラムの起動速度を大幅に高速化し
ます。特に、多数の関数参照と多数のモジュールを使用する一部のプログラムに役立ちます。
2.4バインディングの遅延の原則
ELFはPLT(プロシージャリンケージテーブル)メソッドを
使用して達成します。このメソッドは、非常にデリケートな命令シーケンスを使用して完了します。
2.4.1中間層に間接ジャンプを追加する
外部モジュールの関数を呼び出すときの通常の方法は、GOT内の対応する項目を間接的にジャンプすることです。
遅延バインディングを実現するために、PLTはこのプロセスの途中に間接ジャンプの別のレイヤーを追加します。
関数はGOTを直接ジャンプするのではなく、PLTアイテムと呼ばれる構造をジャンプします。
各外部関数には、PLTに対応する項目があります。
2.4.2 PLTの原理を説明する例
-
bar()関数を例に取り、bar @ pltの実装を見てみましょう
bar @ plt
jmp *(bar @ GOT)
push n
push moduleID
jump _dl_runtime_resolve -
説明:
総括する:
- 最初に、モジュール関数の解決記号添え字をスタックにプッシュします。
- 次に、モジュールIDをスタックにプッシュします
- 次に、動的リンカーを呼び出して、シンボルの解決と再配置を完了します。
- 次に、実際の関数アドレスを入力します
- もう一度呼ばれると、直接ジャンプできます
2.5 .pltセクション
PLTは別のセクションとしてELFファイルに格納され、セクション名は通常.pltと呼ばれます。
それ自体はアドレスに依存しないコードなので、コードセグメントなどと組み合わせて、同じ読み取り可能で実行可能なセグメントにして、メモリに読み込むことができます。