SPARC: 线程局部变量访问
在 SPARC 上,可使用以下代码序列模型访问线程局部变量。
SPARC: 常规动态 (General Dynamic, GD)
此代码序列实现线程局部存储的访问模型中介绍的 GD 模型。
表 14-2 SPARC: 常规动态的线程局部变量访问代码代码序列
| 初始重定位
| 符号
|
# %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 和 add 指令分别生成 R_SPARC_TLS_GD_HI22 和 R_SPARC_TLS_GD_LO10 重定位。这些重定位将指示链接编辑器在 GOT 中分配空间,以存储变量 x 的 TLS_index 结构。链接编辑器通过以相对于 GOT 的偏移替代新的 GOT 项来处理此重定位。
x 的装入目标文件索引和 TLS 块索引在运行前无法确定。因此,链接编辑器将根据 GOT 来放置 R_SPARC_TLS_DTPMOD32 和 R_SPARC_TLS_DPTOFF32 重定位,以供运行时链接程序处理。
第二个 add 指令将生成 R_SPARC_TLS_GD_ADD 重定位。仅当链接编辑器将 GD 代码序列更改为另一个序列时,才会使用此重定位。
call 指令使用特殊的语法 x@TLSPLT。此调用引用 TLS 变量,并生成 R_SPARC_TLS_GD_CALL 重定位。此重定位指示链接编辑器将调用绑定到 __tls_get_addr() 函数,并将 call 指令与 GD 代码序列关联。
注 - add 指令必须出现在
call 指令前面。
add 指令不能放在调用的延迟槽中。由于后面可能发生的代码变换需要已知顺序,所以必须满足此要求。
用作 add 指令(由 R_SPARC_TLS_GD_ADD 重定位标记)的 GOT 指针的寄存器必须是 add 指令中的第一个寄存器。在代码变换期间,此要求允许链接编辑器标识 GOT 指针寄存器。
SPARC: 局部动态 (Local Dynamic, LD)
此代码序列实现线程局部存储的访问模型中介绍的 LD 模型。
表 14-3 SPARC: 局部动态的线程局部变量访问代码代码序列
| 初始重定位
| 符号
|
# %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 指令和 add 指令分别生成 R_SPARC_TLS_LDM_HI22 和 R_SPARC_TLS_LDM_LO10 重定位。这些重定位指示链接编辑器在 GOT 中分配空间,以存储当前目标文件的 TLS_index 结构。链接编辑器通过以相对于 GOT 的偏移替代新的 GOT 项来处理此重定位。
装入目标文件索引在运行前无法确定。因此,将创建 R_SPARC_TLS_DTPMOD32 重定位,并在 TLS_index 结构的 ti_tlsoffset 字段中填充零。
第二个 add 和 call 指令分别使用 R_SPARC_TLS_LDM_ADD 和 R_SPARC_TLS_LDM_CALL 重定位进行标记。
后面的 sethi 指令和 xor 指令分别生成 R_SPARC_LDO_HIX22 和 R_SPARC_TLS_LDO_LOX10 重定位。在链接编辑时已得知了每个局部符号的 TLS 偏移,因此将直接填入这些值。add 指令使用 R_SPARC_TLS_LDO_ADD 重定位进行标记。
当一个过程引用多个局部符号时,编译器将生成代码一次获取 TLS 块的基本地址。然后,使用此基本地址计算每个符号的地址,而不需要单独调用库。
注 - 包含 add 指令(由 R_SPARC_TLS_LDO_ADD 标记)中的 TLS 目标文件地址的寄存器必须是指令序列中的第一个寄存器。在代码变换期间,此要求允许链接编辑器标识寄存器。
32-bit SPARC: 初始可执行 (Initial Executable, IE)
此代码序列实现线程局部存储的访问模型中介绍的 IE 模型。
表 14-4 32-bit SPARC: 初始可执行的线程局部变量访问代码代码序列
| 初始重定位
| 符号
|
# %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 指令和 or 指令分别生成 R_SPARC_TLS_IE_HI22 和 R_SPARC_TLS_IE_LO10 重定位。这些重定位指示链接编辑器在 GOT 中创建空间,以存储符号 x 的静态 TLS 偏移。针对 GOT 的 R_SPARC_TLS_TPOFF32 重定位将会暂停,以便运行时链接程序使用符号 x 的负静态 TLS 偏移填充。ld 和 add 指令分别使用 R_SPARC_TLS_IE_LD 和 R_SPARC_TLS_IE_ADD 重定位进行标记。
注 - 用作 add 指令(由 R_SPARC_TLS_IE_ADD 重定位标记)的 GOT 指针的寄存器必须是此指令中的第一个寄存器。在代码变换期间,此要求允许链接编辑器标识 GOT 指针寄存器。
64-bit SPARC: 初始可执行 (Initial Executable, IE)
此代码序列实现线程局部存储的访问模型中介绍的 IE 模型。
表 14-5 64-bit SPARC: 初始可执行的线程局部变量访问代码代码序列
| 初始重定位
| 符号
|
# %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 模型。
表 14-6 SPARC: 局部可执行的线程局部变量访问代码代码序列
| 初始重定位
| 符号
|
# %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 和 xor 指令分别生成 R_SPARC_TLS_LE_HIX22 和 R_SPARC_TLS_LE_LOX10 重定位。链接编辑器将这些重定位直接绑定到在可执行文件中定义的符号的静态 TLS 偏移。在运行时不需要进行重定位处理。