ELF对线程局部储存的处理(7)

5.4. Alpha 链接器优化

Alpha 的链接器优化要比 IA-32 SPARC 的干净,因为对指令的次序没有限制。

重定位 TLSGD/TLSLDM LTERAL LITUSE ,在汇编文件中,由序号( sequence number )关联。这使得它们在目标文件中被连续发布( emit )。

不会发生 __tls_get_addr 模式的放宽,除非重定位以 TLSGD LITERAL LITUSE_TLSGD ,这个次序出现(对于 TLSLDM ,类似)。这用于区别 TLSGD 重定位不与任何调用序列关联的情形。汇编器将强制一个限制:如果存在 LITUSE_TLSGD ,将出现重定位 TLSGD LITERAL ,而没有其它 LITUSE 重定位与 LITERAL 关联。

__tls_get_addr 模式的放宽要求,在紧跟 jsr 的偏移上,有一个 GPDISP 重定位。

常规动态到初始可执行

GD à IE 代码转换

初始重定位                     符号

0x00  lda  $16, x($gp)   !tlsgd!1

0x04  ldq  $27, __tls_get_addr ($gp) !literal!1

0x08  jsr   $26, ($27), 0  !lituse_tlsgd!1

0x0c  ldah   $29, 0 ($26)  !gpdisp!2

0x10  lda  $29, 0 ($29)  !gpdisp!2

              

0x00  ldq  $16, x($gp)

0x04  nop

0x08  call_pal PAL_rduniq

0x0c  addq $16, $0, $0

0x10  unop

R_ALPHA_TLSGD              x

R_ALPHA_LITERAL     __tls_get_addr

R_ALPHA_LITUSE              4

R_ALPHA_GPDISP               4

 

                         

R_ALPHA_GOTTPREL          x

 

GOT [n]

未解决的重定位

R_ALPHA_TPOFF64          x

 

常规动态到局部可执行

GD à LE 代码转换

初始重定位                     符号

0x00  lda  $16, x($gp)   !tlsgd!1

0x04  ldq  $27, __tls_get_addr ($gp) !literal!1

0x08  jsr   $26, ($27), 0  !lituse_tlsgd!1

0x0c  ldah   $29, 0 ($26)  !gpdisp!2

0x10  lda  $29, 0 ($29)  !gpdisp!2

              

0x00  ldah  $16, x($31)

0x04  lda   $16, x($16)

0x08  call_pal PAL_rduniq

0x0c  addq $16, $0, $0

0x10  unop

R_ALPHA_TLSGD               x

R_ALPHA_LITERAL     __tls_get_addr

R_ALPHA_LITUSE              4

R_ALPHA_GPDISP              4

 

                         

R_ALPHA_TPRELHI            x

R_ALPHA_TPRELLO            x

 

未解决的重定位

 

如果 x TLS 块中的偏移在 2G 以内,使用这个转换。如果偏移更大些,那么使用 GD à IE 的转换,除非没有动态重定位。

如果 x TLS 块中的偏移在 32K 以内,那么第一条指令是一个 lda ,而第二条指令是一个 unop

局部动态到局部可执行

LD à LE 转换与 GD à LE 转换相同,除了我们引用模块 TLS 段的基址,而不是一个特定的变量。

初始可执行到局部可执行

IE à LE 代码转换

初始重定位                     符号

0x00  ldq  $1, x($gp)

0x04  addq $tp, $1, $0

              

0x00  lda  $16, x($31)

0x04  addq $tp, $0, $0

R_ALPHA_GOTTPREL            x

 

                         

R_ALPHA_TPREL               x

 

未解决的重定位

 

如果在 TLS 块中的偏移在 32K 以内,使用这个转换。如果偏移更大些,那么代码序列不变,但是在 GOT 的动态重定位被移除。

5.5. x86-64 链接器优化

x86-64 链接器优化与 GNU 版本的 IA-32 优化非常接近。

常规动态到初始可执行

