bfd/
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 23 Aug 2007 16:13:37 +0000 (16:13 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 23 Aug 2007 16:13:37 +0000 (16:13 +0000)
2007-08-23  H.J. Lu  <hongjiu.lu@intel.com>

* elf32-i386.c: Include "bfd_stdint.h".
(elf_i386_rtype_to_howto): New function.
(elf_i386_info_to_howto_rel): Use it.
(x86_64_opcode16): New union type.
(elf_i386_check_tls_transition): New function.
(elf_i386_tls_transition): Updated to check transition and
issue an error if a transition isn't supported.
(elf_i386_check_relocs): Return FALSE if
elf_i386_tls_transition returns FALSE.
(elf_i386_gc_sweep_hook): Likewise.
(elf_i386_relocate_section): Likewise. Remove BFD_ASSERT
on TLS transitions.

* elf64-x86-64.c: Include "bfd_stdint.h".
(x86_64_opcode16): New union type.
(x86_64_opcode32): Likewise.
(elf64_x86_64_check_tls_transition): New function.
(elf64_x86_64_tls_transition): Updated to check transition and
issue an error if a transition isn't supported.
(elf64_x86_64_check_relocs): Return FALSE if
elf64_x86_64_tls_transition returns FALSE.
(elf64_x86_64_gc_sweep_hook): Likewise.
(elf64_x86_64_relocate_section): Likewise. Remove BFD_ASSERT
on TLS transitions.

ld/testsuite/

2007-08-23  H.J. Lu  <hongjiu.lu@intel.com>

* ld-i386/tlsbinpic.s: Add a new GD -> IE test.

* ld-i386/tlsgd1.s: Add a new GD -> LE test.

* ld-i386/tlsbin.dd: Updated.
* ld-i386/tlsbin.rd: Likewise.
* ld-i386/tlsgd1.dd: Likewise.

bfd/ChangeLog
bfd/elf32-i386.c
bfd/elf64-x86-64.c
ld/testsuite/ChangeLog
ld/testsuite/ld-i386/tlsbin.dd
ld/testsuite/ld-i386/tlsbin.rd
ld/testsuite/ld-i386/tlsbinpic.s
ld/testsuite/ld-i386/tlsgd1.dd
ld/testsuite/ld-i386/tlsgd1.s

index a437ad8..71d760a 100644 (file)
@@ -1,3 +1,30 @@
+2007-08-23  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * elf32-i386.c: Include "bfd_stdint.h".
+       (elf_i386_rtype_to_howto): New function.
+       (elf_i386_info_to_howto_rel): Use it.
+       (x86_64_opcode16): New union type.
+       (elf_i386_check_tls_transition): New function.
+       (elf_i386_tls_transition): Updated to check transition and
+       issue an error if a transition isn't supported.
+       (elf_i386_check_relocs): Return FALSE if
+       elf_i386_tls_transition returns FALSE.
+       (elf_i386_gc_sweep_hook): Likewise.
+       (elf_i386_relocate_section): Likewise. Remove BFD_ASSERT
+       on TLS transitions.
+
+       * elf64-x86-64.c: Include "bfd_stdint.h".
+       (x86_64_opcode16): New union type.
+       (x86_64_opcode32): Likewise.
+       (elf64_x86_64_check_tls_transition): New function.
+       (elf64_x86_64_tls_transition): Updated to check transition and
+       issue an error if a transition isn't supported.
+       (elf64_x86_64_check_relocs): Return FALSE if
+       elf64_x86_64_tls_transition returns FALSE.
+       (elf64_x86_64_gc_sweep_hook): Likewise.
+       (elf64_x86_64_relocate_section): Likewise. Remove BFD_ASSERT
+       on TLS transitions.
+
 2007-08-22  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elfxx-ia64.c: Convert to ISO C90 prototypes.
index af3b860..072dc6f 100644 (file)
@@ -25,6 +25,7 @@
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "elf-vxworks.h"
+#include "bfd_stdint.h"
 
 /* 386 uses REL relocations instead of RELA.  */
 #define USE_REL        1
@@ -345,12 +346,9 @@ elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return NULL;
 }
 
-static void
-elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
-                           arelent *cache_ptr,
-                           Elf_Internal_Rela *dst)
+static reloc_howto_type *
+elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
 {
-  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
   unsigned int indx;
 
   if ((indx = r_type) >= R_386_standard
@@ -365,7 +363,17 @@ elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
                             abfd, (int) r_type);
       indx = R_386_NONE;
     }
-  cache_ptr->howto = &elf_howto_table[indx];
+  BFD_ASSERT (elf_howto_table [indx].type == r_type);
+  return &elf_howto_table[indx];
+}
+
+static void
+elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
+                           arelent *cache_ptr,
+                           Elf_Internal_Rela *dst)
+{
+  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
+  cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type);
 }
 
 /* Return whether a symbol name implies a local label.  The UnixWare
@@ -893,32 +901,293 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info,
     _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 }
 
-static int
-elf_i386_tls_transition (struct bfd_link_info *info, int r_type,
-                        struct elf_link_hash_entry *h)
+typedef union 
+  {
+    unsigned char c[2];
+    uint16_t i;
+  }
+i386_opcode16;
+
+/* Return TRUE if the TLS access code sequence support transition
+   from R_TYPE.  */
+
+static bfd_boolean
+elf_i386_check_tls_transition (bfd *abfd, asection *sec,
+                              bfd_byte *contents,
+                              Elf_Internal_Shdr *symtab_hdr,
+                              struct elf_link_hash_entry **sym_hashes,
+                              unsigned int r_type,
+                              const Elf_Internal_Rela *rel,
+                              const Elf_Internal_Rela *relend)
 {
-  if (info->shared)
-    return r_type;
+  unsigned int val, type;
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+  bfd_vma offset;
+
+  /* Get the section contents.  */
+  if (contents == NULL)
+    {
+      if (elf_section_data (sec)->this_hdr.contents != NULL)
+       contents = elf_section_data (sec)->this_hdr.contents;
+      else
+       {
+         /* FIXME: How to better handle error condition?  */
+         if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+           return FALSE;
 
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (sec)->this_hdr.contents = contents;
+       }
+    }
+
+  offset = rel->r_offset;
   switch (r_type)
     {
     case R_386_TLS_GD:
+    case R_386_TLS_LDM:
+      if (offset < 2 || (rel + 1) >= relend)
+       return FALSE;
+
+      type = bfd_get_8 (abfd, contents + offset - 2);
+      if (r_type == R_386_TLS_GD)
+       {
+         /* Check transition from LD access model.  Only
+               leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr
+               leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop
+            can transit to different access model.  */
+         if ((offset + 10) > sec->size ||
+             (type != 0x8d && type != 0x04))
+           return FALSE;
+
+         val = bfd_get_8 (abfd, contents + offset - 1);
+         if (type == 0x04)
+           {
+             /* leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr */
+             if (offset < 3)
+               return FALSE;
+
+             if (bfd_get_8 (abfd, contents + offset - 3) != 0x8d)
+               return FALSE;
+
+             if ((val & 0xc7) != 0x05 || val == (4 << 3))
+               return FALSE;
+           }
+         else
+           {
+             /* leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop  */
+             if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+               return FALSE;
+
+             if (bfd_get_8 (abfd, contents + offset + 9) != 0x90)
+               return FALSE;
+           }
+       }
+      else
+       {
+         /* Check transition from LD access model.  Only
+               leal foo@tlsgd(%reg), %eax; call ___tls_get_addr
+            can transit to different access model.  */
+         if (type != 0x8d || (offset + 9) > sec->size)
+           return FALSE;
+
+         val = bfd_get_8 (abfd, contents + offset - 1);
+         if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+           return FALSE;
+       }
+
+      if (bfd_get_8 (abfd, contents + offset + 4) != 0xe8)
+       return FALSE;
+
+      r_symndx = ELF32_R_SYM (rel[1].r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+       return FALSE;
+
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      return (h != NULL
+             && h->root.root.string != NULL
+             && (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
+                 || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32)
+             && (strcmp (h->root.root.string, "___tls_get_addr") == 0));
+
+    case R_386_TLS_IE:
+      /* Check transition from IE access model:
+               movl foo@indntpoff(%rip), %eax
+               movl foo@indntpoff(%rip), %reg
+               addl foo@indntpoff(%rip), %reg
+       */
+
+      if (offset < 1 || (offset + 4) > sec->size)
+       return FALSE;
+
+      /* Check "movl foo@tpoff(%rip), %eax" first.  */
+      val = bfd_get_8 (abfd, contents + offset - 1);
+      if (val == 0xa1)
+       return TRUE;
+
+      if (offset < 2)
+       return FALSE;
+
+      /* Check movl|addl foo@tpoff(%rip), %reg.   */
+      type = bfd_get_8 (abfd, contents + offset - 2);
+      return ((type == 0x8b || type == 0x03)
+             && (val & 0xc7) == 0x05);
+
+    case R_386_TLS_GOTIE:
+    case R_386_TLS_IE_32:
+      /* Check transition from {IE_32,GOTIE} access model:
+               subl foo@{tpoff,gontoff}(%reg1), %reg2
+               movl foo@{tpoff,gontoff}(%reg1), %reg2
+               addl foo@{tpoff,gontoff}(%reg1), %reg2
+       */
+
+      if (offset < 2 || (offset + 4) > sec->size)
+       return FALSE;
+
+      val = bfd_get_8 (abfd, contents + offset - 1);
+      if ((val & 0xc0) != 0x80 || (val & 7) == 4)
+       return FALSE;
+
+      type = bfd_get_8 (abfd, contents + offset - 2);
+      return type == 0x8b || type == 0x2b || type == 0x03;
+
+    case R_386_TLS_GOTDESC:
+      /* Check transition from GDesc access model:
+               leal x@tlsdesc(%ebx), %eax
+
+        Make sure it's a leal adding ebx to a 32-bit offset
+        into any register, although it's probably almost always
+        going to be eax.  */
+
+      if (offset < 2 || (offset + 4) > sec->size)
+       return FALSE;
+
+      if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d)
+       return FALSE;
+
+      val = bfd_get_8 (abfd, contents + offset - 1);
+      return (val & 0xc7) == 0x83;
+
+    case R_386_TLS_DESC_CALL:
+      /* Check transition from GDesc access model:
+               call *x@tlsdesc(%rax)
+       */
+      if (offset + 2 <= sec->size)
+       {
+         /* Make sure that it's a call *x@tlsdesc(%rax).  */
+         static i386_opcode16 call = { { 0xff, 0x10 } };
+         return bfd_get_16 (abfd, contents + offset) == call.i;
+       }
+
+      return FALSE;
+
+    default:
+      abort ();
+    }
+}
+
+/* Return TRUE if the TLS access transition is OK or no transition
+   will be performed.  Update R_TYPE if there is a transition.  */
+
+static bfd_boolean
+elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
+                        asection *sec, bfd_byte *contents,
+                        Elf_Internal_Shdr *symtab_hdr,
+                        struct elf_link_hash_entry **sym_hashes,
+                        unsigned int *r_type, int tls_type,
+                        const Elf_Internal_Rela *rel,
+                        const Elf_Internal_Rela *relend,
+                        struct elf_link_hash_entry *h)
+{
+  unsigned int from_type = *r_type;
+  unsigned int to_type = from_type;
+  bfd_boolean check = TRUE;
+
+  switch (from_type)
+    {
+    case R_386_TLS_GD:
     case R_386_TLS_GOTDESC:
     case R_386_TLS_DESC_CALL:
     case R_386_TLS_IE_32:
-      if (h == NULL)
-       return R_386_TLS_LE_32;
-      return R_386_TLS_IE_32;
     case R_386_TLS_IE:
     case R_386_TLS_GOTIE:
-      if (h == NULL)
-       return R_386_TLS_LE_32;
-      return r_type;
+      if (!info->shared)
+       {
+         if (h == NULL)
+           to_type = R_386_TLS_LE_32;
+         else if (from_type != R_386_TLS_IE
+                  && from_type != R_386_TLS_GOTIE)
+           to_type = R_386_TLS_IE_32;
+       }
+
+      /* When we are called from elf_i386_relocate_section, CONTENTS
+        isn't NULL and there may be additional transitions based on
+        TLS_TYPE.  */
+      if (contents != NULL)
+       {
+         unsigned int new_to_type = to_type;
+
+         if (!info->shared
+             && h != NULL
+             && h->dynindx == -1
+             && (tls_type & GOT_TLS_IE))
+           new_to_type = R_386_TLS_LE_32;
+
+         if (to_type == R_386_TLS_GD
+             || to_type == R_386_TLS_GOTDESC
+             || to_type == R_386_TLS_DESC_CALL)
+           {
+             if (tls_type == GOT_TLS_IE_POS)
+               new_to_type = R_386_TLS_GOTIE;
+             else if (tls_type & GOT_TLS_IE)
+               new_to_type = R_386_TLS_IE_32;
+           }
+
+         /* We checked the transition before when we were called from
+            elf_i386_check_relocs.  We only want to check the new
+            transition which hasn't been checked before.  */
+         check = new_to_type != to_type && from_type == to_type;
+         to_type = new_to_type;
+       }
+
+      break;
+
     case R_386_TLS_LDM:
-      return R_386_TLS_LE_32;
+      if (!info->shared)
+       to_type = R_386_TLS_LE_32;
+      break;
+
+    default:
+      return TRUE;
+    }
+
+  /* Return TRUE if there is no transition.  */
+  if (from_type == to_type)
+    return TRUE;
+
+  /* Check if the transition can be performed.  */
+  if (check
+      && ! elf_i386_check_tls_transition (abfd, sec, contents,
+                                         symtab_hdr, sym_hashes,
+                                         from_type, rel, relend))
+    {
+      const reloc_howto_type *from, *to;
+
+      from = elf_i386_rtype_to_howto (abfd, from_type);
+      to = elf_i386_rtype_to_howto (abfd, to_type);
+
+      (*_bfd_error_handler)
+       (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
+          "in section `%A' failed"),
+        abfd, sec, from->name, to->name,
+        h ? h->root.root.string : "a local symbol",
+        (unsigned long) rel->r_offset);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
     }
 
