链接程序和库指南

SPARC: 访问线程局部变量

在 SPARC 上,可使用以下代码序列模型来访问线程局部变量。

SPARC: 常规动态 (General Dynamic, GD)

此代码序列实现线程局部存储的访问模型中介绍的 GD 模型。

表 8–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

sethiadd 指令分别生成 R_SPARC_TLS_GD_HI22R_SPARC_TLS_GD_LO10 重定位。这些重定位指示链接编辑器在 GOT 中分配空间,以存储变量 xTLS_index 结构。链接编辑器通过将相对于 GOT 的偏移替换为新的 GOT 项来处理此重定位。

x 的装入目标文件索引和 TLS 块索引在运行前无法确定。因此,链接编辑器根据 GOT 放置 R_SPARC_TLS_DTPMOD32R_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 模型。

表 8–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_HI22R_SPARC_TLS_LDM_LO10 重定位。这些重定位指示链接编辑器在 GOT 中分配空间,以存储当前目标文件的 TLS_index 结构。链接编辑器通过将相对于 GOT 的偏移替换为新的 GOT 项来处理此重定位。

装入目标文件索引在运行前无法确定。因此,将创建 R_SPARC_TLS_DTPMOD32 重定位,并在 TLS_index 结构的 ti_tlsoffset 字段中填充零。

第二个 addcall 指令分别由 R_SPARC_TLS_LDM_ADDR_SPARC_TLS_LDM_CALL 重定位标记。

后面的 sethi 指令和 xor 指令分别生成 R_SPARC_LDO_HIX22R_SPARC_TLS_LDO_LOX10 重定位。在链接编辑时将确定每个局部符号的 TLS 偏移,因此将直接填充这些值。add 指令使用 R_SPARC_TLS_LDO_ADD 重定位标记。

当一个过程引用多个局部符号时,编译器将生成一次获取 TLS 块的基本地址的代码。然后,使用此基本地址计算每个符号的地址,而不需要单独调用库。


注 –

包含 add 指令(由 R_SPARC_TLS_LDO_ADD 标记)中的 TLS 目标文件地址的寄存器必须是指令序列中的第一个寄存器。在代码变换期间,此要求允许链接编辑器标识寄存器。


32 位 SPARC: 初始可执行 (Initial Executable, IE)

此代码序列实现线程局部存储的访问模型中介绍的 IE 模型。

表 8–4 32 位 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_HI22R_SPARC_TLS_IE_LO10 重定位。这些重定位指示链接编辑器在 GOT 中创建空间,以存储符号 x 的静态 TLS 偏移。针对 GOTR_SPARC_TLS_TPOFF32 重定位未完成,以便运行时链接程序使用符号 x 的负静态 TLS 偏移填充。ldadd 指令分别使用 R_SPARC_TLS_IE_LDR_SPARC_TLS_IE_ADD 重定位标记。


注 –

用作 add 指令(由 R_SPARC_TLS_IE_ADD 重定位标记)的 GOT 指针的寄存器必须是此指令中的第一个寄存器。在代码变换期间,此要求允许链接编辑器标识 GOT 指针寄存器。


64 位 SPARC: 初始可执行 (Initial Executable, IE)

此代码序列实现线程局部存储的访问模型中介绍的 IE 模型。

表 8–5 64 位 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 模型。

表 8–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

sethixor 指令分别生成 R_SPARC_TLS_LE_HIX22R_SPARC_TLS_LE_LOX10 重定位。链接编辑器将这些重定位直接绑定到在可执行文件中定义的符号的静态 TLS 偏移。在运行时不需要进行重定位处理。