这个代码转换可以解释,在 x86-64 常规动态模式代码序列中的, 4 个填充字节。 IE 序列要多 4 个字节:

 

GD à IE 代码转换

初始重定位                     符号

0x00  .byte  0x66

0x01  leaq   x@tlsgd (%rip), %rdi

0x08  .word  0x6666

0x0a  rex64

0x0b  call __tls_get_add@plt

             

0x00  movq %fs:0, %rax

0x09  addq x@gottpoff (%rip), %rax

 

R_X86_64_TLSGD               x

 

 

R_X86_64_PLT32        __tls_get_addr

                         

 

R_X86_64_GOTTPOFF          x

 

GOT [n]

未解决的重定位

R_X86_64_TPOFF64         x

 

常规动态到局部可执行

这个转换与前面的类似,只是偏移可以被直接存入指令:

 

GD à IE 代码转换

初始重定位                     符号

0x00  .byte  0x66

0x01  leaq   x@tlsgd (%rip), %rdi

0x08  .word  0x6666

0x0a  rex64

0x0b  call __tls_get_add@plt

             

0x00  movq %fs:0, %rax

0x09  leaq x@tpoff (%rax), %rax

 

R_X86_64_TLSGD               x

 

 

R_X86_64_PLT32        __tls_get_addr

                          

 

R_X86_64_TPOFF32             x

 

未解决的重定位

 

局部动态到局部可执行

下面的代码转换要求填充结果指令:

 

LD à LE 代码转换

初始重定位                     符号

0x00  leaq x1@tlsld (%rip), %rdi

0x07  call __tls_get_add@plt

     

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

         

0x00  .word 0x6666

0x02  .byte  0x66

0x03  movq %fs:0, %rax

     

0x10  leaq x1@tpoff (%rax), %rdx

R_X86_64_TLSGD               x1

R_X86_64_PLT32        __tls_get_addr

 

R_X86_64_DTPOFF32            x1

                          

 

 

 

 

R_X86_64_TPOFF32              x1

 

未解决的重定位

 

初始可执行到局部可执行

最后一个 x86-64 代码转换:

 

IE à LE 代码转换

初始重定位                     符号

0x00 movq %fs:0, %rax

0x09 addq  x@gottpoff (%rip), %rax

             

0x00 movq %fs:0, %rax

0x09 leaq  x@tpoff (%rip), %rax

 

R_X86_64_GOTTPOFF            x

                           

 

R_X86_64_TPOFF32              x

 

未解决的重定位

 

5.6. s390 链接器优化

s390 ABI IA-32 那样,定义了四个链接器优化。这些优化解释函数 __tls_get_offset 。对于 s390 ,所有的代码序列基本上包括 3 样:

1.       提取线程指针

2.       获得变量到线程指针的偏移

3.       使用一个索引 / 基址操作数,在变量上,合并线程指针及偏移的操作(即, la %rx, 0 (%ry, %rz) )。

所有的优化所要做的,是改变获取偏移的方法。

常规动态到初始可执行

常规动态访问模式是代价最高的,这使得这个转换成为最重要的一个。对于常规动态访问模式,代码必须从字常数库载入一个 GOT 偏移,然后调用 __tls_get_offset ,从线程指针获得变量的偏移。对于初始可执行访问模式,代码需要载入一个包含变量到线程指针的偏移的 GOT 项。初始可执行代码的一个变种,把一个字常数库项用于 GOT 偏移。这使得转换变得简单,函数调用指令被一个载入指令替代,而字常数库常量 x@tlsgd 替代了 x@gotntpoff

 

GD à IE 代码转换

初始重定位                      符号

l   %r6, .L1-.L0 (%r13)

ear %r7, %a

 

 

 

R_390_TLS_GDCALL               x

 

 

 

 

R_390_TLS_GD32                 x

                           

 

 

 

R_390_TLS_LOAD                x

 

 

 

 

R_390_TLS_GOTIE32             x

l   %r2, .L2-.L0 (%r13)

bas %r14, 0 (%r6, %r13)

