From Craig Silverstein: better organization for TLS code.
authorIan Lance Taylor <iant@google.com>
Mon, 29 Oct 2007 20:09:35 +0000 (20:09 +0000)
committerIan Lance Taylor <iant@google.com>
Mon, 29 Oct 2007 20:09:35 +0000 (20:09 +0000)
gold/i386.cc
gold/x86_64.cc

index e36b22cdaf074fb4ae91990407ffec1e5020f304..cfa10ad2fb1bbcf67c897ec207bd067d4a69f44d 100644 (file)
@@ -162,27 +162,27 @@ class Target_i386 : public Sized_target<32, false>
                 const Symbol_value<32>*,
                 unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
 
-    // Do a TLS Initial-Exec to Local-Exec transition.
-    static inline void
-    tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum,
+    // Do a TLS General-Dynamic to Local-Exec transition.
+    inline void
+    tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum,
                 Output_segment* tls_segment,
                 const elfcpp::Rel<32, false>&, unsigned int r_type,
                 elfcpp::Elf_types<32>::Elf_Addr value,
                 unsigned char* view,
                 off_t view_size);
 
-    // Do a TLS General-Dynamic to Local-Exec transition.
+    // Do a TLS Local-Dynamic to Local-Exec transition.
     inline void
-    tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum,
+    tls_ld_to_le(const Relocate_info<32, false>*, size_t relnum,
                 Output_segment* tls_segment,
                 const elfcpp::Rel<32, false>&, unsigned int r_type,
                 elfcpp::Elf_types<32>::Elf_Addr value,
                 unsigned char* view,
                 off_t view_size);
 
