SPARC では、スレッド固有変数へのアクセスに以下のコードシーケンスモデルを使用できます。
このコードシーケンスはもっとも一般的であり、共有オブジェクトと動的実行可能ファイルのどちらでも使用できます。このコードシーケンスは、共有オブジェクト内および動的実行可能ファイル内の外部 TLS 変数も参照できます。
表 8–2 SPARC: 32 ビットおよび 64 ビットの General Dynamic スレッド固有変数のアクセスコード
未処理の再配置: 32 ビット |
シンボル |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD32 R_SPARC_TLS_DTPOFF32 |
x x |
未処理の再配置: 64 ビット |
シンボル |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD64 R_SPARC_TLS_DTPOFF64 |
x x |
sethi 命令は R_SPARC_TLS_GD_HI22 再配置を生成し、add 命令は R_SPARC_TLS_GD_LO10 再配置を生成します。これらの再配置は、変数 x への TLS_index 構造体を保持する領域を大域オフセットテーブル内に割り当てるように、リンカーに指示します。リンカーは、この新しい GOT エントリに GOT からの相対オフセットを代入することによって、この再配置を処理します。
読み込みオブジェクトインデックスと x の TLS ブロックインデックスは実行時まで不明なため、リンカーは、実行時リンカーによって処理されるように、GOT に対する R_SPARC_TLS_DTPMOD32 再配置と R_SPARC_TLS_DPTOFF32 再配置を設定します。
add 命令は、R_SPARC_TLS_GD_ADD 再配置を生成します。この再配置が使用されるのは、リンカーによって GD コードシーケンスがほかのシーケンスに変更される場合だけです。
call 命令は、R_SPARC_TLS_GD_CALL 再配置を生成します。この再配置は、__tls_get_addr () 関数の呼び出しを結合するようリンカーに指示し、call 命令を GD コードシーケンスに関連付けます。
add 命令は、call 命令の前に指定する必要があります。この命令を、呼び出しの遅延スロットに配置することはできません。これは、あとで発生するコード変換が既知の順序を必要とするためです。
R_SPARC_TLS_GD_ADD 再配置によってタグが付けられた add 命令の GOT ポインタとして使用されるレジスタは、add 命令内の最初のレジスタでなければなりません。このように指定することで、リンカーはコード変換時に GOT ポインタであるレジスタを識別できるようになります。
このコードシーケンスは、共有オブジェクトまたは動的実行可能ファイルで使用できます。このシーケンスは、参照として同じオブジェクト内に結合された TLS 変数を参照する場合に使用します。動的な tlsoffset はリンク編集時に結合が可能なため、__tls_get_addr() の呼び出しは LD コードシーケンスを介して参照されるすべてのシンボルの関数呼び出しごとに 1 回だけですみます。
表 8–3 SPARC: 32 ビットおよび 64 ビットの Local Dynamic スレッド固有変数のアクセスコード
未処理の再配置: 32 ビット |
シンボル |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD32 <なし> |
x1 |
未処理の再配置: 64 ビット |
シンボル |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD64 <なし> |
x1 |
最初の sethi 命令は R_SPARC_TLS_LDM_HI22 再配置を生成し、add 命令は R_SPARC_TLS_LDM_LO10 再配置を生成します。これらの再配置は、現在のオブジェクトのTLS_index 構造体を保持する領域を大域オフセットテーブル内に割り当てるように、リンカーに指示します。リンカーは、この新しい GOT エントリに GOT からの相対オフセットを代入することによって、この再配置を処理します。
読み込みオブジェクトインデックスは実行時まで認識されないため、R_SPARC_TLS_DTPMOD32 再配置が作成され、TLS_index 構造体の ti_tlsoffset フィールドにゼロが埋め込まれます。
2 つめの add 命令には R_SPARC_TLS_LDM_ADD 再配置によってタグが付けられ、call 命令には R_SPARC_TLS_LDM_CALL 再配置によってタグが付けられます。
以降の sethi 命令は R_SPARC_LDO_HIX22 再配置を生成し、or 命令は R_SPARC_TLS_LDO_LOX10 再配置を生成します。各ローカルシンボルの TLS オフセットはリンク編集時に認識されるため、これらの値は直接埋め込まれます。add 命令には、R_SPARC_TLS_LDO_ADD 再配置によってタグが付けられます。
手続きが複数のローカルシンボルを参照する場合には、コンパイラは TLS ブロックの基底アドレスを 1 度だけ取得するコードを生成します。以後、各シンボルのアドレスの計算にはこの基底アドレスが使用され、個別にライブラリを呼び出すことはありません。
R_SPARC_TLS_LDO_ADD によってタグが付けられた add 命令内の TLS オブジェクトアドレスが入ったレジスタは、命令シーケンス内の最初のレジスタでなければなりません。このように指定することで、リンカーはコード変換時にレジスタを識別できるようになります。
このコードシーケンスは、動的実行可能ファイルでのみ使用できます。このモデルは、その実行可能ファイル内、またはプロセスの起動時に読み込まれる任意の共有ライブラリ内で定義された TLS 変数を参照できます。このモデルでは、プロセスの起動後に読み込まれる共有ライブラリ内の TLS 変数を参照することはできません。
表 8–4 SPARC: 32 ビットの Initial Executable スレッド固有変数のアクセスコード
未処理の再配置 |
シンボル |
|
---|---|---|
GOT[n] |
R_SPARC_TLS_TPOFF32 |
x |
sethi 命令は R_SPARC_TLS_IE_HI22 再配置を生成し、or 命令は R_SPARC_TLS_IE_LO10 再配置を生成します。これらの再配置は、シンボル x の静的な TLS オフセットを保存する領域を大域オフセットテーブル内に作成するように、リンカーに指示します。このとき、GOT に対する R_SPARC_TLS_TPOFF32 の再配置は、未処理の状態に置かれます。あとで、実行時リンカーがシンボル x の負の静的 TLS オフセットを埋め込みます。ld 命令には R_SPARC_TLS_IE_LD 再配置によってタグが付けられ、add 命令には R_SPARC_TLS_IE_ADD 再配置によってタグが付けられます。
R_SPARC_TLS_IE_ADD 再配置によってタグが付けられた add 命令の GOT ポインタとして使用されるレジスタは、この命令内の最初のレジスタでなければなりません。このように指定することで、リンカーはコード変換時に GOT ポインタであるレジスタを識別できるようになります。
このシーケンスは、ld 命令ではなく ldx 命令を使用して 64 ビットアドレスを読み込んでいる点を除き、SPARC 32 ビットシーケンスと同じです。
表 8–5 SPARC: 64 ビットの Initial Executable スレッド固有変数のアクセスコード
未処理の再配置 |
シンボル |
|
---|---|---|
GOT[n] |
R_SPARC_TLS_TPOFF64 |
x |
このコードシーケンスは、動的実行可能ファイル内から、同じファイル内で定義された TLS 変数を参照するためにのみ使用できます。この場合、静的な tlsoffset はリンク編集時に認識され、実行時の再配置は不要です。
表 8–6 SPARC: 32 ビットおよび 64 ビットの Local Executable スレッド固有変数のアクセスコード
コードシーケンス |
初期の再配置 |
シンボル |
---|---|---|
0x00 sethi %hix(@tpoff(x)), %o0 0x04 xor %o0,%lo(@tpoff(x)),%o0 0x08 add %g7, %o0, %o0 # %o0 - TLS 変数のアドレスが含まれる |
R_SPARC_TLS_LE_HIX22 R_SPARC_TLS_LE_LOX10 <なし> |
x x |
sethi 命令は R_SPARC_TLS_LE_HIX22 再配置を生成し、or 命令は R_SPARC_TLS_LE_LOX10 再配置を生成します。リンカーは、実行可能ファイルで定義されたシンボルの静的な TLS オフセットに、これらの再配置を直接結合します。実行時には、再配置処理は不要です。