JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
リンカーとライブラリ     Oracle Solaris 10 8/11 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

1.  Oracle Solaris リンカーの紹介

2.  リンカー

3.  実行時リンカー

4.  共有オブジェクト

5.  アプリケーションバイナリインタフェースとバージョン管理

6.  サポートインタフェース

7.  オブジェクトファイル形式

8.  スレッド固有領域 (TLS)

C/C++ プログラミングインタフェース

スレッド固有領域 (TLS) セクション

スレッド固有領域の実行時の割り当て

プログラムの起動

スレッドの作成

起動後の動的読み込み

スレッド固有領域ブロックの遅延割り当て

スレッド固有領域のアクセスモデル

SPARC: スレッド固有変数へのアクセス

SPARC: General Dynamic (GD)

SPARC: Local Dynamic (LD)

32 ビット SPARC: Initial Executable (IE)

64 ビット SPARC: Initial Executable (IE)

SPARC: Local Executable (LE)

SPARC: スレッド固有領域の再配置のタイプ

32 ビット x86: スレッド固有変数へのアクセス

32 ビット x86: General Dynamic (GD)

x86: Local Dynamic (LD)

32 ビット x86: Initial Executable (IE)

32 ビット x86: Local Executable (LE)

32 ビット x86: スレッド固有領域の再配置のタイプ

x64: スレッド固有変数へのアクセス

x64: General Dynamic (GD)

x64: Local Dynamic (LD)

x64: Initial Executable (IE)

x64: Local Executable (LE)

x64: スレッド固有領域の再配置のタイプ

9.  mapfile

A.  リンカーのクイックリファレンス

B.  バージョン管理の手引き

C.  動的ストリングトークンによる依存関係の確立

D.  直接結合

E.  System V Release 4 (バージョン 1) Mapfile

F.  リンカーとライブラリのアップデートおよび新機能

索引

スレッド固有領域のアクセスモデル

各 TLS 参照は、次のアクセスモデルのどれかになります。ここでは、もっとも一般的なモデル (しかし最適化の程度はもっとも低い) から順に、もっとも高速なモデル (しかし制限度は高い) へと並んでいます。

General Dynamic (GD) - 動的な TLS

このモデルでは、共有オブジェクトまたは動的実行可能ファイルから、すべての TLS 変数を参照できます。このモデルでは、TLS ブロックが特定のスレッドからはじめて参照される時まで、このブロックの割り当てを延期することもできます。

Local Dynamic (LD) - 局所シンボルの動的な TLS

このモデルは、GD モデルを最適化したものです。コンパイラが、構築されるオブジェクト内で変数がローカルに結合されているか、あるいは保護されていると判断することがあります。この場合、コンパイラは、動的な tlsoffset を静的に結合してこのモデルを使用するように、リンカーに指示します。このモデルにより、GD モデルを上回る性能が得られます。dtv()0,m のアドレスの確認は、関数ごとに tls_get_addr を 1 度呼び出すだけです。リンク編集時に結合される動的な TLS オフセットは、参照ごとに dtv0,m アドレスに追加されます。

Initial Executable (IE) - オフセットが割り当てられた静的な TLS

このモデルは、初期の静的な TLS テンプレートの一部として利用できる TLS 変数だけを参照できます。このテンプレートは、プロセスの起動時に使用できるすべての TLS ブロック、および小規模なバックアップ予約で構成されます。「プログラムの起動」を参照してください。このモデルでは、変数 x の、スレッドポインタからの相対オフセットは、xGOT エントリ内に保存されます。

このモデルでは、初期プロセスの起動後に、遅延読み込み、フィルタ、dlopen(3C) などによって読み込まれる共有ライブラリから、限定された数の TLS 変数を参照できます。このアクセスは、固定のバックアップ予約から満たされます。この予約で提供できるのは、初期化されていない TLS データ項目用の記憶域だけです。柔軟性を最大限高めるため、動的な TLS モデルを使用して、共有オブジェクトがスレッドローカル変数を参照するようにしてください。


注 - フィルタを使用して、静的な TLS の使用を動的に選択できます。共有オブジェクトを、動的な TLS を使用するように構築します。さらに共有オブジェクトを、静的な TLS を使用するために構築された対応物に対する補助フィルタとして動作するよう、構築することができます。静的な TLS オブジェクトの読み込みがリソースにより許可される場合に、そのオブジェクトが使用されます。それ以外の場合、動的な TLS オブジェクトへのフォールバックにより、共有オブジェクトの提供する機能が常に使用可能であることが保証されます。フィルタの詳細については、「フィルタとしての共有オブジェクト」を参照してください。


