ELF对线程局部储存的处理(5)
来源:互联网 发布:mac popo登录408 编辑:程序博客网 时间:2024/06/06 05:19
4.4.局部可执行TLS模式
类似局部动态模式相对于常规动态模式加入的优化,优化局部动态模式得到局部可执行模式。它使用的限制性比局部动态模式还要大。它仅能用于执行映像自身的代码,并访问该执行映像本身的变量。
把使用限制在执行映像意味着,仅对于局部可执行模式而言,TLS块可以相对于线程指针取址。限定变量是那些定义在执行映像里的变量,这意味着总是使用第一个TLS块,这个块用于执行映像,因而对于地址计算来说,其它块的大小都不再重要。它亦意味着,当构建最终映像时,链接器知道到TCB的偏移是多少。计算实际偏移的公式依赖于架构,它包括涉及线程指针,第一个TLS块的偏移tlsoffset1,及变量在这个TLS块中的偏移offsetx的一个加法或减法。其结果在链接时刻已知,并作为一个立即数在代码中可用。
在后面章节中,架构描述里的代码实现了以下代码行,这些代码必须在可执行映像中:
static __thread int x;
&x
4.4.1.IA-64局部可执行TLS模式
用于这个模式的代码序列非常简单。如果线程寄存器的值,适当地保存在一个可用在add指令的寄存器中,代码序列仅为每个新增的变量增加一条指令。
局部可执行模式代码序列
初始重定位 符号
0x00 ld8 t2=tp
;;
0x10 addl loc0=@tprel (x), r2
R_IA_64_TPREL22 x
未解决的重定位
除了把线程指针的值移入r2寄存器,为add指令做准备以外,代码所做的就是把偏移常量加上线程指针(add指令不能直接使用tp寄存器)。变量赋予重定位R_IA_64_TPREL22,链接器执行确定tlsoffset1 + offsetx。即,除了变量在TLS块的偏移外,只有TLS块的对齐会影响结果。
如同初始可执行模式,这里给出的代码序列是三个可能中的之一。允许处理的线程局部数据可以多达221字节(2M)。对于处理少于213(8K)字节或多于221字节数据,优化是可能的,这时使用的重定位分别是R_IA_64_TPREL14及R_IA_64_TPREL64I,指令是一个短add或长move。
4.4.2.IA-32局部可执行TLS模式
IA-32代码序列基本上只是把,可作为立即数得到的偏移,加上线程指针的值。线程指针的确定方式可能不一样;在Sun的模式中,它可以通过从%gs段的0偏移处载入来确定。
局部可执行模式代码序列
初始重定位 符号
0x00 movl $x@tpoff, %edx
0x05 movl %gs:0, %eax
0x0b subl %edx, %eax
R_386_TLS_LE_32 x
未解决的重定位
在这里使用的表达式x@tpoff不是相对于GOT的偏移,而是一个立即数。对此,链接器产生了一个可以被链接器解析的R_386_TLS_LE_32重定位。这样确定的值是变量在TLS块中的正偏移。把它从线程指针值减去,就在%eax寄存器中得到x的最终地址。GNU版本再一次具有更短小的优势。
局部可执行模式代码序列,II
初始重定位 符号
0x00 movl %gs:0, %eax
0x06 leal x@ntpoff (%eax), %eax
R_386_TLS_LE x
未解决的重定位
这里GNU版本使用了一个计算变量在TLS块中负偏移,而不是正偏移的重定位。其显著的好处在于,偏移可以被直接嵌入到一个内存地址(参见下面)。
那么在Sun的模式下,载入x的内容(而不是其地址),使用以下代码序列:
局部可执行模式代码序列,III
初始重定位 符号
0x00 movl $x@tpoff, %edx
0x05 movl %gs:0, %eax
0x0b subl %edx, %eax
0x0d movl (%eax), %eax
R_386_TLS_LE_32 x
未解决的重定位
在末尾有一个额外载入外,这与前面的序列相同。相比而言,GNU序列还是要短些:
局部可执行模式代码序列,IV
初始重定位 符号
0x00 movl %gs:0, %eax
0x06 movl x@ntpoff (%eax), %eax
R_386_TLS_LE x
未解决的重定位
如果不是要计算变量的地址,而是载入或保存它,可以使用下面的序列。注意到在这个情形下,表达式x@ntpoff不作为一个立即数,而是作为一个绝对地址来使用。
局部可执行模式代码序列,V
初始重定位 符号
0x00 movl %gs:x@ntpoff, %eax
R_386_TLS_LE x
未解决的重定位
载入或保存操作比计算地址更简单,这个事实一开始肯定令人吃惊。不过段寄存器的处理是怪异的。你可以把段寄存器%gs视作,把虚拟地址空间的0地址移到另一个位置的,一个手段。这个新位置,一旦计算出来,对CPU内部而言是可以直接访问的。这就是为什么在用户层面计算它的地址时,额外要求转移后(shifted)的地址空间的第一个字包含移位值(shift value)或地址。
4.4.3.SPARC局部可执行TLS模式
SPARC的局部可执行模式是尽可能精简的。它只是把可作为一个立即数得到的偏移,加上线程指针值。
局部可执行模式代码序列,V
初始重定位 符号
0x00 sethi %hix (@tpoff (x)), %o0
0x04 xor %o0, %lox (@tpoff (x)), %o0
0x08 add %g7, %o0, %o0
R_SPARC_TLS_LE_HIX22 x
R_SPARC_TLS_LE_LOX22 x
未解决的重定位
表达式%hix *tpoff (x))及%lox (tpoff (x))使得链接器发布R_SPARC_TLS_LE_HIX22及R_SPARC_TLS_LE_LOX22重定位,这些重定位要求,链接器在这些指令中,把偏移值作为立即数填入。这会把偏移载入%o0寄存器。接下来的add指令要求这里的偏移是负数。为了计算最终的地址,偏移被加上线程寄存器%g7的值。这个add指令没有被重定位标记。其原因是,链接器不需要出于放宽(relaxation)来识别这个指令,它不可能再简化了。
4.4.4.SH局部可执行TLS模式
正如其它架构那样,局部可执行模式的代码序列实在简单。主要的差别是对于所有的SH代码,需要一个数据重定位。
局部可执行模式代码序列,V
初始重定位 符号
0x00 mov.l .Ln, r0
0x02 stc gbr, r1
0x04 add r1, r0
...
.Ln: .long x@tpoff
R_SH_TLS_LE_32 x
未解决的重定位
代码分别在r0及r1寄存器载入了地址的两个部分,线程指针的相对偏远(链接时刻已知)及线程指针。因为就这个代码序列而言,没有进一步优化的可能,带有标签.Ln的字的实际位置不重要。
4.4.5.Alpha局部可执行TLS模式
Alpha的局部可执行模式序列小而精。依照应用所期望的TLS的大小,可以有三个序列可选择。在下面的序列中,预期会调用PAL_rduniq,并且线程指针被拷贝入$tp。
局部可执行模式代码序列,V
初始重定位 符号
0x00 lda $l, x1($tp) !tprel
…
0x10 ldah $1, x2 ($tp) !tprelhi
0x14 lda $1, x2 ($1) !tprello
...
0x20 ldq $1, x3 ($gp) !gottprel
0x24 addl $1, $tp, $1
R_ALPHA_TPREL16 x1
R_ALPHA_TPRELHI x2
R_ALPHA_TPRELLO x2
R_ALPHA_GOTTPREL x3
未解决的重定位
第一个序列可用于32K,第二个则用于2G,而第三个可用于64位的完全位移(displacement)。
4.4.6.x86-64局部可执行TLS模式
x86-64代码序列与IA-32的GNU版本类似。它仅是把可以作为立即数得到的偏移,加上线程指针。线程指针从%fs段的0偏移处载入。
局部可执行模式代码序列
初始重定位 符号
0x00 movq %fs:0, %rax
0x09 leaq x@tpoff (%rax), %rax
R_x86_64_TPOFF32 x
未解决的重定位
为了载入一个TLS变量,而不是计算其地址,可以使用以下序列:
局部可执行模式代码序列
初始重定位 符号
0x00 movq %fs:0, %rax
0x09 movq x@tpoff (%rax), %rax
R_x86_64_TPOFF32 x
未解决的重定位
或更简短:
局部可执行模式代码序列
初始重定位 符号
0x00 movq %fs: x@tpoff, %rax
R_x86_64_TPOFF32 x
未解决的重定位
4.4.7.s390局部可执行TLS模式
s390的局部可执行模式仅是把可作为立即数得到的偏移加上线程指针。通常,这个偏移可以有32位,这要求一个字常数库的项。
局部可执行模式代码序列
初始重定位 符号
ear %r7, %a0
R_390_TLS_LE32 x
l %r8, .L1-.L0 (%r13)
la %r9, 0 (%r8, %r7) # %r9 = &x
...
.L0 : # literal pool, address in %r13
.L1: .long x@ntpoff
未解决的重定位
链接器把重定位R_390_TLS_LE32解析为到线程指针的负偏移。
4.4.8.s390x局部可执行TLS模式
s390x的局部可执行模式与s390的区别仅在于线程指针的提取,及偏移的大小。
局部可执行模式代码序列
初始重定位 符号
ear %r7, %a0
sllg %r7, %r7, 32
ear %r7, %a1
R_390_TLS_LE64 x
lg %r8, .L1-.L0 (%r13)
la %r9, 0 (%r8, %r7) # %r9 = &x
...
.L0: # literal pool, address in %r13
.L1: .quad x@ntpoff
未解决的重定位
- ELF对线程局部储存的处理(5)
- ELF对线程局部储存的处理(1)
- ELF对线程局部储存的处理(2)
- ELF对线程局部储存的处理(3)
- ELF对线程局部储存的处理(4)
- ELF对线程局部储存的处理(6)
- ELF对线程局部储存的处理(7)
- ELF对线程局部储存的处理(8)
- ELF对线程局部储存的处理(1) __thread
- Windows核心编程笔记(十七) 线程局部储存
- Bfd对elf文件头的处理
- 线程局部存储,Part 5:加载器对__declspec(thread)变量的支持(进程初始化阶段)
- TLS 局部线程储存 一个演示小例子
- 局部的变量与成员变量对线程的影响
- 消息线程,对MFC消息机制的局部模拟
- java实现线程安全的栈(链式储存)
- 线程局部存储(TLS)的使用
- java服务对线程并发的处理
- ELF对线程局部储存的处理(2)
- Foxmail中设置Gmail教程
- ELF对线程局部储存的处理(3)
- ELF对线程局部储存的处理(4)
- Oracle 知识备份(三)2011年4月4号
- ELF对线程局部储存的处理(5)
- 品牌战略
- Ubuntu 10.10 下面禁用触摸板
- JSP Servlet 小记
- 如何在各种字符串类型之间进行转换(VS2010)
- FastWei is born...
- 详细解析Java中抽象类和接口的区别
- Spring aop使用实例
- 项目建立之初