la  %r8, 0 (%r2, %r7) # %r8 = &x

...

.L0 : # literal pool, address in %r13

.L1: .long [email protected]

.L2: .long x@ltsgd

            

l   %r6, .L1-.L0 (%r13)

ear %r7, %a

l  %r2, .L2-.L0 (%r13)

l  %r2, 0 (%r2, %r12)

   la %r8, 0 (%r2, %r7) # %r8 = &x

  

.L0 : # literal pool, address in %r13

.L1: .long [email protected]

.L2: .long x@gotntpoff

 

GOT [n]

未解决的重定位

R_390_TLS_TPOFF32              x

 

常规动态到局部可执行

这个把常规动态代码序列变成局部可执行代码序列的优化,与常规动态到初始可执行转换一样简单。局部可执行代码序列,直接从字常数库,载入变量到线程指针的偏移。常规动态代码序列中的函数调用,被转换为一个 nop ,字常数库常量 x@tlsgd x@ntpoff 替换:

 

GD à LE 代码转换

初始重定位                     符号

l   %r6, .L1-.L0 (%r13)

ear %r7, %a

 

 

 

R_390_TLS_GDCALL               x

 

 

 

 

R_390_TLS_GD32                 x

                           

 

 

 

 

 

 

 

 

R_390_TLS_LE32             x

l   %r2, .L2-.L0 (%r13)

bas %r14, 0 (%r6, %r13)

la  %r8, 0 (%r2, %r7) # %r8 = &x

...

.L0 : # literal pool, address in %r13

.L1: .long [email protected]

.L2: .long x@ltsgd

            

l   %r6, .L1-.L0 (%r13)

ear %r7, %a

l  %r2, .L2-.L0 (%r13)

bc 0, 0 # nop

   la %r8, 0 (%r2, %r7) # %r8 = &x

  

.L0 : # literal pool, address in %r13

.L1: .long [email protected]

.L2: .long x@ntpoff

 

未解决的重定位

 

局部动态到局部可执行

局部动态到局部可执行代码转换稍微有点复杂。为了在局部动态模式中,得到一个线程局部变量的地址,需要增加 3 件事:线程指针,到代码所在模块的 TLS 块的(负的)偏移,变量在 TLS 块中的偏移。局部可执行代码只需要把线程指针加上变量到线程指针的负偏移。通过使用一个 nop 代替函数调用,使用 0 代替字常数库常量 x1@tlsldm ,以及 ntpoff 代替常量 @dtpoff ,完成转换。

 

LD à LE 代码转换

初始重定位                     符号

l   %r6, .L1-.L0 (%r13)

ear %r7, %a0

 

 

 

R_390_TLS_LDCALL               x1

 

 

 

 

 

 

 

 

R_390_TLS_LDM32                x1

R_390_TLS_LDO32                x1

R_390_TLS_LDO32                x2

                           

 

 

 

 

 

 

 

 

 

 

 

 

 

R_390_TLS_LE32                  x1

R_390_TLS_LE32                  x2

l   %r2, .L2-.L0 (%r13)

bas %r14, 0 (%r6, %r13)

la  %8, 0 (%r2, %r7)

l  %r9, .L3-.L0 (%r13)

la  %r10, 0 (%r10, %r8) # %r10 = &x1

l  %r9, .L4-.L0 (%r13)

la  %r10, 0 (%r10, %r18) # %r10 = &x2

...

.L0 : # literal pool, address in %r13

.L1: .long [email protected]

.L2: .long x1@ltsldm

.L3: .long x1@dtpoff

.L4: .long x2@dtpoff

        

l   %r6, .L1-.L0 (%r13)

ear %r7, %a0

l   %r2, .L2-.L0 (%r13)

bc   0, 0   # nop

la  %8, 0 (%r2, %r7)

l  %r9, .L3-.L0 (%r13)

la  %r10, 0 (%r10, %r8) # %r10 = &x1

l  %r9, .L4-.L0 (%r13)

la  %r10, 0 (%r10, %r18) # %r10 = &x2