Local Executable (LE) - 静的な TLS

このモデルは、動的実行可能ファイルの TLS ブロックの一部である TLS 変数だけを参照できます。リンカーは、動的な再配置や GOT の参照を別途行うことなく、スレッドポインタからの相対オフセットを静的に計算します。このモデルを使用して動的実行可能ファイルの外部に存在する変数を参照することはできません。

リンカーは、妥当と判断する場合は、比較的一般的なアクセスモデルから、より最適化されたモデルへとコードを移行できます。この移行は、独特な TLS 再配置を使用することで行えます。これらの再配置は、更新を要求するだけでなく、どの TLS アクセスモデルが使用されているかの特定もします。

作成されるオブジェクトのタイプとともに TLS アクセスモデルを認識することで、リンカーは変換を実行できます。たとえば、GD アクセスモデルを使用している再配置可能オブジェクトが、動的実行可能ファイルにリンクされているとします。この場合、リンカーは IE アクセスモ デルまたは LE アクセスモデルを使用して参照を適宜移行できます。そのあとで、そのモデルに必要な再配置が行われます。

次の図は、それぞれのアクセスモデルと、あるモデルから別のモデルにどのように移行するかを示しています。

図 8-2 スレッド固有領域のアクセスモデルと移行

image:スレッド固有領域のアクセスモデルと移行

SPARC: スレッド固有変数へのアクセス

SPARC では、スレッド固有変数へのアクセスに次のコードシーケンスモデルを使用できます。

SPARC: General Dynamic (GD)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている GD モデルを実装します。

表 8-2 SPARC: General Dynamic スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
# %l7 - initialized to GOT pointer

0x00 sethi %hi(@dtlndx(x)), %o0
0x04 add   %o0, %lo(@dtlndx(x)), %o0
0x08 add   %l7, %o0, %o0
0x0c call  x@TLSPLT

# %o0 - contains address of TLS variable
 
 
R_SPARC_TLS_GD_HI22
R_SPARC_TLS_GD_LO10
R_SPARC_TLS_GD_ADD
R_SPARC_TLS_GD_CALL
 
x
x
x
x
未処理の再配置: 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 再配置を生成します。これらの再配置は、変数 xTLS_index 構造体を保持する領域を GOT 内に割り当てるように、リンカーに指示します。リンカーは、この新しい GOT エントリに GOT からの相対オフセットを代入することによって、この再配置を処理します。

読み込みオブジェクトインデックスと x の TLS ブロックインデックスは実行時まで不明です。したがって、リンカーは、実行時リンカーによって処理されるように、GOT に対する R_SPARC_TLS_DTPMOD32 再配置と R_SPARC_TLS_DPTOFF32 再配置を設定します。

2 番目の add 命令は、R_SPARC_TLS_GD_ADD 再配置を生成します。この再配置が使用されるのは、リンカーによって GD コードシーケンスがほかのシーケンスに変更される場合だけです。

call 命令は特別な構文である x@TLSPLT を使用します。この call 命令は TLS 変数を参照し、R_SPARC_TLS_GD_CALL 再配置を生成します。この再配置は、__tls_get_addr() 関数の呼び出しを結合するようリンカーに指示し、call 命令を GD コードシーケンスに関連付けます。


注 - add 命令は、call 命令の前に指定する必要があります。add 命令を、呼び出しの遅延スロットに配置することはできません。これは、あとで発生するコード変換が既知の順序を必要とするためです。

R_SPARC_TLS_GD_ADD 再配置によってタグが付けられた add 命令の GOT ポインタとして使用されるレジスタは、add 命令内の最初のレジスタでなければなりません。このように指定することで、リンカーはコード変換時に GOT ポインタであるレジスタを識別できるようになります。


SPARC: Local Dynamic (LD)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている LD モデルを実装します。

表 8-3 SPARC: Local Dynamic スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
# %l7 - initialized to GOT pointer

0x00 sethi %hi(@tmndx(x1)), %o0
0x04 add   %o0, %lo(@tmndx(x1)), %o0
0x08 add   %l7, %o0, %o0
0x0c call  x@TLSPLT

# %o0 - contains address of TLS block of current object

0x10 sethi %hi(@dtpoff(x1)), %l1
0x14 xor   %l1, %lo(@dtpoff(x1)), %l1
0x18 add   %o0, %l1, %l1

