There are 2 kinds of TLSDESC relaxations: GDesc -> IE transition and
GDesc -> LE transition. What you described only works for GDesc -> IE
transition. For GDesc -> LE transition, we can have
[hjl@gnu-cfl-2 gcc]$ cat x.s
.text
.p2align 4
.globl test
.type test, @function
test:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
leaq foo@TLSDESC(%rip), %r9
movq %r9, %rax
call *foo@TLSCALL(%rax)
addq %fs:0, %rax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.size test, .-test
.section .tdata,"awT",@progbits
.align 4
.type foo, @object
.size foo, 4
foo:
.long 30
.section .note.GNU-stack,"",@progbits
[hjl@gnu-cfl-2 gcc]$ cat main.c
extern int *test (void);
int
main ()
{
return *test ();
}
[hjl@gnu-cfl-2 gcc]$ gcc -c main.c x.s
[hjl@gnu-cfl-2 gcc]$ objdump -dwr x.o
x.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <test>:
0: 48 83 ec 08 sub $0x8,%rsp
4: 4c 8d 0d 00 00 00 00 lea 0x0(%rip),%r9 # b <test+0xb>
7: R_X86_64_GOTPC32_TLSDESC foo-0x4
b: 4c 89 c8 mov %r9,%rax
e: ff 10 callq *(%rax) e: R_X86_64_TLSDESC_CALL foo
10: 64 48 03 04 25 00 00 00 00 add %fs:0x0,%rax
19: 48 83 c4 08 add $0x8,%rsp
1d: c3 retq
[hjl@gnu-cfl-2 gcc]$ gcc main.o x.o
[hjl@gnu-cfl-2 gcc]$ objdump -dw --disassemble=test a.out
a.out: file format elf64-x86-64
Disassembly of section .init:
Disassembly of section .text:
0000000000401120 <test>:
401120: 48 83 ec 08 sub $0x8,%rsp
401124: 49 c7 c1 fc ff ff ff mov $0xfffffffffffffffc,%r9
Linker rewrites
4c 8d 0d 00 00 00 00 lea 0x0(%rip),%r9 # leaq foo@tlsdesc(%rip), %r9
to
49 c7 c1 fc ff ff ff mov $0xfffffffffffffffc,%r9 # movq $foo@tpoff, %r9
Linker changes opcode 0x8d to 0xc7, not 0x8b. To do that, linker
may need to update the REX byte.
40112b: 4c 89 c8 mov %r9,%rax
40112e: 66 90 xchg %ax,%ax
401130: 64 48 03 04 25 00 00 00 00 add %fs:0x0,%rax
401139: 48 83 c4 08 add $0x8,%rsp
40113d: c3 retq
Disassembly of section .fini:
[hjl@gnu-cfl-2 gcc]$
--
H.J.