-    // Do a TLS Local-Dynamic to Local-Exec transition.
-    inline void
-    tls_ld_to_le(const Relocate_info<32, false>*, size_t relnum,
+    // Do a TLS Initial-Exec to Local-Exec transition.
+    static inline void
+    tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum,
                 Output_segment* tls_segment,
                 const elfcpp::Rel<32, false>&, unsigned int r_type,
                 elfcpp::Elf_types<32>::Elf_Addr value,
@@ -814,57 +814,57 @@ Target_i386::Scan::local(const General_options&,
 
       // These are initial TLS relocs, which are expected when
       // linking.
-    case elfcpp::R_386_TLS_IE:
-    case elfcpp::R_386_TLS_GOTIE:
-    case elfcpp::R_386_TLS_LE:
-    case elfcpp::R_386_TLS_GD:
-    case elfcpp::R_386_TLS_LDM:
-    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_GD:            // Global-dynamic
+    case elfcpp::R_386_TLS_GOTDESC:       // Global-dynamic (from ~oliva url)
+    case elfcpp::R_386_TLS_DESC_CALL:
+    case elfcpp::R_386_TLS_LDM:           // Local-dynamic
+    case elfcpp::R_386_TLS_LDO_32:        // Alternate local-dynamic
+    case elfcpp::R_386_TLS_IE:            // Initial-exec
     case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:            // Local-exec
     case elfcpp::R_386_TLS_LE_32:
-    case elfcpp::R_386_TLS_GOTDESC:
-    case elfcpp::R_386_TLS_DESC_CALL:
       {
        bool output_is_shared = parameters->output_is_shared();
        const tls::Tls_optimization optimized_type
             = Target_i386::optimize_tls_reloc(!output_is_shared, r_type);
        switch (r_type)
          {
-         case elfcpp::R_386_TLS_LE:
-         case elfcpp::R_386_TLS_LE_32:
-           // FIXME: If generating a shared object, we need to copy
-           // this relocation into the object.
-           gold_assert(!output_is_shared);
-           break;
-
-         case elfcpp::R_386_TLS_IE:
-         case elfcpp::R_386_TLS_IE_32:
-         case elfcpp::R_386_TLS_GOTIE:
-           // FIXME: If not relaxing to LE, we need to generate a
-           // TPOFF or TPOFF32 reloc.
+         case elfcpp::R_386_TLS_GD:          // Global-dynamic
+         case elfcpp::R_386_TLS_GOTDESC:     // Global-dynamic (from ~oliva)
+         case elfcpp::R_386_TLS_DESC_CALL:
+           // FIXME: If not relaxing to LE, we need to generate
+           // DTPMOD32 and DTPOFF32 relocs.
            if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
            break;
 
-         case elfcpp::R_386_TLS_LDM:
+         case elfcpp::R_386_TLS_LDM:         // Local-dynamic
            // FIXME: If not relaxing to LE, we need to generate a
            // DTPMOD32 reloc.
            if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
            break;
 
-         case elfcpp::R_386_TLS_LDO_32:
+         case elfcpp::R_386_TLS_LDO_32:      // Alternate local-dynamic
            break;
 
-         case elfcpp::R_386_TLS_GD:
-         case elfcpp::R_386_TLS_GOTDESC:
-         case elfcpp::R_386_TLS_DESC_CALL:
-           // FIXME: If not relaxing to LE, we need to generate
-           // DTPMOD32 and DTPOFF32 relocs.
+         case elfcpp::R_386_TLS_IE:          // Initial-exec
+         case elfcpp::R_386_TLS_IE_32:
+         case elfcpp::R_386_TLS_GOTIE:
+           // FIXME: If not relaxing to LE, we need to generate a
+           // TPOFF or TPOFF32 reloc.
            if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
            break;
 
+         case elfcpp::R_386_TLS_LE:          // Local-exec
+         case elfcpp::R_386_TLS_LE_32:
+           // FIXME: If generating a shared object, we need to copy
+           // this relocation into the object.
+           gold_assert(!output_is_shared);
+           break;
+
          default:
            gold_unreachable();
          }
@@ -1018,57 +1018,57 @@ Target_i386::Scan::global(const General_options& options,
 
       // These are initial tls relocs, which are expected when
       // linking.
-    case elfcpp::R_386_TLS_IE:
-    case elfcpp::R_386_TLS_GOTIE:
-    case elfcpp::R_386_TLS_LE:
-    case elfcpp::R_386_TLS_GD:
-    case elfcpp::R_386_TLS_LDM:
-    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_GD:            // Global-dynamic
+    case elfcpp::R_386_TLS_GOTDESC:       // Global-dynamic (from ~oliva url)
+    case elfcpp::R_386_TLS_DESC_CALL:
+    case elfcpp::R_386_TLS_LDM:           // Local-dynamic
+    case elfcpp::R_386_TLS_LDO_32:        // Alternate local-dynamic
+    case elfcpp::R_386_TLS_IE:            // Initial-exec
     case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:            // Local-exec
     case elfcpp::R_386_TLS_LE_32:
-    case elfcpp::R_386_TLS_GOTDESC:
-    case elfcpp::R_386_TLS_DESC_CALL:
       {
        const bool is_final = gsym->final_value_is_known();
        const tls::Tls_optimization optimized_type
             = Target_i386::optimize_tls_reloc(is_final, r_type);
        switch (r_type)
          {
-         case elfcpp::R_386_TLS_LE:
-         case elfcpp::R_386_TLS_LE_32:
-           // FIXME: If generating a shared object, we need to copy
-           // this relocation into the object.
-           gold_assert(!parameters->output_is_shared());
-           break;
-
-         case elfcpp::R_386_TLS_IE:
-         case elfcpp::R_386_TLS_IE_32:
-         case elfcpp::R_386_TLS_GOTIE:
-           // FIXME: If not relaxing to LE, we need to generate a
-           // TPOFF or TPOFF32 reloc.
+         case elfcpp::R_386_TLS_GD:          // Global-dynamic
+         case elfcpp::R_386_TLS_GOTDESC:     // Global-dynamic (~oliva url)
+         case elfcpp::R_386_TLS_DESC_CALL:
+           // FIXME: If not relaxing to LE, we need to generate
+           // DTPMOD32 and DTPOFF32 relocs.
            if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
            break;
 
-         case elfcpp::R_386_TLS_LDM:
+         case elfcpp::R_386_TLS_LDM:         // Local-dynamic
            // FIXME: If not relaxing to LE, we need to generate a
            // DTPMOD32 reloc.
            if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
            break;
 
-         case elfcpp::R_386_TLS_LDO_32:
+         case elfcpp::R_386_TLS_LDO_32:      // Alternate local-dynamic
            break;
 
-         case elfcpp::R_386_TLS_GD:
-         case elfcpp::R_386_TLS_GOTDESC:
-         case elfcpp::R_386_TLS_DESC_CALL:
-           // FIXME: If not relaxing to LE, we need to generate
-           // DTPMOD32 and DTPOFF32 relocs.
+         case elfcpp::R_386_TLS_IE:          // Initial-exec
+         case elfcpp::R_386_TLS_IE_32:
+         case elfcpp::R_386_TLS_GOTIE:
+           // FIXME: If not relaxing to LE, we need to generate a
+           // TPOFF or TPOFF32 reloc.
            if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
            break;
 
+         case elfcpp::R_386_TLS_LE:          // Local-exec
+         case elfcpp::R_386_TLS_LE_32:
+           // FIXME: If generating a shared object, we need to copy
+           // this relocation into the object.
+           gold_assert(!parameters->output_is_shared());
+           break;
+
          default:
            gold_unreachable();
          }
@@ -1322,16 +1322,16 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
 
       // These are initial tls relocs, which are expected when
       // linking.
-    case elfcpp::R_386_TLS_IE:
-    case elfcpp::R_386_TLS_GOTIE:
-    case elfcpp::R_386_TLS_LE:
-    case elfcpp::R_386_TLS_GD:
-    case elfcpp::R_386_TLS_LDM:
-    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_GD:             // Global-dynamic
+    case elfcpp::R_386_TLS_GOTDESC:        // Global-dynamic (from ~oliva url)
+    case elfcpp::R_386_TLS_DESC_CALL:
+    case elfcpp::R_386_TLS_LDM:            // Local-dynamic
+    case elfcpp::R_386_TLS_LDO_32:         // Alternate local-dynamic
+    case elfcpp::R_386_TLS_IE:             // Initial-exec
     case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:             // Local-exec
     case elfcpp::R_386_TLS_LE_32:
-    case elfcpp::R_386_TLS_GOTDESC:
-    case elfcpp::R_386_TLS_DESC_CALL:
       this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view,
                         address, view_size);
       break;
@@ -1386,24 +1386,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       = Target_i386::optimize_tls_reloc(is_final, r_type);
   switch (r_type)
     {
-    case elfcpp::R_386_TLS_LE_32:
-      value = tls_segment->vaddr() + tls_segment->memsz() - value;
-      Relocate_functions<32, false>::rel32(view, value);
-      break;
-
-    case elfcpp::R_386_TLS_LE:
-      value = value - (tls_segment->vaddr() + tls_segment->memsz());
-      Relocate_functions<32, false>::rel32(view, value);
-      break;
-
-    case elfcpp::R_386_TLS_IE:
-    case elfcpp::R_386_TLS_GOTIE:
-    case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_GD:           // Global-dynamic
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
-         Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
-                                             rel, r_type, value, view,
-                                             view_size);
+         this->tls_gd_to_le(relinfo, relnum, tls_segment,
+                            rel, r_type, value, view,
+                            view_size);
          break;
        }
       gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
@@ -1411,20 +1399,14 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
                             r_type);
       break;
 
-    case elfcpp::R_386_TLS_GD:
-      if (optimized_type == tls::TLSOPT_TO_LE)
-       {
-         this->tls_gd_to_le(relinfo, relnum, tls_segment,
-                            rel, r_type, value, view,
-                            view_size);
-         break;
-       }
+    case elfcpp::R_386_TLS_GOTDESC:      // Global-dynamic (from ~oliva url)
+    case elfcpp::R_386_TLS_DESC_CALL:
       gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
                             _("unsupported reloc %u"),
                             r_type);
       break;
 
-    case elfcpp::R_386_TLS_LDM:
+    case elfcpp::R_386_TLS_LDM:          // Local-dynamic
       if (this->local_dynamic_type_ == LOCAL_DYNAMIC_SUN)
        {
          gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
@@ -1444,7 +1426,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
                             r_type);
       break;
 
-    case elfcpp::R_386_TLS_LDO_32:
+    case elfcpp::R_386_TLS_LDO_32:       // Alternate local-dynamic
       // This reloc can appear in debugging sections, in which case we
       // won't see the TLS_LDM reloc.  The local_dynamic_type field
       // tells us this.
@@ -1458,109 +1440,31 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       Relocate_functions<32, false>::rel32(view, value);
       break;
 
-    case elfcpp::R_386_TLS_GOTDESC:
-    case elfcpp::R_386_TLS_DESC_CALL:
+    case elfcpp::R_386_TLS_IE:           // Initial-exec
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_IE_32:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
+                                             rel, r_type, value, view,
+                                             view_size);
+         break;
+       }
       gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
                             _("unsupported reloc %u"),
                             r_type);
       break;