# %l1 - contains address of local TLS variable x1

0x20 sethi %hi(@dtpoff(x2)), %l2
0x24 xor   %l2, %lo(@dtpoff(x2)), %l2
0x28 add   %o0, %l2, %l2

# %l2 - contains address of local TLS variable x2
 
 
R_SPARC_TLS_LDM_HI22
R_SPARC_TLS_LDM_LO10
R_SPARC_TLS_LDM_ADD
R_SPARC_TLS_LDM_CALL
 
 
 
R_SPARC_TLS_LDO_HIX22
R_SPARC_TLS_LDO_LOX10
R_SPARC_TLS_LDO_ADD
 
 
 
R_SPARC_TLS_LDO_HIX22
R_SPARC_TLS_LDO_LOX10
R_SPARC_TLS_LDO_ADD
 
 
x1
x1
x1
x1
 
 
 
x1
x1
x1
 
 
 
x2
x2
x2
未処理の再配置: 32 ビット
シンボル
GOT[n]
GOT[n + 1]
R_SPARC_TLS_DTPMOD32
<none>
x1
未処理の再配置: 64 ビット
シンボル
GOT[n]
GOT[n + 1]
R_SPARC_TLS_DTPMOD64
<none>
x1

最初の sethi 命令は R_SPARC_TLS_LDM_HI22 再配置を生成し、add 命令は R_SPARC_TLS_LDM_LO10 再配置を生成します。これらの再配置は、現在のオブジェクトの TLS_index 構造体を保持する領域を GOT に割り当てるように、リンカーに指示します。リンカーは、この新しい 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 再配置を生成し、xor 命令は R_SPARC_TLS_LDO_LOX10 再配置を生成します。各局所シンボルの TLS オフセットはリンク編集時に認識されるため、これらの値は直接埋め込まれます。add 命令には、R_SPARC_TLS_LDO_ADD 再配置によってタグが付けられます。

手続きが複数の局所シンボルを参照する場合には、コンパイラは TLS ブロックの基底アドレスを取得するコードを 1 度だけ生成します。以後、各シンボルのアドレスの計算にはこの基底アドレスが使用され、個別にライブラリを呼び出すことはありません。


注 - R_SPARC_TLS_LDO_ADD によってタグが付けられた add 命令内の TLS オブジェクトアドレスが入ったレジスタは、命令シーケンス内の最初のレジスタでなければなりません。このように指定することで、リンカーはコード変換時にレジスタを識別できるようになります。


32 ビット SPARC: Initial Executable (IE)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている IE モデルを実装します。

表 8-4 32 ビット SPARC: Initial Executable スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
# %l7 - initialized to GOT pointer, %g7 - thread pointer

0x00 sethi %hi(@tpoff(x)), %o0
0x04 or    %o0, %lo(@tpoff(x)), %o0
0x08 ld    [%l7 + %o0], %o0
0x0c add   %g7, %o0, %o0
 
# %o0 - contains address of TLS variable
 
 
R_SPARC_TLS_IE_HI22
R_SPARC_TLS_IE_LO10
R_SPARC_TLS_IE_LD
R_SPARC_TLS_IE_ADD
 
 
x
x
x
x
未処理の再配置
シンボル
GOT[n]
R_SPARC_TLS_TPOFF32
x

sethi 命令は R_SPARC_TLS_IE_HI22 再配置を生成し、or 命令は R_SPARC_TLS_IE_LO10 再配置を生成します。これらの再配置は、シンボル x の静的な TLS オフセットを保存する領域を GOT 内に作成するように、リンカーに指示します。実行時リンカーがシンボル x の負の静的 TLS オフセットを埋め込むよう、GOT に対する R_SPARC_TLS_TPOFF32 の再配置は、未処理の状態に置かれます。ld 命令には R_SPARC_TLS_IE_LD 再配置によってタグが付けられ、add 命令には R_SPARC_TLS_IE_ADD 再配置によってタグが付けられます。


注 - R_SPARC_TLS_IE_ADD 再配置によってタグが付けられた add 命令の GOT ポインタとして使用されるレジスタは、この命令内の最初のレジスタでなければなりません。このように指定することで、リンカーはコード変換時に GOT ポインタであるレジスタを識別できるようになります。


64 ビット SPARC: Initial Executable (IE)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている IE モデルを実装します。

表 8-5 64 ビット SPARC: Initial Executable スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
# %l7 - initialized to GOT pointer, %g7 - thread pointer