-  return r_type;
+  *r_type = to_type;
+  return TRUE;
 }
 
 /* Look through the relocs for a section during the first phase, and
@@ -975,7 +1244,11 @@ elf_i386_check_relocs (bfd *abfd,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
-      r_type = elf_i386_tls_transition (info, r_type, h);
+      if (! elf_i386_tls_transition (info, abfd, sec, NULL,
+                                    symtab_hdr, sym_hashes,
+                                    &r_type, GOT_UNKNOWN,
+                                    rel, rel_end, h)) 
+       return FALSE;
 
       switch (r_type)
        {
@@ -1364,7 +1637,12 @@ elf_i386_gc_sweep_hook (bfd *abfd,
        }
 
       r_type = ELF32_R_TYPE (rel->r_info);
-      r_type = elf_i386_tls_transition (info, r_type, h);
+      if (! elf_i386_tls_transition (info, abfd, sec, NULL,
+                                    symtab_hdr, sym_hashes,
+                                    &r_type, GOT_UNKNOWN,
+                                    rel, relend, h)) 
+       return FALSE;
+
       switch (r_type)
        {
        case R_386_TLS_LDM:
@@ -2624,98 +2902,50 @@ elf_i386_relocate_section (bfd *output_bfd,
        case R_386_TLS_DESC_CALL:
        case R_386_TLS_IE_32:
        case R_386_TLS_GOTIE:
-         r_type = elf_i386_tls_transition (info, r_type, h);
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
            tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx];
          else if (h != NULL)
-           {
-             tls_type = elf_i386_hash_entry(h)->tls_type;
-             if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE))
-               r_type = R_386_TLS_LE_32;
-           }
+           tls_type = elf_i386_hash_entry(h)->tls_type;
          if (tls_type == GOT_TLS_IE)
            tls_type = GOT_TLS_IE_NEG;
-         if (r_type == R_386_TLS_GD
-             || r_type == R_386_TLS_GOTDESC
-             || r_type == R_386_TLS_DESC_CALL)
-           {
-             if (tls_type == GOT_TLS_IE_POS)
-               r_type = R_386_TLS_GOTIE;
-             else if (tls_type & GOT_TLS_IE)
-               r_type = R_386_TLS_IE_32;
-           }
+
+         if (! elf_i386_tls_transition (info, input_bfd,
+                                        input_section, contents,
+                                        symtab_hdr, sym_hashes,
+                                        &r_type, tls_type, rel,
+                                        relend, h))
+           return FALSE;
 
          if (r_type == R_386_TLS_LE_32)
            {
              BFD_ASSERT (! unresolved_reloc);
              if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
                {
-                 unsigned int val, type;
+                 unsigned int type;
                  bfd_vma roff;
-                 unsigned long tls_r_symndx;
-                 struct elf_link_hash_entry *tls_h;
 
                  /* GD->LE transition.  */
-                 BFD_ASSERT (rel->r_offset >= 2);
                  type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
