From 52bc799a91cd19a56cb59a9ecd29c0f63153c302 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sat, 12 Mar 2011 14:38:31 +0000 Subject: [PATCH] Support TLS x32 GD->IE, GD->LE and LD->LE transitions. bfd/ 2011-03-12 H.J. Lu * elf64-x86-64.c (elf_x86_64_check_tls_transition): Supprt TLS x32 GD->IE and GD->LE transitions. (elf_x86_64_relocate_section): Supprt TLS x32 GD->IE, GD->LE and LD->LE transitions. ld/testsuite/ 2011-03-12 H.J. Lu * ld-x86-64/tlsgd4.dd: New. * ld-x86-64/tlsgd4.s: Likewise. * ld-x86-64/tlsgd5.dd: Likewise. * ld-x86-64/tlsgd5a.s: Likewise. * ld-x86-64/tlsgd5b.s: Likewise. * ld-x86-64/tlsgd6.dd: Likewise. * ld-x86-64/tlsgd6a.s: Likewise. * ld-x86-64/tlsgd6b.s: Likewise. * ld-x86-64/tlsld2.dd: Likewise. * ld-x86-64/tlsld2.s: Likewise. * ld-x86-64/x86-64.exp (x86_64tests): Add tlsgd4, libtlsgd5.so, tlsgd5, libtlsgd6.so, tlsgd6 and tlsld2. --- bfd/ChangeLog | 7 +++ bfd/elf64-x86-64.c | 84 +++++++++++++++++++++++-------- ld/testsuite/ChangeLog | 16 ++++++ ld/testsuite/ld-x86-64/tlsgd4.dd | 10 ++++ ld/testsuite/ld-x86-64/tlsgd4.s | 14 ++++++ ld/testsuite/ld-x86-64/tlsgd5.dd | 14 ++++++ ld/testsuite/ld-x86-64/tlsgd5a.s | 8 +++ ld/testsuite/ld-x86-64/tlsgd5b.s | 7 +++ ld/testsuite/ld-x86-64/tlsgd6.dd | 14 ++++++ ld/testsuite/ld-x86-64/tlsgd6a.s | 7 +++ ld/testsuite/ld-x86-64/tlsgd6b.s | 7 +++ ld/testsuite/ld-x86-64/tlsld2.dd | 14 ++++++ ld/testsuite/ld-x86-64/tlsld2.s | 12 +++++ ld/testsuite/ld-x86-64/x86-64.exp | 16 ++++++ 14 files changed, 210 insertions(+), 20 deletions(-) create mode 100644 ld/testsuite/ld-x86-64/tlsgd4.dd create mode 100644 ld/testsuite/ld-x86-64/tlsgd4.s create mode 100644 ld/testsuite/ld-x86-64/tlsgd5.dd create mode 100644 ld/testsuite/ld-x86-64/tlsgd5a.s create mode 100644 ld/testsuite/ld-x86-64/tlsgd5b.s create mode 100644 ld/testsuite/ld-x86-64/tlsgd6.dd create mode 100644 ld/testsuite/ld-x86-64/tlsgd6a.s create mode 100644 ld/testsuite/ld-x86-64/tlsgd6b.s create mode 100644 ld/testsuite/ld-x86-64/tlsld2.dd create mode 100644 ld/testsuite/ld-x86-64/tlsld2.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 3c4ba5f44da..b2b65b8105a 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2011-03-12 H.J. Lu + + * elf64-x86-64.c (elf_x86_64_check_tls_transition): Supprt TLS + x32 GD->IE and GD->LE transitions. + (elf_x86_64_relocate_section): Supprt TLS x32 GD->IE, GD->LE + and LD->LE transitions. + 2011-03-10 Alan Modra * elf64-ppc.c (ppc64_elf_relocate_section): Provide section/offset diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index c26c40bb190..927b3ed4a5f 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -865,18 +865,34 @@ elf_x86_64_check_tls_transition (bfd *abfd, if (r_type == R_X86_64_TLSGD) { - /* Check transition from GD access model. Only + /* Check transition from GD access model. For 64bit, only .byte 0x66; leaq foo@tlsgd(%rip), %rdi .word 0x6666; rex64; call __tls_get_addr + can transit to different access model. For 32bit, only + leaq foo@tlsgd(%rip), %rdi + .word 0x6666; rex64; call __tls_get_addr can transit to different access model. */ - static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } }, - call = { { 0x66, 0x66, 0x48, 0xe8 } }; - if (offset < 4 - || (offset + 12) > sec->size - || bfd_get_32 (abfd, contents + offset - 4) != leaq.i + static x86_64_opcode32 call = { { 0x66, 0x66, 0x48, 0xe8 } }; + if ((offset + 12) > sec->size || bfd_get_32 (abfd, contents + offset + 4) != call.i) return FALSE; + + if (ABI_64_P (abfd)) + { + static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } }; + if (offset < 4 + || bfd_get_32 (abfd, contents + offset - 4) != leaq.i) + return FALSE; + } + else + { + static x86_64_opcode16 lea = { { 0x8d, 0x3d } }; + if (offset < 3 + || bfd_get_8 (abfd, contents + offset - 3) != 0x48 + || bfd_get_16 (abfd, contents + offset - 2) != lea.i) + return FALSE; + } } else { @@ -3434,15 +3450,26 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD) { - /* GD->LE transition. + /* GD->LE transition. For 64bit, change .byte 0x66; leaq foo@tlsgd(%rip), %rdi .word 0x6666; rex64; call __tls_get_addr - Change it into: + into: movq %fs:0, %rax + leaq foo@tpoff(%rax), %rax + For 32bit, change + leaq foo@tlsgd(%rip), %rdi + .word 0x6666; rex64; call __tls_get_addr + into: + movl %fs:0, %eax leaq foo@tpoff(%rax), %rax */ - memcpy (contents + roff - 4, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", - 16); + if (ABI_64_P (output_bfd)) + memcpy (contents + roff - 4, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", + 16); + else + memcpy (contents + roff - 3, + "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", + 15); bfd_put_32 (output_bfd, elf_x86_64_tpoff (info, relocation), contents + roff + 8); @@ -3670,15 +3697,26 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD) { - /* GD->IE transition. + /* GD->IE transition. For 64bit, change .byte 0x66; leaq foo@tlsgd(%rip), %rdi .word 0x6666; rex64; call __tls_get_addr@plt - Change it into: + into: movq %fs:0, %rax + addq foo@gottpoff(%rip), %rax + For 32bit, change + leaq foo@tlsgd(%rip), %rdi + .word 0x6666; rex64; call __tls_get_addr@plt + into: + movl %fs:0, %eax addq foo@gottpoff(%rip), %rax */ - memcpy (contents + roff - 4, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", - 16); + if (ABI_64_P (output_bfd)) + memcpy (contents + roff - 4, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", + 16); + else + memcpy (contents + roff - 3, + "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", + 15); relocation = (htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset + off @@ -3747,12 +3785,18 @@ elf_x86_64_relocate_section (bfd *output_bfd, { /* LD->LE transition: leaq foo@tlsld(%rip), %rdi; call __tls_get_addr. - We change it into: - .word 0x6666; .byte 0x66; movl %fs:0, %rax. */ + For 64bit, we change it into: + .word 0x6666; .byte 0x66; movq %fs:0, %rax. + For 32bit, we change it into: + nopl 0x0(%rax); movl %fs:0, %eax. */ BFD_ASSERT (r_type == R_X86_64_TPOFF32); - memcpy (contents + rel->r_offset - 3, - "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); + if (ABI_64_P (output_bfd)) + memcpy (contents + rel->r_offset - 3, + "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); + else + memcpy (contents + rel->r_offset - 3, + "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12); /* Skip R_X86_64_PC32/R_X86_64_PLT32. */ rel++; continue; diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index c5bad136857..603089ceddd 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,19 @@ +2011-03-12 H.J. Lu + + * ld-x86-64/tlsgd4.dd: New. + * ld-x86-64/tlsgd4.s: Likewise. + * ld-x86-64/tlsgd5.dd: Likewise. + * ld-x86-64/tlsgd5a.s: Likewise. + * ld-x86-64/tlsgd5b.s: Likewise. + * ld-x86-64/tlsgd6.dd: Likewise. + * ld-x86-64/tlsgd6a.s: Likewise. + * ld-x86-64/tlsgd6b.s: Likewise. + * ld-x86-64/tlsld2.dd: Likewise. + * ld-x86-64/tlsld2.s: Likewise. + + * ld-x86-64/x86-64.exp (x86_64tests): Add tlsgd4, libtlsgd5.so, + tlsgd5, libtlsgd6.so, tlsgd6 and tlsld2. + 2011-03-03 H.J. Lu * ld-x86-64/tlsie4.dd: New. diff --git a/ld/testsuite/ld-x86-64/tlsgd4.dd b/ld/testsuite/ld-x86-64/tlsgd4.dd new file mode 100644 index 00000000000..b8a99c89ec9 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd4.dd @@ -0,0 +1,10 @@ +#target: x86_64-*-linux* + +.*: +file format .* + +Disassembly of section .text: + +[a-f0-9]+ <_start>: +[ ]*[a-f0-9]+: 64 8b 04 25 00 00 00 00 mov %fs:0x0,%eax +[ ]*[a-f0-9]+: 48 8d 80 fc ff ff ff lea -0x4\(%rax\),%rax +#pass diff --git a/ld/testsuite/ld-x86-64/tlsgd4.s b/ld/testsuite/ld-x86-64/tlsgd4.s new file mode 100644 index 00000000000..037ce25a5b1 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd4.s @@ -0,0 +1,14 @@ + .text + .globl _start +_start: + leaq foo@TLSGD(%rip), %rdi + .word 0x6666 + rex64 + call __tls_get_addr + .globl foo + .section .tdata,"awT",@progbits + .align 4 + .type foo, @object + .size foo, 4 +foo: + .long 100 diff --git a/ld/testsuite/ld-x86-64/tlsgd5.dd b/ld/testsuite/ld-x86-64/tlsgd5.dd new file mode 100644 index 00000000000..7ca953a8f9e --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd5.dd @@ -0,0 +1,14 @@ +#source: tlsgd5a.s +#as: --64 +#ld: -melf_x86_64 tmpdir/tlsgd5 +#objdump: -drw +#target: x86_64-*-linux* + +.*: +file format .* + +Disassembly of section .text: + +[a-f0-9]+ <_start>: +[ ]*[a-f0-9]+: 64 48 8b 04 25 00 00 00 00 mov %fs:0x0,%rax +[ ]*[a-f0-9]+: 48 03 05 00 01 20 00 add 0x200100\(%rip\),%rax # 600368 <_DYNAMIC\+0x100> +#pass diff --git a/ld/testsuite/ld-x86-64/tlsgd5a.s b/ld/testsuite/ld-x86-64/tlsgd5a.s new file mode 100644 index 00000000000..b0f3fb22a2d --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd5a.s @@ -0,0 +1,8 @@ + .text + .globl _start +_start: + .byte 0x66 + leaq foo@TLSGD(%rip), %rdi + .word 0x6666 + rex64 + call __tls_get_addr diff --git a/ld/testsuite/ld-x86-64/tlsgd5b.s b/ld/testsuite/ld-x86-64/tlsgd5b.s new file mode 100644 index 00000000000..eb7fd5a4e10 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd5b.s @@ -0,0 +1,7 @@ + .globl foo + .section .tdata,"awT",@progbits + .align 4 + .type foo, @object + .size foo, 4 +foo: + .long 100 diff --git a/ld/testsuite/ld-x86-64/tlsgd6.dd b/ld/testsuite/ld-x86-64/tlsgd6.dd new file mode 100644 index 00000000000..e1d8238bc61 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd6.dd @@ -0,0 +1,14 @@ +#source: tlsgd6a.s +#as: --x32 +#ld: -melf32_x86_64 tmpdir/tlsgd6 +#objdump: -drw +#target: x86_64-*-linux* + +.*: +file format .* + +Disassembly of section .text: + +[a-f0-9]+ <_start>: +[ ]*[a-f0-9]+: 64 8b 04 25 00 00 00 00 mov %fs:0x0,%eax +[ ]*[a-f0-9]+: 48 03 05 81 00 20 00 add 0x200081\(%rip\),%rax # 60022c <_DYNAMIC\+0x80> +#pass diff --git a/ld/testsuite/ld-x86-64/tlsgd6a.s b/ld/testsuite/ld-x86-64/tlsgd6a.s new file mode 100644 index 00000000000..a0a8069bf50 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd6a.s @@ -0,0 +1,7 @@ + .text + .globl _start +_start: + leaq foo@TLSGD(%rip), %rdi + .word 0x6666 + rex64 + call __tls_get_addr diff --git a/ld/testsuite/ld-x86-64/tlsgd6b.s b/ld/testsuite/ld-x86-64/tlsgd6b.s new file mode 100644 index 00000000000..eb7fd5a4e10 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsgd6b.s @@ -0,0 +1,7 @@ + .globl foo + .section .tdata,"awT",@progbits + .align 4 + .type foo, @object + .size foo, 4 +foo: + .long 100 diff --git a/ld/testsuite/ld-x86-64/tlsld2.dd b/ld/testsuite/ld-x86-64/tlsld2.dd new file mode 100644 index 00000000000..3dbe3a8e383 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsld2.dd @@ -0,0 +1,14 @@ +#source: tlsld2.s +#as: --x32 +#ld: -melf32_x86_64 tmpdir/tlsld2 +#objdump: -drw +#target: x86_64-*-linux* + +.*: +file format .* + +Disassembly of section .text: + +[a-f0-9]+ <_start>: +[ ]*[a-f0-9]+: 0f 1f 40 00 nopl 0x0\(%rax\) +[ ]*[a-f0-9]+: 64 8b 04 25 00 00 00 00 mov %fs:0x0,%eax +#pass diff --git a/ld/testsuite/ld-x86-64/tlsld2.s b/ld/testsuite/ld-x86-64/tlsld2.s new file mode 100644 index 00000000000..6dcdd699aa1 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsld2.s @@ -0,0 +1,12 @@ + .text + .globl _start +_start: + leaq foo@TLSLD(%rip), %rdi + call __tls_get_addr + .globl foo + .section .tdata,"awT",@progbits + .align 4 + .type foo, @object + .size foo, 4 +foo: + .long 100 diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 43b9c393a43..8e977293205 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -90,6 +90,22 @@ set x86_64tests { {"TLS X32 IE->LE transition" "-melf32_x86_64" "--x32" {tlsie4.s} {{objdump -dwr tlsie4.dd}} "tlsie4"} + {"TLS X32 GD->LE transition" "-melf32_x86_64" + "--x32" {tlsgd4.s} + {{objdump -dwr tlsgd4.dd}} "tlsgd4"} + {"Helper TLS GD->IE transition DSO" "-shared -melf_x86_64" + "--64" {tlsgd5b.s} {} "libtlsgd5.so"} + {"TLS GD->IE transition" "-melf_x86_64 tmpdir/libtlsgd5.so" + "--64" {tlsgd5a.s} + {{objdump -dwr tlsgd5.dd}} "tlsgd5"} + {"Helper TLS X32 GD->IE transition DSO" "-shared -melf32_x86_64" + "--x32" {tlsgd6b.s} {} "libtlsgd6.so"} + {"TLS X32 GD->IE transition" "-melf32_x86_64 tmpdir/libtlsgd6.so" + "--x32" {tlsgd6a.s} + {{objdump -dwr tlsgd6.dd}} "tlsgd6"} + {"TLS X32 LD->LE transition" "-melf32_x86_64" + "--x32" {tlsld2.s} + {{objdump -dwr tlsld2.dd}} "tlsld2"} } run_ld_link_tests $x86_64tests -- 2.30.2