0x00 sethi %hi(@tpoff(x)), %o0
0x04 or    %o0, %lo(@tpoff(x)), %o0
0x08 ldx   [%l7 + %o0], %o0
0x0c add   %g7, %o0, %o0
 
# %o0 - contains address of TLS variable
 
 
R_SPARC_TLS_IE_HI22
R_SPARC_TLS_IE_LO10
R_SPARC_TLS_IE_LD
R_SPARC_TLS_IE_ADD
 
 
x
x
x
x
未処理の再配置
シンボル
GOT[n]
R_SPARC_TLS_TPOFF64
x

SPARC: Local Executable (LE)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている LE モデルを実装します。

表 8-6 SPARC: Local Executable スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
# %g7 - thread pointer

0x00 sethi %hix(@tpoff(x)), %o0
0x04 xor   %o0,%lo(@tpoff(x)),%o0
0x08 add   %g7, %o0, %o0
 
# %o0 - contains address of TLS variable
 
 
R_SPARC_TLS_LE_HIX22
R_SPARC_TLS_LE_LOX10
<none>
 
 
x
x

sethi 命令は R_SPARC_TLS_LE_HIX22 再配置を生成し、xor 命令は R_SPARC_TLS_LE_LOX10 再配置を生成します。リンカーは、実行可能ファイルで定義されたシンボルの静的な TLS オフセットに、これらの再配置を直接結合します。実行時には、再配置処理は不要です。

SPARC: スレッド固有領域の再配置のタイプ

次の表に、SPARC 用に定義された TLS 再配置を示します。表内の説明では、次の表記が使用されています。

@dtlndx(x)
TLS_index 構造体を保持するために、GOT 内に連続した 2 つのエントリを割り当てます。この情報は、__tls_get_addr() に渡されます。このエントリを参照する命令は、2 つの GOT エントリのうちの最初のエントリのアドレスに結合されます。
@tmndx(x)

TLS_index 構造体を保持するために、GOT 内に連続した 2 つのエントリを割り当てます。この情報は、__tls_get_addr() に渡されます。この構造体の ti_tlsoffset フィールドは 0 に設定され、ti_moduleid は実行時に埋め込まれます。__tls_get_addr () 呼び出しは、動的な TLS ブロックの開始オフセットを返します。

@dtpoff(x)

TLS ブロックからの相対 tlsoffset を計算します。

@tpoff(x)

静的な TLS ブロックからの負の相対 tlsoffset を計算します。この値は、TLS アドレスを計算するためにスレッドポインタに追加されます。

@dtpmod(x)

TLS シンボルを含むオブジェクトの識別子を計算します。

表 8-7 SPARC: スレッド固有領域の再配置のタイプ

名前
フィールド
計算
R_SPARC_TLS_GD_HI22
56
T-simm22
@dtlndx(S + A) >> 10
R_SPARC_TLS_GD_LO10
57
T-simm13
@dtlndx(S + A) & 0x3ff
R_SPARC_TLS_GD_ADD
58
なし
この表のあとの説明を参照してください。
R_SPARC_TLS_GD_CALL
59
V-disp30
この表のあとの説明を参照してください。
R_SPARC_TLS_LDM_HI22
60
T-simm22
@tmndx(S + A) >> 10
R_SPARC_TLS_LDM_LO10
61
T-simm13
@tmndx(S + A) & 0x3ff
R_SPARC_TLS_LDM_ADD
62
なし
この表のあとの説明を参照してください。
R_SPARC_TLS_LDM_CALL
63
V-disp30
この表のあとの説明を参照してください。
R_SPARC_TLS_LDO_HIX22
64
T-simm22
@dtpoff(S + A) >> 10
R_SPARC_TLS_LDO_LOX10
65
T-simm13
@dtpoff(S + A) & 0x3ff
R_SPARC_TLS_LDO_ADD
66
なし
この表のあとの説明を参照してください。
R_SPARC_TLS_IE_HI22
67
T-simm22
@got(@tpoff(S + A)) >> 10
R_SPARC_TLS_IE_LO10
68
T-simm13
@got(@tpoff(S + A)) & 0x3ff
R_SPARC_TLS_IE_LD
69
なし
この表のあとの説明を参照してください。
R_SPARC_TLS_IE_LDX
70
なし
この表のあとの説明を参照してください。
R_SPARC_TLS_IE_ADD
71
なし
この表のあとの説明を参照してください。
R_SPARC_TLS_LE_HIX22
72
T-imm22
(@tpoff(S + A) ^0xffffffffffffffff) >> 10
R_SPARC_TLS_LE_LOX10
73
T-simm13
(@tpoff(S + A) & 0x3ff) | 0x1c00
R_SPARC_TLS_DTPMOD32
74
V-word32
@dtpmod(S + A)
R_SPARC_TLS_DTPMOD64
75
V-word64
@dtpmod(S + A)
R_SPARC_TLS_DTPOFF32
76
V-word32
@dtpoff(S + A)
R_SPARC_TLS_DTPOFF64
77
V-word64
@dtpoff(S + A)
R_SPARC_TLS_TPOFF32
78
V-word32
@tpoff(S + A)
R_SPARC_TLS_TPOFF64
79
V-word64
@tpoff(S + A)