-                 BFD_ASSERT (type == 0x8d || type == 0x04);
-                 BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
-                 BFD_ASSERT (bfd_get_8 (input_bfd,
-                                        contents + rel->r_offset + 4)
-                             == 0xe8);
-                 BFD_ASSERT (rel + 1 < relend);
-                 tls_r_symndx = ELF32_R_SYM (rel[1].r_info);
-                 BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
-                 tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
-                 BFD_ASSERT (tls_h != NULL
-                             && tls_h->root.root.string != NULL
-                             && strcmp (tls_h->root.root.string,
-                                        "___tls_get_addr") == 0);
-                 BFD_ASSERT ((! info->shared
-                              && ELF32_R_TYPE (rel[1].r_info) == R_386_PC32)
-                             || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
-                 roff = rel->r_offset + 5;
-                 val = bfd_get_8 (input_bfd,
-                                  contents + rel->r_offset - 1);
                  if (type == 0x04)
                    {
                      /* leal foo(,%reg,1), %eax; call ___tls_get_addr
                         Change it into:
                         movl %gs:0, %eax; subl $foo@tpoff, %eax
                         (6 byte form of subl).  */
-                     BFD_ASSERT (rel->r_offset >= 3);
-                     BFD_ASSERT (bfd_get_8 (input_bfd,
-                                            contents + rel->r_offset - 3)
-                                 == 0x8d);
-                     BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
                      memcpy (contents + rel->r_offset - 3,
                              "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+                     roff = rel->r_offset + 5;
                    }
                  else
                    {
-                     BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
-                     if (rel->r_offset + 10 <= input_section->size
-                         && bfd_get_8 (input_bfd,
-                                       contents + rel->r_offset + 9) == 0x90)
-                       {
-                         /* leal foo(%reg), %eax; call ___tls_get_addr; nop
-                            Change it into:
-                            movl %gs:0, %eax; subl $foo@tpoff, %eax
-                            (6 byte form of subl).  */
-                         memcpy (contents + rel->r_offset - 2,
-                                 "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
-                         roff = rel->r_offset + 6;
-                       }
-                     else
-                       {
-                         /* leal foo(%reg), %eax; call ___tls_get_addr
-                            Change it into:
-                            movl %gs:0, %eax; subl $foo@tpoff, %eax
-                            (5 byte form of subl).  */
-                         memcpy (contents + rel->r_offset - 2,
-                                 "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
-                       }
+                     /* leal foo(%reg), %eax; call ___tls_get_addr; nop
+                        Change it into:
+                        movl %gs:0, %eax; subl $foo@tpoff, %eax
+                        (6 byte form of subl).  */
+                     memcpy (contents + rel->r_offset - 2,
+                             "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+                     roff = rel->r_offset + 6;
                    }
                  bfd_put_32 (output_bfd, tpoff (info, relocation),
                              contents + roff);
@@ -2733,19 +2963,11 @@ elf_i386_relocate_section (bfd *output_bfd,
 
                     Registers other than %eax may be set up here.  */
 
-                 unsigned int val, type;
+                 unsigned int val;
                  bfd_vma roff;
 
-                 /* First, make sure it's a leal adding ebx to a
-                    32-bit offset into any register, although it's
-                    probably almost always going to be eax.  */
                  roff = rel->r_offset;
-                 BFD_ASSERT (roff >= 2);
-                 type = bfd_get_8 (input_bfd, contents + roff - 2);
-                 BFD_ASSERT (type == 0x8d);
                  val = bfd_get_8 (input_bfd, contents + roff - 1);
-                 BFD_ASSERT ((val & 0xc7) == 0x83);
-                 BFD_ASSERT (roff + 4 <= input_section->size);
 
                  /* Now modify the instruction as appropriate.  */
                  /* aoliva FIXME: remove the above and xor the byte
@@ -2762,28 +2984,18 @@ elf_i386_relocate_section (bfd *output_bfd,
                     It's originally:
                     call *(%eax)
                     Turn it into:
-                    nop; nop  */
+                    xchg %ax,%ax  */
 
-                 unsigned int val, type;
                  bfd_vma roff;
-
-                 /* First, make sure it's a call *(%eax).  */
+                 
                  roff = rel->r_offset;
-                 BFD_ASSERT (roff + 2 <= input_section->size);
-                 type = bfd_get_8 (input_bfd, contents + roff);
-                 BFD_ASSERT (type == 0xff);
-                 val = bfd_get_8 (input_bfd, contents + roff + 1);
-                 BFD_ASSERT (val == 0x10);
-
-                 /* Now modify the instruction as appropriate.  Use
-                    xchg %ax,%ax instead of 2 nops.  */
                  bfd_put_8 (output_bfd, 0x66, contents + roff);
                  bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
                  continue;
                }
              else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
                {
-                 unsigned int val, type;
+                 unsigned int val;
 
                  /* IE->LE transition:
                     Originally it can be one of:
@@ -2794,9 +3006,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                     movl $foo, %eax
                     movl $foo, %reg
                     addl $foo, %reg.  */
-                 BFD_ASSERT (rel->r_offset >= 1);
                  val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
-                 BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
                  if (val == 0xa1)
                    {
                      /* movl foo, %eax.  */
@@ -2805,14 +3015,14 @@ elf_i386_relocate_section (bfd *output_bfd,
                    }
                  else
                    {
-                     BFD_ASSERT (rel->r_offset >= 2);
+                     unsigned int type;
+
                      type = bfd_get_8 (input_bfd,
                                        contents + rel->r_offset - 2);
                      switch (type)
                        {
                        case 0x8b:
                          /* movl */
-                         BFD_ASSERT ((val & 0xc7) == 0x05);
                          bfd_put_8 (output_bfd, 0xc7,
                                     contents + rel->r_offset - 2);
                          bfd_put_8 (output_bfd,
@@ -2821,7 +3031,6 @@ elf_i386_relocate_section (bfd *output_bfd,
                          break;
                        case 0x03:
                          /* addl */
-                         BFD_ASSERT ((val & 0xc7) == 0x05);
                          bfd_put_8 (output_bfd, 0x81,
                                     contents + rel->r_offset - 2);
                          bfd_put_8 (output_bfd,
@@ -2850,11 +3059,8 @@ elf_i386_relocate_section (bfd *output_bfd,
                     subl $foo, %reg2
                     movl $foo, %reg2 (6 byte form)
                     addl $foo, %reg2.  */
-                 BFD_ASSERT (rel->r_offset >= 2);
                  type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
                  val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
-                 BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
-                 BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
                  if (type == 0x8b)
                    {
                      /* movl */
@@ -3055,38 +3261,21 @@ elf_i386_relocate_section (bfd *output_bfd,
              bfd_vma roff;
 
              /* GD->IE transition.  */
-             BFD_ASSERT (rel->r_offset >= 2);
              type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
-             BFD_ASSERT (type == 0x8d || type == 0x04);
-             BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
-             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
-                         == 0xe8);
-             BFD_ASSERT (rel + 1 < relend);
-             BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
-             roff = rel->r_offset - 3;
              val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
              if (type == 0x04)
                {
                  /* leal foo(,%reg,1), %eax; call ___tls_get_addr
                     Change it into:
                     movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax.  */
-                 BFD_ASSERT (rel->r_offset >= 3);
-                 BFD_ASSERT (bfd_get_8 (input_bfd,
-                                        contents + rel->r_offset - 3)
-                             == 0x8d);
-                 BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
                  val >>= 3;
+                 roff = rel->r_offset - 3;
                }
              else
                {
                  /* leal foo(%reg), %eax; call ___tls_get_addr; nop
                     Change it into:
                     movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax.  */
-                 BFD_ASSERT (rel->r_offset + 10 <= input_section->size);
-                 BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
-                 BFD_ASSERT (bfd_get_8 (input_bfd,
-                                        contents + rel->r_offset + 9)
-                             == 0x90);
                  roff = rel->r_offset - 2;
                }
              memcpy (contents + roff,
@@ -3116,25 +3305,18 @@ elf_i386_relocate_section (bfd *output_bfd,
                 leal x@tlsdesc(%ebx), %eax
 
                 Change it to:
-                movl x@gotntpoff(%ebx), %eax # before nop; nop
+                movl x@gotntpoff(%ebx), %eax # before xchg %ax,%ax
                 or:
                 movl x@gottpoff(%ebx), %eax # before negl %eax
 
                 Registers other than %eax may be set up here.  */
 
-             unsigned int val, type;
              bfd_vma roff;
 
              /* First, make sure it's a leal adding ebx to a 32-bit
                 offset into any register, although it's probably
                 almost always going to be eax.  */
              roff = rel->r_offset;
-             BFD_ASSERT (roff >= 2);
-             type = bfd_get_8 (input_bfd, contents + roff - 2);
-             BFD_ASSERT (type == 0x8d);
-             val = bfd_get_8 (input_bfd, contents + roff - 1);
-             BFD_ASSERT ((val & 0xc7) == 0x83);
-             BFD_ASSERT (roff + 4 <= input_section->size);
 
              /* Now modify the instruction as appropriate.  */
              /* To turn a leal into a movl in the form we use it, it
@@ -3162,22 +3344,15 @@ elf_i386_relocate_section (bfd *output_bfd,
                 call *(%eax)
 
                 Change it to:
-                nop; nop
+                xchg %ax,%ax
                 or
                 negl %eax
                 depending on how we transformed the TLS_GOTDESC above.
              */
 
-             unsigned int val, type;
              bfd_vma roff;
 
-             /* First, make sure it's a call *(%eax).  */
              roff = rel->r_offset;
-             BFD_ASSERT (roff + 2 <= input_section->size);
-             type = bfd_get_8 (input_bfd, contents + roff);
-             BFD_ASSERT (type == 0xff);
-             val = bfd_get_8 (input_bfd, contents + roff + 1);
-             BFD_ASSERT (val == 0x10);
 
              /* Now modify the instruction as appropriate.  */
              if (tls_type != GOT_TLS_IE_NEG)
@@ -3200,35 +3375,20 @@ elf_i386_relocate_section (bfd *output_bfd,
          break;
 
        case R_386_TLS_LDM:
-         if (! info->shared)
-           {
-             unsigned int val;
-             unsigned long tls_r_symndx;
-             struct elf_link_hash_entry *tls_h;
+         if (! elf_i386_tls_transition (info, input_bfd,
+                                        input_section, contents,
+                                        symtab_hdr, sym_hashes,
+                                        &r_type, GOT_UNKNOWN, rel,
+                                        relend, h))
+           return FALSE;
 
+         if (r_type != R_386_TLS_LDM)
+           {
              /* LD->LE transition:
-                Ensure it is:
                 leal foo(%reg), %eax; call ___tls_get_addr.
                 We change it into:
                 movl %gs:0, %eax; nop; leal 0(%esi,1), %esi.  */
-             BFD_ASSERT (rel->r_offset >= 2);
-             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2)
-                         == 0x8d);
-             val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
-             BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
-             BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
-             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
-                         == 0xe8);
-             BFD_ASSERT (rel + 1 < relend);
-             tls_r_symndx = ELF32_R_SYM (rel[1].r_info);
-             BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
-             tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
-             BFD_ASSERT (tls_h != NULL
-                         && tls_h->root.root.string != NULL
-                         && strcmp (tls_h->root.root.string,
-                                    "___tls_get_addr") == 0);
-             BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
-                         || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+             BFD_ASSERT (r_type == R_386_TLS_LE_32);
              memcpy (contents + rel->r_offset - 2,
                      "\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
              /* Skip R_386_PC32/R_386_PLT32.  */
index d73b270..34eae58 100644 (file)
@@ -25,6 +25,7 @@
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
+#include "bfd_stdint.h"
 
 #include "elf/x86-64.h"
 
@@ -712,27 +713,262 @@ elf64_x86_64_elf_object_p (bfd *abfd)
   return TRUE;
 }
 
-static int
-elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type,
-                            struct elf_link_hash_entry *h)
+typedef union
+  {
+    unsigned char c[2];
+    uint16_t i;
+  }
+x86_64_opcode16;
+
+typedef union
+  {
+    unsigned char c[4];
+    uint32_t i;
+  }
+x86_64_opcode32;
+
+/* Return TRUE if the TLS access code sequence support transition
+   from R_TYPE.  */
+
+static bfd_boolean
+elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
+                                  bfd_byte *contents,
+                                  Elf_Internal_Shdr *symtab_hdr,
+                                  struct elf_link_hash_entry **sym_hashes,
+                                  unsigned int r_type,
+                                  const Elf_Internal_Rela *rel,
+                                  const Elf_Internal_Rela *relend)
 {
-  if (info->shared)
-    return r_type;
+  unsigned int val;
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+  bfd_vma offset;
 
+  /* Get the section contents.  */
+  if (contents == NULL)
+    {
+      if (elf_section_data (sec)->this_hdr.contents != NULL)
+       contents = elf_section_data (sec)->this_hdr.contents;
+      else
+       {
+         /* FIXME: How to better handle error condition?  */
+         if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+           return FALSE;
+
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (sec)->this_hdr.contents = contents;
+       }
+    }
+
+  offset = rel->r_offset;
   switch (r_type)
     {
     case R_X86_64_TLSGD:
+    case R_X86_64_TLSLD:
+      if ((rel + 1) >= relend)
+       return FALSE;
+
+      if (r_type == R_X86_64_TLSGD)
+       {
+         /* Check transition from GD access model.  Only
+               .byte 0x66; 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
+             || bfd_get_32 (abfd, contents + offset + 4) != call.i)
+           return FALSE;
+       }
+      else
+       {
+         /* Check transition from LD access model.  Only
+               leaq foo@tlsld(%rip), %rdi;
+               call __tls_get_addr
+            can transit to different access model.  */
+
+         static x86_64_opcode32 ld = { { 0x48, 0x8d, 0x3d, 0xe8 } };
+         x86_64_opcode32 op;
+
+         if (offset < 3 || (offset + 9) > sec->size)
+           return FALSE;
+
+         op.i = bfd_get_32 (abfd, contents + offset - 3);
+         op.c[3] = bfd_get_8 (abfd, contents + offset + 4);
+         if (op.i != ld.i)
+           return FALSE;
+       }
+
+      r_symndx = ELF64_R_SYM (rel[1].r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+       return FALSE;
+
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      return (h != NULL
+             && h->root.root.string != NULL
+             && (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
+                 || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)
+             && (strcmp (h->root.root.string, "__tls_get_addr") == 0));
+
+    case R_X86_64_GOTTPOFF:
+      /* Check transition from IE access model:
+               movq foo@gottpoff(%rip), %reg
+               addq foo@gottpoff(%rip), %reg
+       */
+
+      if (offset < 3 || (offset + 4) > sec->size)
+       return FALSE;
+
+      val = bfd_get_8 (abfd, contents + offset - 3);
+      if (val != 0x48 && val != 0x4c)
+       return FALSE;
+
+      val = bfd_get_8 (abfd, contents + offset - 2);
+      if (val != 0x8b && val != 0x03)
+       return FALSE;
+
+      val = bfd_get_8 (abfd, contents + offset - 1);
+      return (val & 0xc7) == 5;
+
+    case R_X86_64_GOTPC32_TLSDESC:
+      /* Check transition from GDesc access model:
+               leaq x@tlsdesc(%rip), %rax
+
+        Make sure it's a leaq adding rip to a 32-bit offset
+        into any register, although it's probably almost always
+        going to be rax.  */
+
+      if (offset < 3 || (offset + 4) > sec->size)
+       return FALSE;
+
+      val = bfd_get_8 (abfd, contents + offset - 3);
+      if ((val & 0xfb) != 0x48)
+       return FALSE;
+
+      if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d)
+       return FALSE;
+
+      val = bfd_get_8 (abfd, contents + offset - 1);
+      return (val & 0xc7) == 0x05;
+
+    case R_X86_64_TLSDESC_CALL:
+      /* Check transition from GDesc access model:
+               call *x@tlsdesc(%rax)
+       */
+      if (offset + 2 <= sec->size)
+       {
+         /* Make sure that it's a call *x@tlsdesc(%rax).  */
+         static x86_64_opcode16 call = { { 0xff, 0x10 } };
+         return bfd_get_16 (abfd, contents + offset) == call.i;
+       }
+
+      return FALSE;
+
+    default:
+      abort ();
+    }
+}
+
+/* Return TRUE if the TLS access transition is OK or no transition
+   will be performed.  Update R_TYPE if there is a transition.  */
+
+static bfd_boolean
+elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
+                            asection *sec, bfd_byte *contents,
+                            Elf_Internal_Shdr *symtab_hdr,
+                            struct elf_link_hash_entry **sym_hashes,
+                            unsigned int *r_type, int tls_type,
+                            const Elf_Internal_Rela *rel,
+                            const Elf_Internal_Rela *relend,
+                            struct elf_link_hash_entry *h)
+{
+  unsigned int from_type = *r_type;
+  unsigned int to_type = from_type;
+  bfd_boolean check = TRUE;
+
+  switch (from_type)
+    {
+    case R_X86_64_TLSGD:
     case R_X86_64_GOTPC32_TLSDESC:
     case R_X86_64_TLSDESC_CALL:
     case R_X86_64_GOTTPOFF:
-      if (h == NULL)
-       return R_X86_64_TPOFF32;
-      return R_X86_64_GOTTPOFF;
+      if (!info->shared)
+       {
+         if (h == NULL)
+           to_type = R_X86_64_TPOFF32;
+         else
+           to_type = R_X86_64_GOTTPOFF;
+       }
+
+      /* When we are called from elf64_x86_64_relocate_section,
+        CONTENTS isn't NULL and there may be additional transitions
+        based on TLS_TYPE.  */
+      if (contents != NULL)
+       {
+         unsigned int new_to_type = to_type;
+
+         if (!info->shared
+             && h != NULL
+             && h->dynindx == -1
+             && tls_type == GOT_TLS_IE)
+           new_to_type = R_X86_64_TPOFF32;
+
+         if (to_type == R_X86_64_TLSGD
+             || to_type == R_X86_64_GOTPC32_TLSDESC
+             || to_type == R_X86_64_TLSDESC_CALL)
+           {
+             if (tls_type == GOT_TLS_IE)
+               new_to_type = R_X86_64_GOTTPOFF;
+           }
+
+         /* We checked the transition before when we were called from
+            elf64_x86_64_check_relocs.  We only want to check the new
+            transition which hasn't been checked before.  */
+         check = new_to_type != to_type && from_type == to_type;
+         to_type = new_to_type;
+       }
+
+      break;
+
     case R_X86_64_TLSLD:
-      return R_X86_64_TPOFF32;
+      if (!info->shared)
+       to_type = R_X86_64_TPOFF32;
+      break;
+
+    default:
+      return TRUE;
+    }
+
+  /* Return TRUE if there is no transition.  */
+  if (from_type == to_type)
+    return TRUE;
+
+  /* Check if the transition can be performed.  */
+  if (check
+      && ! elf64_x86_64_check_tls_transition (abfd, sec, contents,
+                                             symtab_hdr, sym_hashes,
+                                             from_type, rel, relend))
+    {
+      const reloc_howto_type *from, *to;
+
+      from = elf64_x86_64_rtype_to_howto (abfd, from_type);
+      to = elf64_x86_64_rtype_to_howto (abfd, to_type);
+
+      (*_bfd_error_handler)
+       (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
+          "in section `%A' failed"),
+        abfd, sec, from->name, to->name,
+        h ? h->root.root.string : "a local symbol",
+        (unsigned long) rel->r_offset);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
     }
 
-   return r_type;
+  *r_type = to_type;
+  return TRUE;
 }
 
 /* Look through the relocs for a section during the first phase, and
@@ -740,7 +976,8 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type,
    linkage table, and dynamic reloc sections.  */
 
 static bfd_boolean
-elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
+elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
+                          asection *sec,
                           const Elf_Internal_Rela *relocs)
 {
   struct elf64_x86_64_link_hash_table *htab;
@@ -786,7 +1023,12 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
-      r_type = elf64_x86_64_tls_transition (info, r_type, h);
+      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
+                                        symtab_hdr, sym_hashes,
+                                        &r_type, GOT_UNKNOWN,
+                                        rel, rel_end, h))
+       return FALSE;
+
       switch (r_type)
        {
        case R_X86_64_TLSLD:
@@ -1173,7 +1415,8 @@ elf64_x86_64_gc_mark_hook (asection *sec,
 
 static bfd_boolean
 elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
-                           asection *sec, const Elf_Internal_Rela *relocs)
+                           asection *sec,
+                           const Elf_Internal_Rela *relocs)
 {
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
@@ -1216,7 +1459,12 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        }
 
       r_type = ELF64_R_TYPE (rel->r_info);
-      r_type = elf64_x86_64_tls_transition (info, r_type, h);
+      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
+                                        symtab_hdr, sym_hashes,
+                                        &r_type, GOT_UNKNOWN,
+                                        rel, relend, h))
+       return FALSE;
+
       switch (r_type)
        {
        case R_X86_64_TLSLD:
@@ -2502,67 +2750,38 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_X86_64_GOTPC32_TLSDESC:
        case R_X86_64_TLSDESC_CALL:
        case R_X86_64_GOTTPOFF:
-         r_type = elf64_x86_64_tls_transition (info, r_type, h);
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
            tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
          else if (h != NULL)
-           {
-             tls_type = elf64_x86_64_hash_entry (h)->tls_type;
-             if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE)
-               r_type = R_X86_64_TPOFF32;
-           }
-         if (r_type == R_X86_64_TLSGD
-             || r_type == R_X86_64_GOTPC32_TLSDESC
-             || r_type == R_X86_64_TLSDESC_CALL)
-           {
-             if (tls_type == GOT_TLS_IE)
-               r_type = R_X86_64_GOTTPOFF;
-           }
+           tls_type = elf64_x86_64_hash_entry (h)->tls_type;
+
+         if (! elf64_x86_64_tls_transition (info, input_bfd,
+                                            input_section, contents,
+                                            symtab_hdr, sym_hashes,
+                                            &r_type, tls_type, rel,
+                                            relend, h))
+             return FALSE;
 
          if (r_type == R_X86_64_TPOFF32)
            {
+             bfd_vma roff = rel->r_offset;
+
              BFD_ASSERT (! unresolved_reloc);
+
              if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
                {
-                 unsigned int i;
-                 static unsigned char tlsgd[8]
-                   = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 };
-                 unsigned long tls_r_symndx;
-                 struct elf_link_hash_entry *tls_h;
-
                  /* GD->LE transition.
                     .byte 0x66; leaq foo@tlsgd(%rip), %rdi
                     .word 0x6666; rex64; call __tls_get_addr
                     Change it into:
                     movq %fs:0, %rax
                     leaq foo@tpoff(%rax), %rax */
-                 BFD_ASSERT (rel->r_offset >= 4);
-                 for (i = 0; i < 4; i++)
-                   BFD_ASSERT (bfd_get_8 (input_bfd,
-                                          contents + rel->r_offset - 4 + i)
-                               == tlsgd[i]);
-                 BFD_ASSERT (rel->r_offset + 12 <= input_section->size);
-                 for (i = 0; i < 4; i++)
-                   BFD_ASSERT (bfd_get_8 (input_bfd,
-                                          contents + rel->r_offset + 4 + i)
-                               == tlsgd[i+4]);
-                 BFD_ASSERT (rel + 1 < relend);
-                 tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
-                 BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
-                 tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
-                 BFD_ASSERT (tls_h != NULL
-                             && tls_h->root.root.string != NULL
-                             && strcmp (tls_h->root.root.string,
-                                        "__tls_get_addr") == 0);
-                 BFD_ASSERT ((! info->shared
-                              && ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32)
-                             || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
-                 memcpy (contents + rel->r_offset - 4,
+                 memcpy (contents + roff - 4,
                          "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
                          16);
                  bfd_put_32 (output_bfd, tpoff (info, relocation),
-                             contents + rel->r_offset + 8);
+                             contents + roff + 8);
                  /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
                  rel++;
                  continue;
@@ -2575,26 +2794,13 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
                     Change it to:
                     movl $x@tpoff, %rax
-
-                    Registers other than %rax may be set up here.  */
+                  */
 
                  unsigned int val, type, type2;
-                 bfd_vma roff;
 
-                 /* First, make sure it's a leaq adding rip to a
-                    32-bit offset into any register, although it's
-                    probably almost always going to be rax.  */
-                 roff = rel->r_offset;
-                 BFD_ASSERT (roff >= 3);
                  type = bfd_get_8 (input_bfd, contents + roff - 3);
-                 BFD_ASSERT ((type & 0xfb) == 0x48);
                  type2 = bfd_get_8 (input_bfd, contents + roff - 2);
-                 BFD_ASSERT (type2 == 0x8d);
                  val = bfd_get_8 (input_bfd, contents + roff - 1);
-                 BFD_ASSERT ((val & 0xc7) == 0x05);
-                 BFD_ASSERT (roff + 4 <= input_section->size);
-
-                 /* Now modify the instruction as appropriate.  */
                  bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1),
                             contents + roff - 3);
                  bfd_put_8 (output_bfd, 0xc7, contents + roff - 2);
@@ -2610,29 +2816,13 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                     It's originally:
                     call *(%rax)
                     Turn it into:
-                    nop; nop.  */
-
-                 unsigned int val, type;
-                 bfd_vma roff;
-
-                 /* First, make sure it's a call *(%rax).  */
-                 roff = rel->r_offset;
-                 BFD_ASSERT (roff + 2 <= input_section->size);
-                 type = bfd_get_8 (input_bfd, contents + roff);
-                 BFD_ASSERT (type == 0xff);
-                 val = bfd_get_8 (input_bfd, contents + roff + 1);
-                 BFD_ASSERT (val == 0x10);
-
-                 /* Now modify the instruction as appropriate.  Use
-                    xchg %ax,%ax instead of 2 nops.  */
+                    xchg %ax,%ax.  */
                  bfd_put_8 (output_bfd, 0x66, contents + roff);
                  bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
                  continue;
                }
-             else
+             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF)
                {
-                 unsigned int val, type, reg;
-
                  /* IE->LE transition:
                     Originally it can be one of:
                     movq foo@gottpoff(%rip), %reg
@@ -2641,25 +2831,23 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                     movq $foo, %reg
                     leaq foo(%reg), %reg
                     addq $foo, %reg.  */
-                 BFD_ASSERT (rel->r_offset >= 3);
-                 val = bfd_get_8 (input_bfd, contents + rel->r_offset - 3);
-                 BFD_ASSERT (val == 0x48 || val == 0x4c);
-                 type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
-                 BFD_ASSERT (type == 0x8b || type == 0x03);
-                 reg = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
-                 BFD_ASSERT ((reg & 0xc7) == 5);
+
+                 unsigned int val, type, reg;
+
+                 val = bfd_get_8 (input_bfd, contents + roff - 3);
+                 type = bfd_get_8 (input_bfd, contents + roff - 2);
+                 reg = bfd_get_8 (input_bfd, contents + roff - 1);
                  reg >>= 3;
-                 BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
                  if (type == 0x8b)
                    {
                      /* movq */
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x49,
-                                  contents + rel->r_offset - 3);
+                                  contents + roff - 3);
                      bfd_put_8 (output_bfd, 0xc7,
-                                contents + rel->r_offset - 2);
+                                contents + roff - 2);
                      bfd_put_8 (output_bfd, 0xc0 | reg,
-                                contents + rel->r_offset - 1);
+                                contents + roff - 1);
                    }
                  else if (reg == 4)
                    {
@@ -2667,27 +2855,29 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                         special  */
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x49,
-                                  contents + rel->r_offset - 3);
+                                  contents + roff - 3);
                      bfd_put_8 (output_bfd, 0x81,
-                                contents + rel->r_offset - 2);
+                                contents + roff - 2);
                      bfd_put_8 (output_bfd, 0xc0 | reg,
-                                contents + rel->r_offset - 1);
+                                contents + roff - 1);
                    }
                  else
                    {
                      /* addq -> leaq */
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x4d,
-                                  contents + rel->r_offset - 3);
+                                  contents + roff - 3);
                      bfd_put_8 (output_bfd, 0x8d,
-                                contents + rel->r_offset - 2);
+                                contents + roff - 2);
                      bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