-    }
-}
-
-// Do a relocation in which we convert a TLS Initial-Exec to a
-// Local-Exec.
-
-inline void
-Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
-                                   size_t relnum,
-                                   Output_segment* tls_segment,
-                                   const elfcpp::Rel<32, false>& rel,
-                                   unsigned int r_type,
-                                   elfcpp::Elf_types<32>::Elf_Addr value,
-                                   unsigned char* view,
-                                   off_t view_size)
-{
-  // We have to actually change the instructions, which means that we
-  // need to examine the opcodes to figure out which instruction we
-  // are looking at.
-  if (r_type == elfcpp::R_386_TLS_IE)
-    {
-      // movl %gs:XX,%eax  ==>  movl $YY,%eax
-      // movl %gs:XX,%reg  ==>  movl $YY,%reg
-      // addl %gs:XX,%reg  ==>  addl $YY,%reg
-      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -1);
-      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
-
-      unsigned char op1 = view[-1];
-      if (op1 == 0xa1)
-       {
-         // movl XX,%eax  ==>  movl $YY,%eax
-         view[-1] = 0xb8;
-       }
-      else
-       {
-         tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
 
-         unsigned char op2 = view[-2];
-         if (op2 == 0x8b)
-           {
-             // movl XX,%reg  ==>  movl $YY,%reg
-             tls::check_tls(relinfo, relnum, rel.get_r_offset(),
-                             (op1 & 0xc7) == 0x05);
-             view[-2] = 0xc7;
-             view[-1] = 0xc0 | ((op1 >> 3) & 7);
-           }
-         else if (op2 == 0x03)
-           {
-             // addl XX,%reg  ==>  addl $YY,%reg
-             tls::check_tls(relinfo, relnum, rel.get_r_offset(),
-                             (op1 & 0xc7) == 0x05);
-             view[-2] = 0x81;
-             view[-1] = 0xc0 | ((op1 >> 3) & 7);
-           }
-         else
-           tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0);
-       }
-    }
-  else
-    {
-      // subl %gs:XX(%reg1),%reg2  ==>  subl $YY,%reg2
-      // movl %gs:XX(%reg1),%reg2  ==>  movl $YY,%reg2
-      // addl %gs:XX(%reg1),%reg2  ==>  addl $YY,$reg2
-      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
-      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
+    case elfcpp::R_386_TLS_LE:           // Local-exec
+      value = value - (tls_segment->vaddr() + tls_segment->memsz());
+      Relocate_functions<32, false>::rel32(view, value);
+      break;
 
-      unsigned char op1 = view[-1];
-      unsigned char op2 = view[-2];
-      tls::check_tls(relinfo, relnum, rel.get_r_offset(),
-                     (op1 & 0xc0) == 0x80 && (op1 & 7) != 4);
-      if (op2 == 0x8b)
-       {
-         // movl %gs:XX(%reg1),%reg2  ==>  movl $YY,%reg2
-         view[-2] = 0xc7;
-         view[-1] = 0xc0 | ((op1 >> 3) & 7);
-       }
-      else if (op2 == 0x2b)
-       {
-         // subl %gs:XX(%reg1),%reg2  ==>  subl $YY,%reg2
-         view[-2] = 0x81;
-         view[-1] = 0xe8 | ((op1 >> 3) & 7);
-       }
-      else if (op2 == 0x03)
-       {
-         // addl %gs:XX(%reg1),%reg2  ==>  addl $YY,$reg2
-         view[-2] = 0x81;
-         view[-1] = 0xc0 | ((op1 >> 3) & 7);
-       }
-      else
-       tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0);
+    case elfcpp::R_386_TLS_LE_32:
+      value = tls_segment->vaddr() + tls_segment->memsz() - value;
+      Relocate_functions<32, false>::rel32(view, value);
+      break;
     }