いくつかの再配置型には、単純な計算を超えたセマンティクスが存在します。

R_SPARC_TLS_GD_ADD

この再配置は、GD コードシーケンスの add 命令にタグを付けます。GOT ポインタに使用されるレジスタは、シーケンス内の最初のレジスタです。この再配置によってタグが付けられる命令は、R_SPARC_TLS_GD_CALL 再配置によってタグが付けられる call 命令の前に置かれます。この再配置は、リンク編集時に TLS モデルを移行するために使用されます。

R_SPARC_TLS_GD_CALL

この再配置は、__tls_get_addr() 関数を参照する R_SPARC_WPLT30 再配置と同じように処理されます。この再配置は、 GD コードシーケンスの一部です。

R_SPARC_LDM_ADD

この再配置は、LD コードシーケンスの最初の add 命令にタグを付けます。GOT ポインタに使用されるレジスタは、シーケンス内の最初のレジスタです。この再配置によってタグが付けられる命令は、R_SPARC_TLS_GD_CALL 再配置によってタグが付けられる call 命令の前に置かれます。この再配置は、リンク編集時に TLS モデルを移行するために使用されます。

R_SPARC_LDM_CALL

この再配置は、__tls_get_addr() 関数を参照する R_SPARC_WPLT30 再配置と同じように処理されます。この再配置は、LD コードシーケンスの一部です。

R_SPARC_LDO_ADD

この再配置は、LD コードシーケンス内の最後の add 命令にタグを付けます。コードシーケンスの先頭で計算されるオブジェクトアドレスを含むレジスタは、この命令における最初のレジスタです。この再配置により、リンカーはコード変換時にレジスタを識別できるようになります。

R_SPARC_TLS_IE_LD

この再配置は、32 ビットの IE コードシーケンス内の ld 命令にタグを付けます。この再配置は、リンク編集時に TLS モデルを移行するために使用されます。

R_SPARC_TLS_IE_LDX

この再配置は、64 ビットの IE コードシーケンス内の ldx 命令にタグを付けます。この再配置は、リンク編集時に TLS モデルを移行するために使用されます。

R_SPARC_TLS_IE_ADD

この再配置は、IE コードシーケンス内の add 命令にタグを付けます。GOT ポインタに使用されるレジスタは、シーケンス内の最初のレジスタです。

32 ビット x86: スレッド固有変数へのアクセス

x86 では、TLS へのアクセスに次のコードシーケンスモデルを使用できます。

32 ビット x86: General Dynamic (GD)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている GD モデルを実装します。

表 8-8 32 ビット x86: General Dynamic スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
0x00 leal  x@tlsgd(,%ebx,1), %eax
0x07 call  x@tlsgdplt

# %eax - contains address of TLS variable
R_386_TLS_GD
R_386_TLS_GD_PLT
x
x
未処理の再配置
シンボル
GOT[n]
GOT[n + 1]
R_386_TLS_DTPMOD32
R_386_TLS_DTPOFF32
x

leal 命令は R_386_TLS_GD 再配置を生成します。この再配置は、変数 xTLS_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 命令の直後に配置する必要があります。この要件は、コード変換を可能にするために必要です。

x86: Local Dynamic (LD)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている LD モデルを実装します。

表 8-9 32 ビット x86: Local Dynamic スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
0x00 leal  x1@tlsldm(%ebx), %eax
0x06 call  x1@tlsldmplt

# %eax - contains address of TLS block of current object

0x10 leal  x1@dtpoff(%eax), %edx

# %edx - contains address of local TLS variable x1

0x20 leal  x2@dtpoff(%eax), %edx

# %edx - contains address of local TLS variable x2
R_386_TLS_LDM
R_386_TLS_LDM_PLT
 
 
 
