x86 では、TLS へのアクセスに次のコードシーケンスモデルを使用できます。
このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている GD モデルを実装します。
表 8–8 32 ビット x86: General Dynamic スレッド固有変数のアクセスコード
leal 命令は R_386_TLS_GD 再配置を生成します。この再配置は、変数 x の TLS_index 構造体を保持する領域を GOT 内に割り当てるよう、リンカーに指示します。リンカーは、この新しい GOT エントリに GOT からの相対オフセットを代入することによって、この再配置を処理します。
読み込みオブジェクトインデックスと x の TLS ブロックインデックスは実行時まで不明なため、リンカーは、実行時リンカーによって処理されるように、GOT に対して R_386_TLS_DTPMOD32 再配置と R_386_TLS_DTPOFF32 再配置を設定します。生成された GOT エントリのアドレスは、___tls_get_addr() 呼び出しのためにレジスタ %eax に読み込まれます。
call 命令は、R_386_TLS_GD_PLT 再配置を生成します。この再配置は、___tls_get_addr () 関数の呼び出しを結合するようリンカーに指示し、call 命令を GD コードシーケンスに関連付けます。
call 命令は、leal 命令の直後に配置する必要があります。この要件は、コード変換を可能にするために必要です。
このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている LD モデルを実装します。
表 8–9 32 ビット x86: Local Dynamic スレッド固有変数のアクセスコード
最初の leal 命令は R_386_TLS_LDM 再配置を生成します。この再配置は、現在のオブジェクトの TLS_index 構造体を保持する領域を GOT に割り当てるように、リンカーに指示します。リンカーは、この新しいリンクテーブルエントリに GOT からの相対オフセットを代入することによって、この再配置を処理します。
読み込みオブジェクトインデックスは実行時まで不明です。したがって、R_386_TLS_DTPMOD32 再配置が作成され、構造体の ti_tlsoffset フィールドにゼロが埋め込まれます。call 命令には、R_386_TLS_LDM_PLT 再配置によってタグが付けられます。
各局所シンボルの TLS オフセットはリンク編集時に認識されるため、リンカーはこれらの値を直接埋め込みます。
手続きが複数の局所シンボルを参照する場合には、コンパイラは TLS ブロックの基底アドレスを取得するコードを 1 度だけ生成します。以後、各シンボルのアドレスの計算にはこの基底アドレスが使用され、個別にライブラリを呼び出すことはありません。
このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている IE モデルを実装します。
IE モデルには 2 つのコードシーケンスが存在します。その 1 つは、GOT ポインタを使用する、位置に依存しないコード用です。もう 1 つのシーケンスは、GOT ポインタを使用しない、位置に依存するコード用です。
表 8–10 32 ビット x86: 位置に依存しない Initial Executable スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
0x00 movl %gs:0, %eax 0x06 addl x@gotntpoff(%ebx), %eax # %eax - contains address of TLS variable |
<none> R_386_TLS_GOTIE |
x |
未処理の再配置 |
シンボル |
|
GOT[n] |
R_386_TLS_TPOFF |
x |
addl 命令は R_386_TLS_GOTIE 再配置を生成します。この再配置は、シンボル x の静的な TLS オフセットを保存する領域を GOT 内に作成するように、リンカーに指示します。このとき、GOT テーブルに対する R_386_TLS_TPOFF 再配置は、未処理の状態に置かれます。あとで、実行時リンカーがシンボル x の静的な TLS オフセットを埋め込みます。
表 8–11 32 ビット x86: 位置に依存する Initial Executable スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
0x00 movl %gs:0, %eax 0x06 addl x@indntpoff, %eax # %eax - contains address of TLS variable |
<none> R_386_TLS_IE |
x |
未処理の再配置 |
シンボル |
|
GOT[n] |
R_386_TLS_TPOFF |
x |
addl 命令は R_386_TLS_IE 再配置を生成します。この再配置は、シンボル x の静的な TLS オフセットを保存する領域を GOT 内に作成するように、リンカーに指示します。このシーケンスと位置に依存しない形式との主な違いは、GOT ポインタレジスタのオフセットを使用せず、作成される GOT エントリに直接、命令が結合されることです。このとき、GOT に対する R_386_TLS_TPOFF 再配置は、未処理の状態に置かれます。あとで、実行時リンカーがシンボル x の静的な TLS オフセットを埋め込みます。
次の 2 つのシーケンスに示すように、メモリー参照にオフセットを直接埋め込むことによって、変数 x の (アドレスではなく) 内容を読み込むことができます。
表 8–12 32 ビット x86: 位置に依存しない Initial Executable 動的スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
0x00 movl x@gotntpoff(%ebx), %eax 0x06 movl %gs:(%eax), %eax # %eax - contains address of TLS variable |
R_386_TLS_GOTIE <none> |
x |
未処理の再配置 |
シンボル |
|
GOT[n] |
R_386_TLS_TPOFF |
x |
表 8–13 32 ビット x86: 位置に依存しない Initial Executable スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
0x00 movl x@indntpoff, %ecx 0x06 movl %gs:(%ecx), %eax # %eax - contains address of TLS variable |
R_386_TLS_IE <none> |
x |
未処理の再配置 |
シンボル |
|
GOT[n] |
R_386_TLS_TPOFF |
x |
最後のシーケンスで、%ecx レジスタではなく %eax レジスタを使用すると、最初の命令は 5 バイト長または 6 バイト長になる可能性があります。
このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている LE モデルを実装します。
表 8–14 32 ビット x86: Local Executable スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
0x00 movl %gs:0, %eax 0x06 leal x@ntpoff(%eax), %eax # %eax - contains address of TLS variable |
<none> R_386_TLS_LE |
x |
movl 命令は R_386_TLS_LE_32 再配置を生成します。リンカーは、実行可能ファイルで定義されたシンボルの静的な TLS オフセットに、この再配置を直接結合します。実行時には処理は不要です。
次の命令シーケンスを使用すると、同じ再配置により変数 x の (アドレスではなく) 内容にアクセスできます。
表 8–15 32 ビット x86: Local Executable スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
0x00 movl %gs:0, %eax 0x06 movl x@ntpoff(%eax), %eax # %eax - contains address of TLS variable |
<none> R_386_TLS_LE |
x |
次のシーケンスを使用すると、変数のアドレスの計算ではなく、その変数からの読み込みやその変数への保存を実行できます。この例では、x@ntpoff による式を即値としてではなく絶対アドレスとして使用しています。
表 8–16 32 ビット x86: Local Executable スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
0x00 movl %gs:x@ntpoff, %eax # %eax - contains address of TLS variable |
R_386_TLS_LE |
x |