-                                contents + rel->r_offset - 1);
+                                contents + roff - 1);
                    }
                  bfd_put_32 (output_bfd, tpoff (info, relocation),
-                             contents + rel->r_offset);
+                             contents + roff);
                  continue;
                }
+             else
+               BFD_ASSERT (FALSE);
            }
 
          if (htab->sgot == NULL)
@@ -2814,151 +3004,104 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  + htab->sgot->output_offset + off;
              unresolved_reloc = FALSE;
            }
-         else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
-           {
-             unsigned int i;
-             static unsigned char tlsgd[8]
-               = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 };
-
-             /* GD->IE transition.
-                .byte 0x66; leaq foo@tlsgd(%rip), %rdi
-                .word 0x6666; rex64; call __tls_get_addr@plt
-                Change it into:
-                movq %fs:0, %rax
-                addq foo@gottpoff(%rip), %rax */
-             BFD_ASSERT (rel->r_offset >= 4);
-             for (i = 0; i < 4; i++)
-               BFD_ASSERT (bfd_get_8 (input_bfd,
-                                      contents + rel->r_offset - 4 + i)
-                           == tlsgd[i]);
-             BFD_ASSERT (rel->r_offset + 12 <= input_section->size);
-             for (i = 0; i < 4; i++)
-               BFD_ASSERT (bfd_get_8 (input_bfd,
-                                      contents + rel->r_offset + 4 + i)
-                           == tlsgd[i+4]);
-             BFD_ASSERT (rel + 1 < relend);
-             BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
-             memcpy (contents + rel->r_offset - 4,
-                     "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
-                     16);
-
-             relocation = (htab->sgot->output_section->vma
-                           + htab->sgot->output_offset + off
-                           - rel->r_offset
-                           - input_section->output_section->vma
-                           - input_section->output_offset
-                           - 12);
-             bfd_put_32 (output_bfd, relocation,
-                         contents + rel->r_offset + 8);
-             /* Skip R_X86_64_PLT32.  */
-             rel++;
-             continue;
-           }
-         else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+         else
            {
-             /* GDesc -> IE transition.
-                It's originally something like:
-                leaq x@tlsdesc(%rip), %rax
-
-                Change it to:
-                movq x@gottpoff(%rip), %rax # before nop; nop
-
-                Registers other than %rax may be set up here.  */
-
-             unsigned int val, type, type2;
-             bfd_vma roff;
-
-             /* First, make sure it's a leaq adding rip to a 32-bit
-                offset into any register, although it's probably
-                almost always going to be rax.  */
-             roff = rel->r_offset;
-             BFD_ASSERT (roff >= 3);
-             type = bfd_get_8 (input_bfd, contents + roff - 3);
-             BFD_ASSERT ((type & 0xfb) == 0x48);
-             type2 = bfd_get_8 (input_bfd, contents + roff - 2);
-             BFD_ASSERT (type2 == 0x8d);
-             val = bfd_get_8 (input_bfd, contents + roff - 1);
-             BFD_ASSERT ((val & 0xc7) == 0x05);
-             BFD_ASSERT (roff + 4 <= input_section->size);
-
-             /* Now modify the instruction as appropriate.  */
-             /* To turn a leaq into a movq in the form we use it, it
-                suffices to change the second byte from 0x8d to
-                0x8b.  */
-             bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
+             bfd_vma roff = rel->r_offset;
 
-             bfd_put_32 (output_bfd,
-                         htab->sgot->output_section->vma
-                         + htab->sgot->output_offset + off
-                         - rel->r_offset
-                         - input_section->output_section->vma
-                         - input_section->output_offset
-                         - 4,
-                         contents + roff);
-             continue;
-           }
-         else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
-           {
-             /* GDesc -> IE transition.
-                It's originally:
-                call *(%rax)
+             if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
+               {
+                 /* GD->IE transition.
+                    .byte 0x66; leaq foo@tlsgd(%rip), %rdi
+                    .word 0x6666; rex64; call __tls_get_addr@plt
+                    Change it into:
+                    movq %fs:0, %rax
+                    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);
 
-                Change it to:
-                nop; nop.  */
+                 relocation = (htab->sgot->output_section->vma
+                               + htab->sgot->output_offset + off
+                               - roff
+                               - input_section->output_section->vma
+                               - input_section->output_offset
+                               - 12);
+                 bfd_put_32 (output_bfd, relocation,
+                             contents + roff + 8);
+                 /* Skip R_X86_64_PLT32.  */
+                 rel++;
+                 continue;
+               }
+             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+               {
+                 /* GDesc -> IE transition.
+                    It's originally something like:
+                    leaq x@tlsdesc(%rip), %rax
 
-             unsigned int val, type;
-             bfd_vma roff;
+                    Change it to:
+                    movq x@gottpoff(%rip), %rax # before xchg %ax,%ax
+                  */
 
-             /* First, make sure it's a call *(%eax).  */
-             roff = rel->r_offset;
-             BFD_ASSERT (roff + 2 <= input_section->size);
-             type = bfd_get_8 (input_bfd, contents + roff);
-             BFD_ASSERT (type == 0xff);
-             val = bfd_get_8 (input_bfd, contents + roff + 1);
-             BFD_ASSERT (val == 0x10);
+                 unsigned int val, type, type2;
 
-             /* Now modify the instruction as appropriate.  Use
-                xchg %ax,%ax instead of 2 nops.  */
-             bfd_put_8 (output_bfd, 0x66, contents + roff);
-             bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+                 type = bfd_get_8 (input_bfd, contents + roff - 3);
+                 type2 = bfd_get_8 (input_bfd, contents + roff - 2);
+                 val = bfd_get_8 (input_bfd, contents + roff - 1);
 
-             continue;
+                 /* Now modify the instruction as appropriate. To
+                    turn a leaq into a movq in the form we use it, it
+                    suffices to change the second byte from 0x8d to
+                    0x8b.  */
+                 bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
+
+                 bfd_put_32 (output_bfd,
+                             htab->sgot->output_section->vma
+                             + htab->sgot->output_offset + off
+                             - rel->r_offset
+                             - input_section->output_section->vma
+                             - input_section->output_offset
+                             - 4,
+                             contents + roff);
+                 continue;
+               }
+             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
+               {
+                 /* GDesc -> IE transition.
+                    It's originally:
+                    call *(%rax)
+
+                    Change it to:
+                    xchg %ax,%ax.  */
+
+                 unsigned int val, type;
+
+                 type = bfd_get_8 (input_bfd, contents + roff);
+                 val = bfd_get_8 (input_bfd, contents + roff + 1);
+                 bfd_put_8 (output_bfd, 0x66, contents + roff);
+                 bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+                 continue;
+               }
+             else
+               BFD_ASSERT (FALSE);
            }