-
-  value = tls_segment->vaddr() + tls_segment->memsz() - value;
-  if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE)
-    value = - value;
-
-  Relocate_functions<32, false>::rel32(view, value);
 }
 
 // Do a relocation in which we convert a TLS General-Dynamic to a
@@ -1659,6 +1563,102 @@ Target_i386::Relocate::tls_ld_to_le(const Relocate_info<32, false>* relinfo,
   this->skip_call_tls_get_addr_ = true;
 }
 
+// Do a relocation in which we convert a TLS Initial-Exec to a
+// Local-Exec.
+
+inline void
+Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
+                                   size_t relnum,
+                                   Output_segment* tls_segment,
+                                   const elfcpp::Rel<32, false>& rel,
+                                   unsigned int r_type,
+                                   elfcpp::Elf_types<32>::Elf_Addr value,
+                                   unsigned char* view,
+                                   off_t view_size)
+{
+  // We have to actually change the instructions, which means that we
+  // need to examine the opcodes to figure out which instruction we
+  // are looking at.
+  if (r_type == elfcpp::R_386_TLS_IE)
+    {
+      // movl %gs:XX,%eax  ==>  movl $YY,%eax
+      // movl %gs:XX,%reg  ==>  movl $YY,%reg
+      // addl %gs:XX,%reg  ==>  addl $YY,%reg
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -1);
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
+
+      unsigned char op1 = view[-1];
+      if (op1 == 0xa1)
+       {
+         // movl XX,%eax  ==>  movl $YY,%eax
+         view[-1] = 0xb8;
+       }
+      else
+       {
+         tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
+
+         unsigned char op2 = view[-2];
+         if (op2 == 0x8b)
+           {
+             // movl XX,%reg  ==>  movl $YY,%reg
+             tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+                             (op1 & 0xc7) == 0x05);
+             view[-2] = 0xc7;
+             view[-1] = 0xc0 | ((op1 >> 3) & 7);
+           }
+         else if (op2 == 0x03)
+           {
+             // addl XX,%reg  ==>  addl $YY,%reg
+             tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+                             (op1 & 0xc7) == 0x05);
+             view[-2] = 0x81;
+             view[-1] = 0xc0 | ((op1 >> 3) & 7);
+           }
+         else
+           tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0);
+       }
+    }
+  else
+    {
+      // subl %gs:XX(%reg1),%reg2  ==>  subl $YY,%reg2
+      // movl %gs:XX(%reg1),%reg2  ==>  movl $YY,%reg2
+      // addl %gs:XX(%reg1),%reg2  ==>  addl $YY,$reg2
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
+
+      unsigned char op1 = view[-1];
+      unsigned char op2 = view[-2];
+      tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+                     (op1 & 0xc0) == 0x80 && (op1 & 7) != 4);
+      if (op2 == 0x8b)
+       {
+         // movl %gs:XX(%reg1),%reg2  ==>  movl $YY,%reg2
+         view[-2] = 0xc7;
+         view[-1] = 0xc0 | ((op1 >> 3) & 7);
+       }
+      else if (op2 == 0x2b)
+       {
+         // subl %gs:XX(%reg1),%reg2  ==>  subl $YY,%reg2
+         view[-2] = 0x81;
+         view[-1] = 0xe8 | ((op1 >> 3) & 7);
+       }
+      else if (op2 == 0x03)
+       {
+         // addl %gs:XX(%reg1),%reg2  ==>  addl $YY,$reg2
+         view[-2] = 0x81;
+         view[-1] = 0xc0 | ((op1 >> 3) & 7);
+       }
+      else
+       tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0);
+    }
+
+  value = tls_segment->vaddr() + tls_segment->memsz() - value;
+  if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE)
+    value = - value;
+
+  Relocate_functions<32, false>::rel32(view, value);
+}
+
 // Relocate section data.
 
 void