...

.L0 : # literal pool, address in %r13

.L1: .long [email protected]

.L2: .long 0

.L3: .long x1@ntpoff

.L4: .long x2@ntpoff

 

GOT [n]

未解决的重定位

R_390_TLS_DTPMOD              x1

 

初始可执行到局部可执行

初始可执行到局部可执行的转换并不提高执行的速度,但对于 3 个初始可执行版本中的 2 个,减少了一个 GOT 项。

 

IE à LE 代码转换

初始重定位                     符号

ear %r7, %a0

 

 

R_390_TLS_LOAD              x

 

 

 

R_390_TLS_GOTIE32           x

                         

 

 

 

 

 

 

R_390_TLS_LE32                x

l  %r8, .L1-.L0 (%r13)

l  %r9, 0 (%r8, %r12)

la  %r10, 0 (%r9, %r7) # %r10 = &x

...

.L0 : # literal pool, address in %r13

.L1 : .long x@indntpoff

ear %r7, %a0

l  %r8, .L1-.L0 (%r13)

lr  %r9, %r8 ; bcr 0, %r0

la  %r10, 0 (%r9, %r7) # %r10 = &x

...

.L0 : # literal pool, address in %r13

.L1 : .long x@ntpoff

 

未解决的重定位

 

IE à LE 代码转换

初始重定位                     符号

ear %r7, %a0

 

 

R_390_TLS_LOAD              x

 

 

 

R_390_TLS_GOTIE32           x

                         

 

 

 

 

 

 

R_390_TLS_LE32                x

l  %r8, .L1-.L0 (%r13)

l  %r9, 0 (%r8, %r12)

la  %r10, 0 (%r9, %r7) # %r10 = &x

...

.L0 : # literal pool, address in %r13

.L1 : .long x@gotntpoff

ear %r7, %a0

l  %r8, .L1-.L0 (%r13)

lr  %r9, %r8 ; bcr 0, %r0

la  %r10, 0 (%r9, %r7) # %r10 = &x

...

.L0 : # literal pool, address in %r13

.L1 : .long x@ntpoff

 

未解决的重定位

 

对于小 GOT ,没有 IE à LE 的代码转换,因为不存在可以保存改变后的 x@ntpoff 常量的字常数库项。对于这个情形, GOT 的一个项用于这个常量。

5.7. s390x 链接器优化

正如 s390 那样,同样的四种优化存在于 s390x 中。优化遵循相同的原理,但使用 64 位而不是 32 位指令。 6 字节的 bras1 指令,要么被 6 字节的 lg 载入指令替代,要么被 6 字节 brc1 0, .nop 替代。 6 字节的 lg 指令被 6 字节三合一 0 比特移位,而不是更合适但不幸只有 4 字节的 lgr ,所替代。

常规动态到初始可执行

GD à IE 代码转换

初始重定位                     符号

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %a1

 

 

 

 

R_390_TLS_GDCALL               x

 

 

 

R_390_TLS_GD64                 x

                           

 

 

 

 

R_390_TLS_LOAD                x

 

 

 

R_390_TLS_GOTIE64              x

lg    %r2, .L1-.L0 (%r13)

brasl %r14, __tls_get_offset@plt

la  %r8, 0 (%r2, %r7) # %r8 = &x

...

.L0 : # literal pool, address in %r13

.L1: .quad x@tlsgd

            

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %al

lg   %r2, .L1-.L0 (%r13)

lg   %r2, 0 (%r2, %r12)

   la   %r8, 0 (%r2, %r7) # %r8 = &x

  

.L0 : # literal pool, address in %r13

.L1: .quad x@gotntpoff

 

GOT [n]

未解决的重定位

R_390_TLS_TPOFF64              x

 

常规动态到局部可执行

GD à LE 代码转换

初始重定位                     符号

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %a1

 

 

 

 

R_390_TLS_GDCALL               x

 

 

 

R_390_TLS_GD64                 x

                           

 

 

 

 

 

 

 

 

