链接程序和库指南

x64: 局部动态 (Local Dynamic, LD)

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

表 8–19 x64: 局部动态线程局部变量的访问代码

代码序列

初始重定位

符号

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

前两个指令与用于常规动态模型的代码序列等效,虽然不进行任何填充。这两个指令必须是连续的。x1@tlsld(%rip) 序列为符号 x1 生成 tls_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 块的基本地址保存在一个寄存器中,则装入、存储或计算受保护的线程局部变量的地址需要一个指令。

使用局部动态模型比使用常规动态模型可获得更多好处。访问其他每个线程局部变量只需要三个新指令。此外,不需要其他 GOT 项或运行时重定位。