Support TLS x32 GD->IE, GD->LE and LD->LE transitions.
authorH.J. Lu <hjl.tools@gmail.com>
Sat, 12 Mar 2011 14:38:31 +0000 (14:38 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Sat, 12 Mar 2011 14:38:31 +0000 (14:38 +0000)
bfd/

2011-03-12  H.J. Lu  <hongjiu.lu@intel.com>

* 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  <hongjiu.lu@intel.com>

* 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.

14 files changed:
bfd/ChangeLog
bfd/elf64-x86-64.c
ld/testsuite/ChangeLog
ld/testsuite/ld-x86-64/tlsgd4.dd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsgd4.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsgd5.dd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsgd5a.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsgd5b.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsgd6.dd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsgd6a.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsgd6b.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsld2.dd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsld2.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index 3c4ba5f44dafdda5e3a26229ffbb50a3d846c4dc..b2b65b8105aa68ed5c4548f6dbf39426ac905816 100644 (file)
@@ -1,3 +1,10 @@
+2011-03-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * 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  <amodra@gmail.com>
 
        * elf64-ppc.c (ppc64_elf_relocate_section): Provide section/offset
index c26c40bb190589571c2d6ea65843b4648166c609..927b3ed4a5f0f984f78e43174faa4be0c3cb5ccb 100644 (file)
@@ -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;
index c5bad136857ae9a7d45d574fd2197465a9316e75..603089cedddf65b2aa2282e6bb60a8ad32bd5ed4 100644 (file)
@@ -1,3 +1,19 @@
+2011-03-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * 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  <hongjiu.lu@intel.com>
 
        * 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 (file)
index 0000000..b8a99c8
--- /dev/null
@@ -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 (file)
index 0000000..037ce25
--- /dev/null
@@ -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 (file)
index 0000000..7ca953a
--- /dev/null
@@ -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 (file)
index 0000000..b0f3fb2
--- /dev/null
@@ -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 (file)
index 0000000..eb7fd5a
--- /dev/null
@@ -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 (file)
index 0000000..e1d8238
--- /dev/null
@@ -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 (file)
index 0000000..a0a8069
--- /dev/null
@@ -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 (file)
index 0000000..eb7fd5a
--- /dev/null
@@ -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 (file)
index 0000000..3dbe3a8
--- /dev/null
@@ -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 (file)
index 0000000..6dcdd69
--- /dev/null
@@ -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
index 43b9c393a43bcc63c92ea36f524281d43a2b852d..8e9772932053101bf10b934d53abbc7d39480bee 100644 (file)
@@ -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