-         else
-           BFD_ASSERT (FALSE);
          break;
 
        case R_X86_64_TLSLD:
-         if (! info->shared)
-           {
-             unsigned long tls_r_symndx;
-             struct elf_link_hash_entry *tls_h;
+         if (! elf64_x86_64_tls_transition (info, input_bfd,
+                                            input_section, contents,
+                                            symtab_hdr, sym_hashes,
+                                            &r_type, GOT_UNKNOWN,
+                                            rel, relend, h))
+           return FALSE;
 
+         if (r_type != R_X86_64_TLSLD)
+           {
              /* LD->LE transition:
-                Ensure it is:
                 leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
                 We change it into:
                 .word 0x6666; .byte 0x66; movl %fs:0, %rax.  */
-             BFD_ASSERT (rel->r_offset >= 3);
-             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 3)
-                         == 0x48);
-             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2)
-                         == 0x8d);
-             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 1)
-                         == 0x3d);
-             BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
-             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
-                         == 0xe8);
-             BFD_ASSERT (rel + 1 < relend);
-             tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
-             BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
-             tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
-             BFD_ASSERT (tls_h != NULL
-                         && tls_h->root.root.string != NULL
-                         && strcmp (tls_h->root.root.string,
-                                    "__tls_get_addr") == 0);
-             BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
-                         || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+
+             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);
              /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