R_386_TLS_LDO_32
 
 
 
R_386_TLS_LDO_32
x1
x1
 
 
 
x1
 
 
 
x2
未処理の再配置
シンボル
GOT[n]
GOT[n + 1]
R_386_TLS_DTPMOD32
<none>
x

最初の leal 命令は R_386_TLS_LDM 再配置を生成します。この再配置は、現在のオブジェクトの TLS_index 構造体を保持する領域を GOT に割り当てるように、リンカーに指示します。リンカーは、この新しいリンクテーブルエントリに GOT からの相対オフセットを代入することによって、この再配置を処理します。

読み込みオブジェクトインデックスは実行時まで不明です。したがって、R_386_TLS_DTPMOD32 再配置が作成され、構造体の ti_tlsoffset フィールドにゼロが埋め込まれます。call 命令には、R_386_TLS_LDM_PLT 再配置によってタグが付けられます。

各局所シンボルの TLS オフセットはリンク編集時に認識されるため、リンカーはこれらの値を直接埋め込みます。

手続きが複数の局所シンボルを参照する場合には、コンパイラは TLS ブロックの基底アドレスを取得するコードを 1 度だけ生成します。以後、各シンボルのアドレスの計算にはこの基底アドレスが使用され、個別にライブラリを呼び出すことはありません。

32 ビット x86: Initial Executable (IE)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている 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 バイト長になる可能性があります。

32 ビット x86: Local Executable (LE)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている 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

32 ビット x86: スレッド固有領域の再配置のタイプ

次の表に、x86 用に定義された TLS 再配置を示します。表内の説明では、次の表記が使用されています。

@tlsgd(x)
TLS_index 構造体を保持するために、GOT 内に連続した 2 つのエントリを割り当てます。この構造体は、___tls_get_addr() に渡されます。このエントリを参照する命令は、2 つの GOT エントリのうちの最初のエントリに結合されます。
@tlsgdplt(x)

この再配置は、___tls_get_addr() 関数を参照する R_386_PLT32 再配置と同じように処理されます。

@tlsldm(x)

TLS_index 構造体を保持するために、GOT 内に連続した 2 つのエントリを割り当てます。この構造体は、___tls_get_addr() に渡されます。TLS_indexti_tlsoffset フィールドは 0 に設定され、ti_moduleid は実行時に埋められます。___tls_get_addr() 呼び出しは、動的な TLS ブロックの開始オフセットを返します。

@gotntpoff(x)

GOT に 1 つのエントリを割り当ててから、静的な TLS ブロックからの負の相対 tlsoffset を使用してこのエントリを初期化します。このシーケンスは、R_386_TLS_TPOFF 再配置を使用して実行時に行われます。

@indntpoff(x)

この式は @gotntpoff に似ていますが、位置に依存するコードで使用されます。@gotntpoff は、movl 命令内または addl 命令内の GOT の先頭からの相対 GOT スロットアドレスに解決されます。@indntpoff は、絶対 GOT スロットアドレスに解決されます。

@ntpoff(x)

静的な TLS ブロックからの負の相対 tlsoffset を計算します。

@dtpoff(x)

TLS ブロックからの相対 tlsoffset を計算します。この値は加数の即値として使用され、特定のレジスタには関連付けられません。

@dtpmod(x)

TLS シンボルを含むオブジェクトの識別子を計算します。

表 8-17 32 ビット x86: スレッド固有領域の再配置のタイプ

名前
フィールド
計算
R_386_TLS_GD_PLT
12
Word32
@tlsgdplt
R_386_TLS_LDM_PLT
13
Word32
@tlsldmplt
R_386_TLS_TPOFF
14
Word32
@ntpoff(S)
R_386_TLS_IE
15
Word32
@indntpoff(S)
R_386_TLS_GOTIE
16
Word32
@gotntpoff(S)
R_386_TLS_LE
17
Word32
@ntpoff(S)
R_386_TLS_GD
18
Word32
@tlsgd(S)
R_386_TLS_LDM
19
Word32
@tlsldm(S)
R_386_TLS_LDO_32
32
Word32
@dtpoff(S)
R_386_TLS_DTPMOD32
35
Word32
@dtpmod(S)
R_386_TLS_DTPOFF32
36
Word32
@dtpoff(S)

x64: スレッド固有変数へのアクセス

x64 では、TLS へのアクセスに次のコードシーケンスモデルを使用できます。

x64: General Dynamic (GD)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている GD モデルを実装します。

