Nios II Gen2 プロセッサー・リファレンス・ガイド

ID 683836
日付 10/28/2016
Public
ドキュメント目次

7.9.6.3. プロシージャー・リンケージ・テーブル

位置依存実行可能ファイル内の関数コールは、256 MB のセグメントの内容に対処するcallおよびjmpi命令を使用できる可能性があります。また、%lo%hiおよび %hiadj演算子を使用して関数のアドレスを取得することもできます。関数が別の共有オブジェクトにある場合、リンカーは実行可能ファイルに PLT エントリーと呼ばれる呼び出し可能なスタブを作成します。PLT エントリーは、呼び出された関数のアドレスを PLT GOT (GOT の先頭の領域 ) からロードし、制御をそこに転送します。

PLT GOT エントリーは、タイプ R_NIOS2_JUMP_SLOT の最終シンボルを参照する再配置が必要です。動的リンカーは直ちにそれを解決するか、遅延バインディングのために変更しないでおくことができます。リンクエディターは、PLT セクションの開始時に遅延バインディング・スタブを指す初期値を入力します。

次の例に示すように、各 PLT エントリーが表示されます。

PLT エントリー

.PLTn: orhi r15, r0, %hiadj(plt_got_slot_address) ldw r15, %lo(plt_got_slot_address)(r15) jmp r15

次の例は、PLT GOT が相対的なジャンプのために小さなデータエリアに十分接近している場合の PLT エントリーを示しています。

小さなデータエリアに近い PLT エントリー

.PLTn: ldw r15, %gprel(plt_got_slot_address)(gp) jmp r15

初期の PLT エントリー

res_0: br .PLTresolve ... .PLTresolve: orhi r14, r0, %hiadj(res_0) addi r14, r14, %lo(res_0) sub r15, r15, r14 orhi r13, %hiadj(_GLOBAL_OFFSET_TABLE_) ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) jmp r13

初期の PLT エントリーの前に、一連の分岐が最初のエントリー (nextpc命令 ) の開始点となります。各 PLT エントリーには、res_0からres_Nというラベルの分岐が 1 つあります。最後のいくつかの分岐は、nop命令に置き換えることで性能を改善できます。リンクエディターは N 番目の PLT エントリーが N 番目の分岐を指すように配置します。res_Nres_0は、対応する R_JUMP_SLOT 再配置の .rela.plt セクションへのインデックスの 4 倍です。

動的リンカーは、GOT[1] を各ライブラリーの一意の識別子に初期化し、GOT[2] をランタイム・リゾルバー・ルーチンのアドレスに初期化します。.PLTresolve内の 2 つのロードが同じ%hiadjを共有するためには、_GLOBAL_OFFSET_TABLE_を 16 バイト境界に揃える必要があります。

ランタイムリゾルバーは、r4からr7までの元の関数引数、r14の GOT[1] からの共有ライブラリー識別子、r15の再配置インデックスの 4 倍を受け取ります。リゾルバーは、対応する PLT GOT エントリーを更新して、PLT エントリーが後のにターゲットに直接制御を移した後、ターゲットに制御を移します。

共有オブジェクトでは、リンク時にライブラリーのロードアドレスがわからないため、callおよびjmpi命令を使用できません。現在の共有オブジェクトの外にある関数への呼び出しは、GOT を通過する必要があります。プログラムは%callを使用して関数アドレスをロードし、リンクエディターはそのようなエントリーが遅延バウンディングされるように調整します。PLT エントリーは遅延バインディングにのみ使用されるため、共有オブジェクトの PLT は次のように小さくなります。

共有オブジェクト PLT

.PLTn: orhi r15, r0, %hiadj(index * 4) addi r15, r15, %lo(index * 4) br .PLTresolve

初期の PLT エントリー

.PLTresolve: nextpc r14 orhi r13, r0, %hiadj(_GLOBAL_OFFSET_TABLE_) add r13, r13, r14 ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) jmp r13

初期の PLT エントリーが範囲外である場合、次に示すように、長い分岐より 1 命令のみ長いため、リゾルバーはインラインになる可能性があります。

範囲外の初期の PLT エントリー

.PLTn: orhi r15, r0, %hiadj(index * 4) addi r15, r15, %lo(index * 4) nextpc r14 orhi r13, r0, %hiadj(_GLOBAL_OFFSET_TABLE_) add r13, r13, r14 ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) jmp r13