index 59223f0..ad42541 100644 (file)
@@ -1,3 +1,13 @@
+2007-08-23  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * ld-i386/tlsbinpic.s: Add a new GD -> IE test.
+
+       * ld-i386/tlsgd1.s: Add a new GD -> LE test.
+
+       * ld-i386/tlsbin.dd: Updated.
+       * ld-i386/tlsbin.rd: Likewise.
+       * ld-i386/tlsgd1.dd: Likewise.
+
 2007-08-17  Jakub Jelinek  <jakub@redhat.com>
 
        * ld-sparc/tlssunnopic32.dd: Fix up #target.
index 0e3ef4d..e399f86 100644 (file)
@@ -222,235 +222,243 @@ Disassembly of section .text:
  8049170:      90[     ]+nop *
  8049171:      90[     ]+nop *
  8049172:      90[     ]+nop *
- 8049173:      8b 5d fc[       ]+mov    -0x4\(%ebp\),%ebx
- 8049176:      c9[     ]+leave *
- 8049177:      c3[     ]+ret *
+#  GD -> IE because variable is not defined in executable
+ 8049173:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 8049179:      2b 83 f8 ff ff ff[      ]+sub    -0x8\(%ebx\),%eax
+#                              ->R_386_TLS_TPOFF32     sG1
+ 804917f:      90[     ]+nop *
+ 8049180:      90[     ]+nop *
+ 8049181:      90[     ]+nop *
+ 8049182:      90[     ]+nop *
+ 8049183:      8b 5d fc[       ]+mov    -0x4\(%ebp\),%ebx
+ 8049186:      c9[     ]+leave *
+ 8049187:      c3[     ]+ret *
 
-0+8049178 <_start>:
- 8049178:      55[     ]+push   %ebp
- 8049179:      89 e5[  ]+mov    %esp,%ebp
- 804917b:      e8 00 00 00 00[         ]+call   8049180 <_start\+0x8>
- 8049180:      59[     ]+pop    %ecx
- 8049181:      81 c1 a4 0f 00 00[      ]+add    \$0xfa4,%ecx
- 8049187:      90[     ]+nop *
- 8049188:      90[     ]+nop *
- 8049189:      90[     ]+nop *
- 804918a:      90[     ]+nop *
+0+8049188 <_start>:
+ 8049188:      55[     ]+push   %ebp
+ 8049189:      89 e5[  ]+mov    %esp,%ebp
+ 804918b:      e8 00 00 00 00[         ]+call   8049190 <_start\+0x8>
+ 8049190:      59[     ]+pop    %ecx
+ 8049191:      81 c1 94 0f 00 00[      ]+add    \$0xf94,%ecx
+ 8049197:      90[     ]+nop *
+ 8049198:      90[     ]+nop *
+ 8049199:      90[     ]+nop *
+ 804919a:      90[     ]+nop *
 #  @gottpoff IE against global var
- 804918b:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
- 8049192:      90[     ]+nop *
- 8049193:      90[     ]+nop *
- 8049194:      2b 91 f4 ff ff ff[      ]+sub    -0xc\(%ecx\),%edx
+ 804919b:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 80491a2:      90[     ]+nop *
+ 80491a3:      90[     ]+nop *
+ 80491a4:      2b 91 f4 ff ff ff[      ]+sub    -0xc\(%ecx\),%edx
 #                              ->R_386_TLS_TPOFF32     sG6
- 804919a:      90[     ]+nop *
- 804919b:      90[     ]+nop *
- 804919c:      90[     ]+nop *
- 804919d:      90[     ]+nop *
-#  @indntpoff IE against global var
- 804919e:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
- 80491a4:      90[     ]+nop *
- 80491a5:      90[     ]+nop *
- 80491a6:      03 05 08 a1 04 08[      ]+add    0x804a108,%eax
-#                              ->R_386_TLS_TPOFF       sG7
+ 80491aa:      90[     ]+nop *
+ 80491ab:      90[     ]+nop *
  80491ac:      90[     ]+nop *
  80491ad:      90[     ]+nop *
- 80491ae:      90[     ]+nop *
- 80491af:      90[     ]+nop *
-#  @indntpoff direct %gs access IE against global var
- 80491b0:      8b 15 20 a1 04 08[      ]+mov    0x804a120,%edx
-#                              ->R_386_TLS_TPOFF       sG8
- 80491b6:      90[     ]+nop *
- 80491b7:      90[     ]+nop *
- 80491b8:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
- 80491bb:      90[     ]+nop *
+#  @indntpoff IE against global var
+ 80491ae:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 80491b4:      90[     ]+nop *
+ 80491b5:      90[     ]+nop *
+ 80491b6:      03 05 08 a1 04 08[      ]+add    0x804a108,%eax
+#                              ->R_386_TLS_TPOFF       sG7
  80491bc:      90[     ]+nop *
  80491bd:      90[     ]+nop *
  80491be:      90[     ]+nop *