表 8-18 x64: General Dynamic スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
0x00 .byte 0x66
0x01 leaq  x@tlsgd(%rip), %rdi
0x08 .word 0x666
0x0a rex64
0x0b call  __tls_get_addr@plt

# %iax - contains address of TLS variable
<none>
R_AMD64_TLSGD
<none>
<none>
R_AMD64_PLT32
 
x


__tls_get_addr
未処理の再配置
シンボル
GOT[n]
GOT[n + 1]
R_AMD64_DTPMOD64
R_AMD64_DTPOFF64
x
x

__tls_get_addr() 関数は、tls_index 構造体のアドレスという 1 つのパラメータを取ります。x@tlsgd(%rip) による式と関連付けられた R_AMD64_TLSGD 再配置は、tls_index 構造体を GOT 内で割り当てるように、リンカーに指示します。tls_index 構造体で必要な 2 つの要素は、連続する GOT エントリである GOT[n] および GOT[n+1] で保持されます。これらの GOT エントリは、R_AMD64_DTPMOD64 再配置と R_AMD64_DTPOFF64 再配置に関連付けられます。

アドレス 0x00 の命令は、最初の GOT エントリのアドレスを計算します。この計算により、リンク編集時に明らかになる GOT の最初の PC 相対アドレスが現在の命令のポインタに追加されます。結果は、%rdi レジスタを使用して __tls_get_addr() 関数に渡されます。


注 - leaq 命令は、最初の GOT エントリのアドレスを計算します。この計算は、リンク編集時に決定された GOT の PC 相対アドレスを現在の命令のポインタに追加して行われます。.byte.word、および .rex64 接頭辞によって、命令シーケンス全体で 16 バイトを占めることが確実になります。接頭辞が使用されるのは、コードに悪影響を及ぼすことがないからです。


x64: Local Dynamic (LD)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている LD モデルを実装します。

表 8-19 x64: Local Dynamic スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
0x00 leaq  x1@tlsld(%rip), %rdi
0x07 call  __tls_get_addr@plt

# %rax - contains address of TLS block

0x10 leaq  x1@dtpoff(%rax), %rcx

# %rcx - contains address of TLS variable x1

0x20 leaq  x2@dtpoff(%rax), %r9

# %rcx - contains address of TLS variable x2
R_AMD64_TLSLD
R_AMD64_PLT32
 


R_AMD64_DTOFF32
 


R_AMD64_DTOFF32
x1
__tls_get_addr



 
x1


 
x2
未処理の再配置
シンボル
GOT[n]
R_AMD64_DTMOD64
x1

最初の 2 つの命令は、パッドはありませんが、一般的な動的モデルに使用されるコードシーケンスと同じです。2 つの命令は必ず連続させてください。x1@tlsld(%rip) シーケンスは、シンボル x1tls_index エントリを生成します。このインデックスはオフセットがゼロ の x1 を含む現在のモジュールを参照します。リンカーは、オブジェクト R_AMD64_DTMOD64 の再配置を作成します。

オフセットは別々に読み込まれるので、R_AMD64_DTOFF32 再配置は不要です。x1@dtpoff による式は、シンボル x1 のオフセットにアクセスするために使用されます。この命令をアドレス 0x10 として使用して、完全なオフセットが読み込まれ %rax() 内の __tls_get_addr 呼び出しの結果に追加されて結果が %rcx に生成されます。x1@dtpoff による式は、R_AMD64_DTPOFF32 再配置を作成します。

次の命令を使用すると、変数のアドレスを計算するのではなく、変数の値を読み込むことができます。この命令は、元の leaq 命令と同じ再配置を作成します。

movq  x1@dtpoff(%rax), %r11

TLS ブロックのベースアドレスがレジスタ内で保持されていると、保護されているスレッド固有変数のアドレスの読み込み、保存、または計算には 1 つの命令が必要となります。

固有の動的モデルを使用した場合には、一般的な動的モデルを使用した場合よりも利点があります。すべての追加スレッド固有変数アクセスに必要なのは、3 つの新しい命令だけです。さらに、GOT エントリの追加や実行時の再配置は必要ありません。

x64: Initial Executable (IE)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている IE モデルを実装します。

表 8-20 x64: Initial Executable スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
0x00 movq  %fs:0, %rax
0x09 addq  x@gottpoff(%rip), %rax

# %rax - contains address of TLS variable
<none>
R_AMD64_GOTTPOFF
 
x
未処理の再配置
シンボル
GOT[n]
R_AMD64_TPOFF64
x