R_390_TLS_LE64                x

lg    %r2, .L1-.L0 (%r13)

brasl %r14, __tls_get_offset@plt

la  %r8, 0 (%r2, %r7) # %r8 = &x

...

.L0 : # literal pool, address in %r13

.L1: .quad x@tlsgd

            

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %al

lg   %r2, .L1-.L0 (%r13)

brcl  0, .

   la   %r8, 0 (%r2, %r7) # %r8 = &x

  

.L0 : # literal pool, address in %r13

.L1: .quad x@ntpoff

 

未解决的重定位

 

局部动态到局部可执行

LD à LE 代码转换

初始重定位                     符号

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %a1

 

 

 

 

R_390_TLS_LDCALL              x1

 

 

 

 

 

 

 

R_390_TLS_LDM64                 x1

R_390_TLS_LDO64                 x1

R_390_TLS_LDO64                  x2

                           

 

 

 

 

 

 

 

 

 

 

 

 

 

R_390_TLS_LE64                x1

R_390_TLS_LE64                x2

lg    %r2, .L1-.L0 (%r13)

brasl %r14, __tls_get_offset@plt

la  %r8, 0 (%r2, %r7

lg  %r9, .L2-.L0 (%r13)

la  %r10, 0 (%r9, %r8) # %r10 = &x1

lg  %r9, .L3-.L0 (%r13)

la  %r10, 0 (%r9, %r8) # %r10 = &x2

...

.L0 : # literal pool, address in %r13

.L1: .quad x1@tlsldm

.L2: .quad x1@dtpoff

.L3: .quad x2@dtpoff

            

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %al

lg   %r2, .L1-.L0 (%r13)

brcl  0, .

la   %r8, 0 (%r2, %r7)

   lg  %r9, .L2-.L0 (%r13)

la  %r10, 0 (%r9, %r8) # %r10 = &x1

lg  %r9, .L3-.L0 (%r13)

la  %10, 0 (%r9, %r8) # %r10 = &x2

  

.L0 : # literal pool, address in %r13

.L1: .quad 0

.L2: .quad x1@ntpoff

.L3: .quad x2@ntpoff

 

未解决的重定位

 

初始可执行到局部可执行

IE à LE 代码转换

初始重定位                     符号

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %a1

 

 

 

 

R_390_TLS_LOAD               x

 

 

 

R_390_TLS_GOTIE64             x

                           

 

 

 

 

 

 

 

 

R_390_TLS_LE64                 x

lg    %r2, .L1-.L0 (%r13)

lg   %r9, 0 (%r8, %r12)

la  %r10, 0 (%r9, %r7) # %r10 = &x

...

.L0 : # literal pool, address in %r13

.L1: .quad x@gotntpoff

            

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %al

lg   %r8, .L1-.L0 (%r13)

sllg  %r9, %r8, 0

   la   %r10, 0 (%r9, %r7) # %r10 = &x

  

.L0 : # literal pool, address in %r13

.L1: .quad x@ntpoff

 

未解决的重定位

 

IE à LE 代码转换

初始重定位                     符号

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %a1

 

 

 

 

R_390_TLS_LOAD               x

 

 

 

R_390_TLS_GOTIE64             x

                           

 

 

 

 

 

 

 

 

R_390_TLS_LE64                x

lg    %r8, .L1-.L0 (%r13)

lg   %r9, 0 (%r8)

la    %r10, 0 (%r9, %r7) # %r10 = &x

...

.L0 : # literal pool, address in %r13

.L1: .quad x@indntpoff

             

ear  %r7, %a0

sllg  %r7, %r7, 32

ear  %r7, %al

lg   %r8, .L1-.L0 (%r13)

sllg  %r9, %r8, 0

   la   %r10, 0 (%r9, %r7) # %r10 = &x

  

.L0 : # literal pool, address in %r13

.L1: .quad x@ntpoff

 

未解决的重定位

 

你可能感兴趣的:(ELF对线程局部储存的处理(7))