-#  @gottpoff IE -> LE against global var defined in exec
- 80491bf:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 80491bf:      90[     ]+nop *
+#  @indntpoff direct %gs access IE against global var
+ 80491c0:      8b 15 20 a1 04 08[      ]+mov    0x804a120,%edx
+#                              ->R_386_TLS_TPOFF       sG8
  80491c6:      90[     ]+nop *
  80491c7:      90[     ]+nop *
- 80491c8:      81 ea 8c 0f 00 00[      ]+sub    \$0xf8c,%edx
-#                                                      bg6
+ 80491c8:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
+ 80491cb:      90[     ]+nop *
+ 80491cc:      90[     ]+nop *
+ 80491cd:      90[     ]+nop *
  80491ce:      90[     ]+nop *
- 80491cf:      90[     ]+nop *
- 80491d0:      90[     ]+nop *
- 80491d1:      90[     ]+nop *
-#  @indntpoff IE -> LE against global var defined in exec
- 80491d2:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
- 80491d8:      90[     ]+nop *
- 80491d9:      90[     ]+nop *
- 80491da:      81 c0 78 f0 ff ff[      ]+add    \$0xfffff078,%eax
-#                                                      bg7
+#  @gottpoff IE -> LE against global var defined in exec
+ 80491cf:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 80491d6:      90[     ]+nop *
+ 80491d7:      90[     ]+nop *
+ 80491d8:      81 ea 8c 0f 00 00[      ]+sub    \$0xf8c,%edx
+#                                                      bg6
+ 80491de:      90[     ]+nop *
+ 80491df:      90[     ]+nop *
  80491e0:      90[     ]+nop *
  80491e1:      90[     ]+nop *
- 80491e2:      90[     ]+nop *
- 80491e3:      90[     ]+nop *
-#  @indntpoff direct %gs access IE -> LE against global var defined
-#  in exec
- 80491e4:      c7 c2 7c f0 ff ff[      ]+mov    \$0xfffff07c,%edx
-#                                                      bg8
- 80491ea:      90[     ]+nop *
- 80491eb:      90[     ]+nop *
- 80491ec:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
- 80491ef:      90[     ]+nop *
+#  @indntpoff IE -> LE against global var defined in exec
+ 80491e2:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 80491e8:      90[     ]+nop *
+ 80491e9:      90[     ]+nop *
+ 80491ea:      81 c0 78 f0 ff ff[      ]+add    \$0xfffff078,%eax
+#                                                      bg7
  80491f0:      90[     ]+nop *
  80491f1:      90[     ]+nop *
  80491f2:      90[     ]+nop *
-#  @gottpoff IE -> LE against local var
- 80491f3:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 80491f3:      90[     ]+nop *
+#  @indntpoff direct %gs access IE -> LE against global var defined
+#  in exec
+ 80491f4:      c7 c2 7c f0 ff ff[      ]+mov    \$0xfffff07c,%edx
+#                                                      bg8
  80491fa:      90[     ]+nop *
  80491fb:      90[     ]+nop *
- 80491fc:      81 ea 6c 0f 00 00[      ]+sub    \$0xf6c,%edx
-#                                                      bl6
+ 80491fc:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
+ 80491ff:      90[     ]+nop *
+ 8049200:      90[     ]+nop *
+ 8049201:      90[     ]+nop *
  8049202:      90[     ]+nop *
- 8049203:      90[     ]+nop *
- 8049204:      90[     ]+nop *
- 8049205:      90[     ]+nop *
-#  @indntpoff IE -> LE against local var
- 8049206:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
- 804920c:      90[     ]+nop *
- 804920d:      90[     ]+nop *
- 804920e:      81 c0 98 f0 ff ff[      ]+add    \$0xfffff098,%eax
-#                                                      bl7
+#  @gottpoff IE -> LE against local var
+ 8049203:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 804920a:      90[     ]+nop *
+ 804920b:      90[     ]+nop *
+ 804920c:      81 ea 6c 0f 00 00[      ]+sub    \$0xf6c,%edx
+#                                                      bl6
+ 8049212:      90[     ]+nop *
+ 8049213:      90[     ]+nop *
  8049214:      90[     ]+nop *
  8049215:      90[     ]+nop *
- 8049216:      90[     ]+nop *
- 8049217:      90[     ]+nop *
-#  @indntpoff direct %gs access IE -> LE against local var
- 8049218:      c7 c2 9c f0 ff ff[      ]+mov    \$0xfffff09c,%edx
-#                                                      bl8
- 804921e:      90[     ]+nop *
- 804921f:      90[     ]+nop *
- 8049220:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
- 8049223:      90[     ]+nop *
+#  @indntpoff IE -> LE against local var
+ 8049216:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 804921c:      90[     ]+nop *
+ 804921d:      90[     ]+nop *
+ 804921e:      81 c0 98 f0 ff ff[      ]+add    \$0xfffff098,%eax
+#                                                      bl7
  8049224:      90[     ]+nop *
  8049225:      90[     ]+nop *
  8049226:      90[     ]+nop *
-#  @gottpoff IE -> LE against hidden but not local var
- 8049227:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 8049227:      90[     ]+nop *
+#  @indntpoff direct %gs access IE -> LE against local var
+ 8049228:      c7 c2 9c f0 ff ff[      ]+mov    \$0xfffff09c,%edx
+#                                                      bl8
  804922e:      90[     ]+nop *
  804922f:      90[     ]+nop *
- 8049230:      81 ea ac 0f 00 00[      ]+sub    \$0xfac,%edx
-#                                                      sh6
+ 8049230:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
+ 8049233:      90[     ]+nop *
+ 8049234:      90[     ]+nop *
+ 8049235:      90[     ]+nop *
  8049236:      90[     ]+nop *
- 8049237:      90[     ]+nop *
- 8049238:      90[     ]+nop *
- 8049239:      90[     ]+nop *
-#  @indntpoff IE -> LE against hidden but not local var
- 804923a:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
- 8049240:      90[     ]+nop *
- 8049241:      90[     ]+nop *
- 8049242:      81 c0 58 f0 ff ff[      ]+add    \$0xfffff058,%eax
-#                                                      sh7
+#  @gottpoff IE -> LE against hidden but not local var
+ 8049237:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 804923e:      90[     ]+nop *
+ 804923f:      90[     ]+nop *
+ 8049240:      81 ea ac 0f 00 00[      ]+sub    \$0xfac,%edx
+#                                                      sh6
+ 8049246:      90[     ]+nop *
+ 8049247:      90[     ]+nop *
  8049248:      90[     ]+nop *
  8049249:      90[     ]+nop *
- 804924a:      90[     ]+nop *
- 804924b:      90[     ]+nop *
-#  @indntpoff direct %gs access IE -> LE against hidden but not
-#  local var
- 804924c:      c7 c2 5c f0 ff ff[      ]+mov    \$0xfffff05c,%edx
-#                                                      sh8
- 8049252:      90[     ]+nop *
- 8049253:      90[     ]+nop *
- 8049254:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
- 8049257:      90[     ]+nop *
+#  @indntpoff IE -> LE against hidden but not local var
+ 804924a:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 8049250:      90[     ]+nop *
+ 8049251:      90[     ]+nop *
+ 8049252:      81 c0 58 f0 ff ff[      ]+add    \$0xfffff058,%eax
+#                                                      sh7
  8049258:      90[     ]+nop *
  8049259:      90[     ]+nop *
  804925a:      90[     ]+nop *
-#  LE @tpoff, global var defined in exec
- 804925b:      ba 00 10 00 00[         ]+mov    \$0x1000,%edx
-#                                                      sg1
- 8049260:      90[     ]+nop *
- 8049261:      90[     ]+nop *
- 8049262:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 804925b:      90[     ]+nop *
+#  @indntpoff direct %gs access IE -> LE against hidden but not
+#  local var
+ 804925c:      c7 c2 5c f0 ff ff[      ]+mov    \$0xfffff05c,%edx
+#                                                      sh8
+ 8049262:      90[     ]+nop *
+ 8049263:      90[     ]+nop *
+ 8049264:      65 8b 02[       ]+mov    %gs:\(%edx\),%eax
+ 8049267:      90[     ]+nop *
  8049268:      90[     ]+nop *
  8049269:      90[     ]+nop *
- 804926a:      29 d0[  ]+sub    %edx,%eax
- 804926c:      90[     ]+nop *
- 804926d:      90[     ]+nop *
- 804926e:      90[     ]+nop *
- 804926f:      90[     ]+nop *
-#  LE @tpoff, local var
- 8049270:      b8 7f 0f 00 00[         ]+mov    \$0xf7f,%eax
-#                                                      bl1+1
- 8049275:      90[     ]+nop *
- 8049276:      90[     ]+nop *
- 8049277:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 804926a:      90[     ]+nop *
+#  LE @tpoff, global var defined in exec
+ 804926b:      ba 00 10 00 00[         ]+mov    \$0x1000,%edx
+#                                                      sg1
+ 8049270:      90[     ]+nop *
+ 8049271:      90[     ]+nop *
+ 8049272:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 8049278:      90[     ]+nop *
+ 8049279:      90[     ]+nop *
+ 804927a:      29 d0[  ]+sub    %edx,%eax
+ 804927c:      90[     ]+nop *
+ 804927d:      90[     ]+nop *
  804927e:      90[     ]+nop *
  804927f:      90[     ]+nop *