シンボル xR_AMD64_GOTTPOFF 再配置は、リンカーに GOT エントリおよび関連する R_AMD64_TPOFF64 再配置の生成を要求します。その後、この命令は x@gottpoff(%rip) 命令の最後からの GOT エントリの相対オフセットを使用します。R_AMD64_TPOFF64 再配置は、現在読み込まれているモジュールから決定されるシンボル x の値を使用します。オフセットは GOT エントリに書き込まれたあとで、addq 命令によって読み込まれます。

x のアドレスではなく x の内容を読み込む場合は、次のシーケンスを使用できます。

表 8-21 x64: Initial Executable スレッド固有変数のアクセスコード II

コードシーケンス
初期の再配置
シンボル
0x00 movq  x@gottpoff(%rip), %rax
0x07 movq  %fs:(%rax), %rax

# %rax - contains contents of TLS variable
R_AMD64_GOTTPOFF
<none>
x
未処理の再配置
シンボル
GOT[n]
R_AMD64_TPOFF64
x

x64: Local Executable (LE)

このコードシーケンスは、「スレッド固有領域のアクセスモデル」で説明されている LE モデルを実装します。

表 8-22 x64: Local Executable スレッド固有変数のアクセスコード

コードシーケンス
初期の再配置
シンボル
0x00 movq  %fs:0, %rax
0x09 leaq  x@tpoff(%rax), %rax

# %rax - contains address of TLS variable
<none>
R_AMD64_TPOFF32
x

TLS 変数のアドレスではなく TLS 変数の内容を読み込む場合は、次のシーケンスを使用できます。

表 8-23 x64: Local Executable スレッド固有変数のアクセスコード II

コードシーケンス
初期の再配置
シンボル
0x00 movq  %fs:0, %rax
0x09 movq  x@tpoff(%rax), %rax

# %rax - contains contents of TLS variable
<none>
R_AMD64_TPOFF32
x

次のシーケンスはより短いものです。

表 8-24 x64: Local Executable スレッド固有変数のアクセスコード III

コードシーケンス
初期の再配置
シンボル
0x00 movq  %fs:x@tpoff, %rax

# %rax - contains contents of TLS variable
R_AMD64_TPOFF32
x

x64: スレッド固有領域の再配置のタイプ

次の表に、x64 用に定義された TLS 再配置を示します。表内の説明では、次の表記が使用されています。

@tlsgd(%rip)
TLS_index 構造体を保持するために、GOT 内に連続した 2 つのエントリを割り当てます。この構造体は、__tls_get_addr() に渡されます。この命令は、正確で一般的な動的コードシーケンス内でのみ使用できます。
@tlsld(%rip)

TLS_index 構造体を保持するために、GOT 内に連続した 2 つのエントリを割り当てます。この構造体は、__tls_get_addr() に渡されます。実行時、オブジェクトの ti_offset オフセットフィールドは ゼロに設定され、ti_module オフセットは初期化されます。__tls_get_addr() 関数の呼び出しは、動的な TLS ブロックの開始オフセットを返します。この命令は、正確なコードシーケンス内で使用できます。

@dtpoff

変数を含む TLS ブロックの最初からの変数の相対オフセットを計算します。計算値は加数の即値として使用され、特定のレジスタには関連付けられません。

@dtpmod(x)

TLS シンボルを含むオブジェクトの識別子を計算します。

@gottpoff(%rip)

最初の TLS ブロック内の変数のオフセットを保持する GOT 内のエントリを割り当てます。このオフセットは TLS ブロックの端、%fs:0 から計算されます。この演算子は、movq または addq 命令とだけ使用できます。

@tpoff(x)

TLS ブロックの端、%fs:0 からの変数の相対オフセットを計算します。GOT エントリは作成されません。

表 8-25 x64: スレッド固有領域の再配置のタイプ

名前
フィールド
計算
R_AMD64_DPTMOD64
16
Word64
@dtpmod(s)
R_AMD64_DTPOFF64
17
Word64
@dtpoff(s)
R_AMD64_TPOFF64
18
Word64
@tpoff(s)
R_AMD64_TLSGD
19
Word32
@tlsgd(s)
R_AMD64_TLSLD
20
Word32
@tlsld(s)
R_AMD64_DTPOFF32
21
Word32
@dtpoff(s)
R_AMD64_GOTTPOFF
22
Word32
@gottpoff(s)
R_AMD64_TPOFF32
23
Word32
@gottpoff(s)