index c520375a9d2686abdda918100597a874d0a9bbab..84c717d97dd3482711c0abd712d0d720fddb3877 100644 (file)
@@ -174,27 +174,27 @@ class Target_x86_64 : public Sized_target<64, false>
                 const Symbol_value<64>*,
                 unsigned char*, elfcpp::Elf_types<64>::Elf_Addr, off_t);
 
-    // Do a TLS Initial-Exec to Local-Exec transition.
-    static inline void
-    tls_ie_to_le(const Relocate_info<64, false>*, size_t relnum,
+    // Do a TLS General-Dynamic to Local-Exec transition.
+    inline void
+    tls_gd_to_le(const Relocate_info<64, false>*, size_t relnum,
                 Output_segment* tls_segment,
                 const elfcpp::Rela<64, false>&, unsigned int r_type,
                 elfcpp::Elf_types<64>::Elf_Addr value,
                 unsigned char* view,
                 off_t view_size);
 
-    // Do a TLS General-Dynamic to Local-Exec transition.
+    // Do a TLS Local-Dynamic to Local-Exec transition.
     inline void
-    tls_gd_to_le(const Relocate_info<64, false>*, size_t relnum,
+    tls_ld_to_le(const Relocate_info<64, false>*, size_t relnum,
                 Output_segment* tls_segment,
                 const elfcpp::Rela<64, false>&, unsigned int r_type,
                 elfcpp::Elf_types<64>::Elf_Addr value,
                 unsigned char* view,
                 off_t view_size);
 
-    // Do a TLS Local-Dynamic to Local-Exec transition.
-    inline void
-    tls_ld_to_le(const Relocate_info<64, false>*, size_t relnum,
+    // Do a TLS Initial-Exec to Local-Exec transition.
+    static inline void
+    tls_ie_to_le(const Relocate_info<64, false>*, size_t relnum,
                 Output_segment* tls_segment,
                 const elfcpp::Rela<64, false>&, unsigned int r_type,
                 elfcpp::Elf_types<64>::Elf_Addr value,
@@ -780,33 +780,29 @@ Target_x86_64::Scan::local(const General_options&,
       break;
 
       // These are initial tls relocs, which are expected when linking
-    case elfcpp::R_X86_64_TLSGD:
-    case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+    case elfcpp::R_X86_64_TLSGD:            // Global-dynamic
+    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
     case elfcpp::R_X86_64_TLSDESC_CALL:
-    case elfcpp::R_X86_64_TLSLD:
-    case elfcpp::R_X86_64_GOTTPOFF:
-    case elfcpp::R_X86_64_TPOFF32:
+    case elfcpp::R_X86_64_TLSLD:            // Local-dynamic
     case elfcpp::R_X86_64_DTPOFF32:
     case elfcpp::R_X86_64_DTPOFF64:
+    case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
+    case elfcpp::R_X86_64_TPOFF32:          // Local-exec
       {
        bool output_is_shared = parameters->output_is_shared();
        const tls::Tls_optimization optimized_type
             = Target_x86_64::optimize_tls_reloc(!output_is_shared, r_type);
        switch (r_type)
          {
-          case elfcpp::R_X86_64_TPOFF32:     // Local-exec
-           // FIXME: If generating a shared object, we need to copy
-           // this relocation into the object.
-           gold_assert(!output_is_shared);
+          case elfcpp::R_X86_64_TLSGD:       // General-dynamic
+          case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+          case elfcpp::R_X86_64_TLSDESC_CALL:
+           // FIXME: If not relaxing to LE, we need to generate
+           // DTPMOD64 and DTPOFF64 relocs.
+           if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_local(object, r_type);
            break;
 
-          case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
-            // FIXME: If not relaxing to LE, we need to generate a
-            // TPOFF64 reloc.
-            if (optimized_type != tls::TLSOPT_TO_LE)
-              unsupported_reloc_local(object, r_type);
-            break;
-
           case elfcpp::R_X86_64_TLSLD:       // Local-dynamic
           case elfcpp::R_X86_64_DTPOFF32:
           case elfcpp::R_X86_64_DTPOFF64:
@@ -816,14 +812,17 @@ Target_x86_64::Scan::local(const General_options&,
              unsupported_reloc_local(object, r_type);
            break;
 
+          case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
+            // FIXME: If not relaxing to LE, we need to generate a
+            // TPOFF64 reloc.
+            if (optimized_type != tls::TLSOPT_TO_LE)
+              unsupported_reloc_local(object, r_type);
+            break;
 
-          case elfcpp::R_X86_64_TLSGD:       // General-dynamic
-          case elfcpp::R_X86_64_GOTPC32_TLSDESC:
-          case elfcpp::R_X86_64_TLSDESC_CALL:
-           // FIXME: If not relaxing to LE, we need to generate
-           // DTPMOD64 and DTPOFF64 relocs.
-           if (optimized_type != tls::TLSOPT_TO_LE)
-             unsupported_reloc_local(object, r_type);
+          case elfcpp::R_X86_64_TPOFF32:     // Local-exec
+           // FIXME: If generating a shared object, we need to copy
+           // this relocation into the object.
+           gold_assert(!output_is_shared);
            break;
 
           default:
@@ -966,33 +965,29 @@ Target_x86_64::Scan::global(const General_options& options,
       break;
 
       // These are initial tls relocs, which are expected for global()
-    case elfcpp::R_X86_64_TLSGD:
-    case elfcpp::R_X86_64_TLSLD:
-    case elfcpp::R_X86_64_GOTTPOFF:
-    case elfcpp::R_X86_64_TPOFF32:
-    case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+    case elfcpp::R_X86_64_TLSGD:            // Global-dynamic
+    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
     case elfcpp::R_X86_64_TLSDESC_CALL:
+    case elfcpp::R_X86_64_TLSLD:            // Local-dynamic
     case elfcpp::R_X86_64_DTPOFF32:
     case elfcpp::R_X86_64_DTPOFF64:
+    case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
+    case elfcpp::R_X86_64_TPOFF32:          // Local-exec
       {
        const bool is_final = gsym->final_value_is_known();
        const tls::Tls_optimization optimized_type
             = Target_x86_64::optimize_tls_reloc(is_final, r_type);
        switch (r_type)
          {
-          case elfcpp::R_X86_64_TPOFF32:     // Local-exec
-           // FIXME: If generating a shared object, we need to copy
-           // this relocation into the object.
-           gold_assert(is_final);
+          case elfcpp::R_X86_64_TLSGD:       // General-dynamic
+          case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+          case elfcpp::R_X86_64_TLSDESC_CALL:
+           // FIXME: If not relaxing to LE, we need to generate
+           // DTPMOD64 and DTPOFF64, or TLSDESC, relocs.
+           if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_global(object, r_type, gsym);
            break;
 
-          case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
-            // FIXME: If not relaxing to LE, we need to generate a
-            // TPOFF64 reloc.
-            if (optimized_type != tls::TLSOPT_TO_LE)
-              unsupported_reloc_global(object, r_type, gsym);
-            break;
-
           case elfcpp::R_X86_64_TLSLD:       // Local-dynamic
           case elfcpp::R_X86_64_DTPOFF32:
           case elfcpp::R_X86_64_DTPOFF64:
@@ -1002,14 +997,17 @@ Target_x86_64::Scan::global(const General_options& options,
              unsupported_reloc_global(object, r_type, gsym);
            break;
 
+          case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
+            // FIXME: If not relaxing to LE, we need to generate a
+            // TPOFF64 reloc.
+            if (optimized_type != tls::TLSOPT_TO_LE)
+              unsupported_reloc_global(object, r_type, gsym);
+            break;
 
-          case elfcpp::R_X86_64_TLSGD:       // General-dynamic
-          case elfcpp::R_X86_64_GOTPC32_TLSDESC:
-          case elfcpp::R_X86_64_TLSDESC_CALL:
-           // FIXME: If not relaxing to LE, we need to generate
-           // DTPMOD64 and DTPOFF64, or TLSDESC, relocs.
-           if (optimized_type != tls::TLSOPT_TO_LE)
-             unsupported_reloc_global(object, r_type, gsym);
+          case elfcpp::R_X86_64_TPOFF32:     // Local-exec
+           // FIXME: If generating a shared object, we need to copy
+           // this relocation into the object.
+           gold_assert(is_final);
            break;
 
           default:
@@ -1316,14 +1314,14 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
       break;
 
       // These are initial tls relocs, which are expected when linking
-    case elfcpp::R_X86_64_TLSGD:
-    case elfcpp::R_X86_64_TLSLD:
-    case elfcpp::R_X86_64_GOTTPOFF:
-    case elfcpp::R_X86_64_TPOFF32:
-    case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+    case elfcpp::R_X86_64_TLSGD:            // Global-dynamic
+    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
     case elfcpp::R_X86_64_TLSDESC_CALL:
+    case elfcpp::R_X86_64_TLSLD:            // Local-dynamic
     case elfcpp::R_X86_64_DTPOFF32:
     case elfcpp::R_X86_64_DTPOFF64:
+    case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
+    case elfcpp::R_X86_64_TPOFF32:          // Local-exec
       this->relocate_tls(relinfo, relnum, rela, r_type, gsym, psymval, view,
                         address, view_size);
       break;
@@ -1371,26 +1369,8 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
       = Target_x86_64::optimize_tls_reloc(is_final, r_type);
   switch (r_type)
     {
-    case elfcpp::R_X86_64_TPOFF32:   // Local-exec reloc
-      value = value - (tls_segment->vaddr() + tls_segment->memsz());
-      Relocate_functions<64, false>::rel32(view, value);
-      break;
-
-    case elfcpp::R_X86_64_GOTTPOFF:  // Initial-exec reloc
-      if (optimized_type == tls::TLSOPT_TO_LE)
-       {
-         Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
-                                                rela, r_type, value, view,
-                                                view_size);
-         break;
-       }
-      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
-                            _("unsupported reloc type %u"),
-                            r_type);
-      break;
-
-    case elfcpp::R_X86_64_TLSGD:
-    case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+    case elfcpp::R_X86_64_TLSGD:            // Global-dynamic
+    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
     case elfcpp::R_X86_64_TLSDESC_CALL:
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
@@ -1403,7 +1383,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
                             _("unsupported reloc %u"), r_type);
       break;
 
-    case elfcpp::R_X86_64_TLSLD:
+    case elfcpp::R_X86_64_TLSLD:            // Local-dynamic
       if (optimized_type == tls::TLSOPT_TO_LE)
         {
          this->tls_ld_to_le(relinfo, relnum, tls_segment, rela, r_type,
@@ -1429,63 +1409,25 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
         value = value - tls_segment->vaddr();
       Relocate_functions<64, false>::rel64(view, value);
       break;
-    }
-}
 
-// Do a relocation in which we convert a TLS Initial-Exec to a
-// Local-Exec.
-
-inline void
-Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
-                                      size_t relnum,
-                                      Output_segment* tls_segment,
-                                      const elfcpp::Rela<64, false>& rela,
-                                      unsigned int,
-                                      elfcpp::Elf_types<64>::Elf_Addr value,
-                                      unsigned char* view,
-                                      off_t view_size)
-{
-  // We need to examine the opcodes to figure out which instruction we
-  // are looking at.
-
-  // movq foo@gottpoff(%rip),%reg  ==>  movq $YY,%reg
-  // addq foo@gottpoff(%rip),%reg  ==>  addq $YY,%reg
-
-  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
-  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
-
-  unsigned char op1 = view[-3];
-  unsigned char op2 = view[-2];
-  unsigned char op3 = view[-1];
-  unsigned char reg = op3 >> 3;
+    case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
+                                                rela, r_type, value, view,
+                                                view_size);
+         break;
+       }
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unsupported reloc type %u"),
+                            r_type);
+      break;
 
-  if (op2 == 0x8b)
-    {
-      // movq
-      if (op1 == 0x4c)
-        view[-3] = 0x49;
-      view[-2] = 0xc7;
-      view[-1] = 0xc0 | reg;
-    }
-  else if (reg == 4)
-    {
-      // Special handling for %rsp.
-      if (op1 == 0x4c)
-        view[-3] = 0x49;
-      view[-2] = 0x81;
-      view[-1] = 0xc0 | reg;
-    }
-  else
-    {
-      // addq
-      if (op1 == 0x4c)
-        view[-3] = 0x4d;
-      view[-2] = 0x8d;
-      view[-1] = 0x80 | reg | (reg << 3);
+    case elfcpp::R_X86_64_TPOFF32:          // Local-exec
+      value = value - (tls_segment->vaddr() + tls_segment->memsz());
+      Relocate_functions<64, false>::rel32(view, value);
+      break;
     }
-
-  value = value - (tls_segment->vaddr() + tls_segment->memsz());
-  Relocate_functions<64, false>::rela32(view, value, 0);
 }
 
 // Do a relocation in which we convert a TLS General-Dynamic to a
@@ -1552,6 +1494,62 @@ Target_x86_64::Relocate::tls_ld_to_le(const Relocate_info<64, false>* relinfo,
   this->skip_call_tls_get_addr_ = true;
 }
 
+// Do a relocation in which we convert a TLS Initial-Exec to a
+// Local-Exec.
+
+inline void
+Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
+                                      size_t relnum,
+                                      Output_segment* tls_segment,
+                                      const elfcpp::Rela<64, false>& rela,
+                                      unsigned int,
+                                      elfcpp::Elf_types<64>::Elf_Addr value,
+                                      unsigned char* view,
+                                      off_t view_size)
+{
+  // We need to examine the opcodes to figure out which instruction we
+  // are looking at.
+
+  // movq foo@gottpoff(%rip),%reg  ==>  movq $YY,%reg
+  // addq foo@gottpoff(%rip),%reg  ==>  addq $YY,%reg
+
+  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
+
+  unsigned char op1 = view[-3];
+  unsigned char op2 = view[-2];
+  unsigned char op3 = view[-1];
+  unsigned char reg = op3 >> 3;
+
+  if (op2 == 0x8b)
+    {
+      // movq
+      if (op1 == 0x4c)
+        view[-3] = 0x49;
+      view[-2] = 0xc7;
+      view[-1] = 0xc0 | reg;
+    }
+  else if (reg == 4)
+    {
+      // Special handling for %rsp.
+      if (op1 == 0x4c)
+        view[-3] = 0x49;
+      view[-2] = 0x81;
+      view[-1] = 0xc0 | reg;
+    }
+  else
+    {
+      // addq
+      if (op1 == 0x4c)
+        view[-3] = 0x4d;
+      view[-2] = 0x8d;
+      view[-1] = 0x80 | reg | (reg << 3);
+    }
+
+  value = value - (tls_segment->vaddr() + tls_segment->memsz());
+  Relocate_functions<64, false>::rela32(view, value, 0);
+}
+
 // Relocate section data.
 
 void