- 8049280:      29 c2[  ]+sub    %eax,%edx
- 8049282:      90[     ]+nop *
- 8049283:      90[     ]+nop *
- 8049284:      90[     ]+nop *
+#  LE @tpoff, local var
+ 8049280:      b8 7f 0f 00 00[         ]+mov    \$0xf7f,%eax
+#                                                      bl1+1
  8049285:      90[     ]+nop *
-#  LE @tpoff, hidden var defined in exec
- 8049286:      b8 bd 0f 00 00[         ]+mov    \$0xfbd,%eax
-#                                                      sh1+3
- 804928b:      90[     ]+nop *
- 804928c:      90[     ]+nop *
- 804928d:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 8049286:      90[     ]+nop *
+ 8049287:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 804928e:      90[     ]+nop *
+ 804928f:      90[     ]+nop *
+ 8049290:      29 c2[  ]+sub    %eax,%edx
+ 8049292:      90[     ]+nop *
+ 8049293:      90[     ]+nop *
  8049294:      90[     ]+nop *
  8049295:      90[     ]+nop *
- 8049296:      29 c2[  ]+sub    %eax,%edx
- 8049298:      90[     ]+nop *
- 8049299:      90[     ]+nop *
- 804929a:      90[     ]+nop *
+#  LE @tpoff, hidden var defined in exec
+ 8049296:      b8 bd 0f 00 00[         ]+mov    \$0xfbd,%eax
+#                                                      sh1+3
  804929b:      90[     ]+nop *
-#  LE @ntpoff, global var defined in exec
- 804929c:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
- 80492a2:      90[     ]+nop *
- 80492a3:      90[     ]+nop *
- 80492a4:      8d 90 04 f0 ff ff[      ]+lea    -0xffc\(%eax\),%edx
-#                                                      sg2
+ 804929c:      90[     ]+nop *
+ 804929d:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 80492a4:      90[     ]+nop *
+ 80492a5:      90[     ]+nop *
+ 80492a6:      29 c2[  ]+sub    %eax,%edx
+ 80492a8:      90[     ]+nop *
+ 80492a9:      90[     ]+nop *
  80492aa:      90[     ]+nop *
  80492ab:      90[     ]+nop *
- 80492ac:      90[     ]+nop *
- 80492ad:      90[     ]+nop *
-#  LE @ntpoff, local var, non-canonical sequence
- 80492ae:      b8 86 f0 ff ff[         ]+mov    \$0xfffff086,%eax
-#                                                      bl2+2
+#  LE @ntpoff, global var defined in exec
+ 80492ac:      65 a1 00 00 00 00[      ]+mov    %gs:0x0,%eax
+ 80492b2:      90[     ]+nop *
  80492b3:      90[     ]+nop *
- 80492b4:      90[     ]+nop *
- 80492b5:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 80492b4:      8d 90 04 f0 ff ff[      ]+lea    -0xffc\(%eax\),%edx
+#                                                      sg2
+ 80492ba:      90[     ]+nop *
+ 80492bb:      90[     ]+nop *
  80492bc:      90[     ]+nop *
  80492bd:      90[     ]+nop *
- 80492be:      01 c2[  ]+add    %eax,%edx
- 80492c0:      90[     ]+nop *
- 80492c1:      90[     ]+nop *
- 80492c2:      90[     ]+nop *
+#  LE @ntpoff, local var, non-canonical sequence
+ 80492be:      b8 86 f0 ff ff[         ]+mov    \$0xfffff086,%eax
+#                                                      bl2+2
  80492c3:      90[     ]+nop *
-#  LE @ntpoff, hidden var defined in exec, non-canonical sequence
- 80492c4:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
- 80492cb:      90[     ]+nop *
+ 80492c4:      90[     ]+nop *
+ 80492c5:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
  80492cc:      90[     ]+nop *
- 80492cd:      81 c2 45 f0 ff ff[      ]+add    \$0xfffff045,%edx
-#                                                      sh2+1
+ 80492cd:      90[     ]+nop *
+ 80492ce:      01 c2[  ]+add    %eax,%edx
+ 80492d0:      90[     ]+nop *
+ 80492d1:      90[     ]+nop *
+ 80492d2:      90[     ]+nop *
  80492d3:      90[     ]+nop *
- 80492d4:      90[     ]+nop *
- 80492d5:      90[     ]+nop *
- 80492d6:      90[     ]+nop *
+#  LE @ntpoff, hidden var defined in exec, non-canonical sequence
+ 80492d4:      65 8b 15 00 00 00 00[   ]+mov    %gs:0x0,%edx
+ 80492db:      90[     ]+nop *
+ 80492dc:      90[     ]+nop *
+ 80492dd:      81 c2 45 f0 ff ff[      ]+add    \$0xfffff045,%edx
+#                                                      sh2+1
+ 80492e3:      90[     ]+nop *
+ 80492e4:      90[     ]+nop *
+ 80492e5:      90[     ]+nop *
+ 80492e6:      90[     ]+nop *
 #  LE @ntpoff, global var defined in exec
- 80492d7:      65 a1 08 f0 ff ff[      ]+mov    %gs:0xfffff008,%eax
+ 80492e7:      65 a1 08 f0 ff ff[      ]+mov    %gs:0xfffff008,%eax
 #                                                      sg3
- 80492dd:      90[     ]+nop *
- 80492de:      90[     ]+nop *
- 80492df:      90[     ]+nop *
- 80492e0:      90[     ]+nop *
+ 80492ed:      90[     ]+nop *
+ 80492ee:      90[     ]+nop *
+ 80492ef:      90[     ]+nop *
+ 80492f0:      90[     ]+nop *
 #  LE @ntpoff, local var
- 80492e1:      65 8b 15 8b f0 ff ff[   ]+mov    %gs:0xfffff08b,%edx
+ 80492f1:      65 8b 15 8b f0 ff ff[   ]+mov    %gs:0xfffff08b,%edx
 #                                                      bl3+3
- 80492e8:      90[     ]+nop *
- 80492e9:      90[     ]+nop *
- 80492ea:      90[     ]+nop *
- 80492eb:      90[     ]+nop *
+ 80492f8:      90[     ]+nop *
+ 80492f9:      90[     ]+nop *
+ 80492fa:      90[     ]+nop *
+ 80492fb:      90[     ]+nop *
 #  LE @ntpoff, hidden var defined in exec
- 80492ec:      65 8b 15 49 f0 ff ff[   ]+mov    %gs:0xfffff049,%edx
+ 80492fc:      65 8b 15 49 f0 ff ff[   ]+mov    %gs:0xfffff049,%edx
 #                                                      sh3+1
- 80492f3:      90[     ]+nop *
- 80492f4:      90[     ]+nop *
- 80492f5:      90[     ]+nop *
- 80492f6:      90[     ]+nop *
- 80492f7:      8b 5d fc[       ]+mov    -0x4\(%ebp\),%ebx
- 80492fa:      c9[     ]+leave *
- 80492fb:      c3[     ]+ret *
+ 8049303:      90[     ]+nop *
+ 8049304:      90[     ]+nop *
+ 8049305:      90[     ]+nop *
+ 8049306:      90[     ]+nop *
+ 8049307:      8b 5d fc[       ]+mov    -0x4\(%ebp\),%ebx
+ 804930a:      c9[     ]+leave *
+ 804930b:      c3[     ]+ret *
index 54abd8b..10934cb 100644 (file)
@@ -32,7 +32,7 @@ Key to Flags:
 .*
 
 Elf file type is EXEC \(Executable file\)
-Entry point 0x8049178
+Entry point 0x8049188
 There are 6 program headers, starting at offset [0-9]+
 
 Program Headers:
@@ -137,7 +137,7 @@ Symbol table '.symtab' contains 70 entries:
  +[0-9]+: 00000058 +0 TLS +GLOBAL HIDDEN +9 sh7
  +[0-9]+: 0000005c +0 TLS +GLOBAL HIDDEN +9 sh8
  +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +9 sg1
- +[0-9]+: 0+8049178 +0 FUNC +GLOBAL DEFAULT +8 _start
+ +[0-9]+: 0+8049188 +0 FUNC +GLOBAL DEFAULT +8 _start
  +[0-9]+: 0000004c +0 TLS +GLOBAL HIDDEN +9 sh4
  +[0-9]+: 00000078 +0 TLS +GLOBAL DEFAULT +10 bg7
  +[0-9]+: 00000050 +0 TLS +GLOBAL HIDDEN +9 sh5
index 844f952..9c8a006 100644 (file)
@@ -162,6 +162,11 @@ fn2:
        movl    %gs:(%edx), %edx
        nop;nop;nop;nop
 
+       /* GD -> IE because variable is not defined in executable */
+       leal    sG1@tlsgd(%ebx), %eax
+       call    ___tls_get_addr@plt
+       nop;nop;nop;nop;nop
+
        movl    -4(%ebp), %ebx
        leave
        ret
index 54d7416..9a33132 100644 (file)
@@ -11,4 +11,6 @@ Disassembly of section .text:
 [a-f0-9]+ <_start>:
 [      ]*[a-f0-9]+:    65 a1 00 00 00 00       mov    %gs:0x0,%eax
 [      ]*[a-f0-9]+:    81 e8 04 00 00 00       sub    \$0x4,%eax
+[      ]*[a-f0-9]+:    65 a1 00 00 00 00       mov    %gs:0x0,%eax
+[      ]*[a-f0-9]+:    81 e8 04 00 00 00       sub    \$0x4,%eax
 #pass
index 2b3ed0e..552ca09 100644 (file)
@@ -3,6 +3,9 @@
 _start:
        leal    foo@TLSGD(,%ebx,1), %eax
        call    ___tls_get_addr
+       leal    foo@TLSGD(%ebx), %eax
+       call    ___tls_get_addr
+       nop
        .globl foo
        .section        .tdata,"awT",@progbits
        .align 4