2010-02-18 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Fri, 19 Feb 2010 22:53:54 +0000 (22:53 +0000)
committerDoug Kwan <dougkwan@google.com>
Fri, 19 Feb 2010 22:53:54 +0000 (22:53 +0000)
* arm-reloc.def: Mark R_ARM_TLS_GD32, R_ARM_TLS_LDM32,
R_ARM_TLS_LDO32, R_ARM_TLS_IE32 and R_ARM_TLS_LE32 are implemented.
* arm.cc (Arm_relocation_functions): New forward declaration.
(Target_arm::Target_arm): Initialize new data members
got_mod_index_offset_ and tls_base_symbol_defined_.
(Target_arm::Relocate::relocate_tls): New method.
(Target_arm::optimize_tls_reloc, Target_arm::define_tls_base_symbol,
 Target_arm::got_mod_index_entry, Target_arm::rel_tls_desc_section):
New methods.
    (Target_arm::Got_type): Add GOT_TYPE_TLS_NOFFSET, GOT_TYPE_OFFSET,
GOT_TYPE_TLS_PAIR and GOT_TYPE_TLS_DESC.
(Target_arm::got_mod_index_offset_,
Target_arm::tls_base_symbol_defined_): New data members.
(Target_arm::Scan::local, Target::Scan::global,
Target_arm::Relocate::relocate): Handle 32-bit initial TLS
relocations.

gold/ChangeLog
gold/arm-reloc.def
gold/arm.cc

index 8796c6d3cd57c6359ee43c88df4db7cc36cb9298..3c68e5bf0ff7019712eafd48ef137293b5396ffa 100644 (file)
@@ -1,3 +1,22 @@
+2010-02-19  Doug Kwan  <dougkwan@google.com>
+
+       * arm-reloc.def: Mark R_ARM_TLS_GD32, R_ARM_TLS_LDM32,
+       R_ARM_TLS_LDO32, R_ARM_TLS_IE32 and R_ARM_TLS_LE32 are implemented.
+       * arm.cc (Arm_relocation_functions): New forward declaration.
+       (Target_arm::Target_arm): Initialize new data members
+       got_mod_index_offset_ and tls_base_symbol_defined_.
+       (Target_arm::Relocate::relocate_tls): New method.
+       (Target_arm::optimize_tls_reloc, Target_arm::define_tls_base_symbol,
+        Target_arm::got_mod_index_entry, Target_arm::rel_tls_desc_section):
+       New methods.
+       (Target_arm::Got_type): Add GOT_TYPE_TLS_NOFFSET, GOT_TYPE_OFFSET,
+       GOT_TYPE_TLS_PAIR and GOT_TYPE_TLS_DESC.
+       (Target_arm::got_mod_index_offset_,
+       Target_arm::tls_base_symbol_defined_): New data members.
+       (Target_arm::Scan::local, Target::Scan::global,
+       Target_arm::Relocate::relocate): Handle 32-bit initial TLS
+       relocations.
+
 2010-02-18  Doug Kwan  <dougkwan@google.com>
 
        * arm.cc (Arm_relobj::find_linked_text_section): New method.
index 39ec3d64129e9fba34b5feb27691f4c362982c31..2caf3710d17dd0effa7e22822d33301fb4451be3 100644 (file)
@@ -165,11 +165,11 @@ RD(GNU_VTENTRY       , STATIC  , Y, DATA , NONE                   ,  Y, -1, N)
 RD(GNU_VTINHERIT     , STATIC  , Y, DATA , NONE                   ,  Y, -1, N)
 RD(THM_JUMP11        , STATIC  , N, THM16, S + A - P              ,  Y, -1, Y)
 RD(THM_JUMP8         , STATIC  , N, THM16, S + A - P              ,  Y, -1, Y)
-RD(TLS_GD32          , STATIC  , N, DATA , GOT(S) + A - P         ,  N, -1, N)
-RD(TLS_LDM32         , STATIC  , N, DATA , GOT(S) + A - P         ,  N, -1, N)
-RD(TLS_LDO32         , STATIC  , N, DATA , S + A - TLS            ,  N, -1, N)
-RD(TLS_IE32          , STATIC  , N, DATA , GOT(S) + A - P         ,  N, -1, N)
-RD(TLS_LE32          , STATIC  , N, DATA , S + A - tp             ,  N, -1, N)
+RD(TLS_GD32          , STATIC  , N, DATA , GOT(S) + A - P         ,  Y, -1, N)
+RD(TLS_LDM32         , STATIC  , N, DATA , GOT(S) + A - P         ,  Y, -1, N)
+RD(TLS_LDO32         , STATIC  , N, DATA , S + A - TLS            ,  Y, -1, N)
+RD(TLS_IE32          , STATIC  , N, DATA , GOT(S) + A - P         ,  Y, -1, N)
+RD(TLS_LE32          , STATIC  , N, DATA , S + A - tp             ,  Y, -1, N)
 RD(TLS_LDO12         , STATIC  , N, ARM  , S + A - TLS            ,  N, -1, Y)
 RD(TLS_LE12          , STATIC  , N, ARM  , S + A - tp             ,  N, -1, Y)
 RD(TLS_IE12GP        , STATIC  , N, ARM  , GOT(S) + A - GOT_ORG   ,  N, -1, Y)
index d974b1bd7e7db2e317080ce485bcc9d845f9f70f..63484707b93ce81650a682c6a3e582df794b5dd8 100644 (file)
@@ -80,6 +80,9 @@ class Arm_exidx_input_section;
 template<bool big_endian>
 class Arm_relobj;
 
+template<bool big_endian>
+class Arm_relocate_functions;
+
 template<bool big_endian>
 class Target_arm;
 
@@ -1847,11 +1850,12 @@ class Target_arm : public Sized_target<32, big_endian>
   Target_arm()
     : Sized_target<32, big_endian>(&arm_info),
       got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
-      copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL), stub_tables_(),
-      stub_factory_(Stub_factory::get_instance()), may_use_blx_(false),
-      should_force_pic_veneer_(false), arm_input_section_map_(),
-      attributes_section_data_(NULL), fix_cortex_a8_(false),
-      cortex_a8_relocs_info_()
+      copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL), 
+      got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
+      stub_tables_(), stub_factory_(Stub_factory::get_instance()),
+      may_use_blx_(false), should_force_pic_veneer_(false),
+      arm_input_section_map_(), attributes_section_data_(NULL),
+      fix_cortex_a8_(false), cortex_a8_relocs_info_()
   { }
 
   // Whether we can use BLX.
@@ -2301,6 +2305,16 @@ class Target_arm : public Sized_target<32, big_endian>
          return true;
        }
     }
+
+   private:
+    // Do a TLS relocation.
+    inline typename Arm_relocate_functions<big_endian>::Status
+    relocate_tls(const Relocate_info<32, big_endian>*, Target_arm<big_endian>*,
+                 size_t, const elfcpp::Rel<32, big_endian>&, unsigned int,
+                const Sized_symbol<32>*, const Symbol_value<32>*,
+                unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
+                section_size_type);
+
   };
 
   // A class which returns the size required for a relocation type,
@@ -2312,6 +2326,11 @@ class Target_arm : public Sized_target<32, big_endian>
     get_size_for_reloc(unsigned int, Relobj*);
   };
 
+  // Adjust TLS relocation type based on the options and whether this
+  // is a local symbol.
+  static tls::Tls_optimization
+  optimize_tls_reloc(bool is_final, int r_type);
+
   // Get the GOT section, creating it if necessary.
   Output_data_got<32, big_endian>*
   got_section(Symbol_table*, Layout*);
@@ -2328,6 +2347,15 @@ class Target_arm : public Sized_target<32, big_endian>
   void
   make_plt_entry(Symbol_table*, Layout*, Symbol*);
 
+  // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
+  void
+  define_tls_base_symbol(Symbol_table*, Layout*);
+
+  // Create a GOT entry for the TLS module index.
+  unsigned int
+  got_mod_index_entry(Symbol_table* symtab, Layout* layout,
+                     Sized_relobj<32, big_endian>* object);
+
   // Get the PLT section.
   const Output_data_plt_arm<big_endian>*
   plt_section() const
@@ -2340,6 +2368,10 @@ class Target_arm : public Sized_target<32, big_endian>
   Reloc_section*
   rel_dyn_section(Layout*);
 
+  // Get the section to use for TLS_DESC relocations.
+  Reloc_section*
+  rel_tls_desc_section(Layout*) const;
+
   // Return true if the symbol may need a COPY relocation.
   // References from an executable object to non-function symbols
   // defined in a dynamic object may need a COPY relocation.
@@ -2454,7 +2486,11 @@ class Target_arm : public Sized_target<32, big_endian>
   // The types of GOT entries needed for this platform.
   enum Got_type
   {
-    GOT_TYPE_STANDARD = 0      // GOT entry for a regular symbol
+    GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
+    GOT_TYPE_TLS_NOFFSET = 1,   // GOT entry for negative TLS offset
+    GOT_TYPE_TLS_OFFSET = 2,    // GOT entry for positive TLS offset
+    GOT_TYPE_TLS_PAIR = 3,      // GOT entry for TLS module/offset pair
+    GOT_TYPE_TLS_DESC = 4       // GOT entry for TLS_DESC pair
   };
 
   typedef typename std::vector<Stub_table<big_endian>*> Stub_table_list;
@@ -2481,6 +2517,10 @@ class Target_arm : public Sized_target<32, big_endian>
   Copy_relocs<elfcpp::SHT_REL, 32, big_endian> copy_relocs_;
   // Space for variables copied with a COPY reloc.
   Output_data_space* dynbss_;
+  // Offset of the GOT entry for the TLS module index.
+  unsigned int got_mod_index_offset_;
+  // True if the _TLS_MODULE_BASE_ symbol has been defined.
+  bool tls_base_symbol_defined_;
   // Vector of Stub_tables created.
   Stub_table_list stub_tables_;
   // Stub factory.
@@ -6673,6 +6713,79 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
   this->plt_->add_entry(gsym);
 }
 
+// Get the section to use for TLS_DESC relocations.
+
+template<bool big_endian>
+typename Target_arm<big_endian>::Reloc_section*
+Target_arm<big_endian>::rel_tls_desc_section(Layout* layout) const
+{
+  return this->plt_section()->rel_tls_desc(layout);
+}
+
+// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::define_tls_base_symbol(
+    Symbol_table* symtab,
+    Layout* layout)
+{
+  if (this->tls_base_symbol_defined_)
+    return;
+
+  Output_segment* tls_segment = layout->tls_segment();
+  if (tls_segment != NULL)
+    {
+      bool is_exec = parameters->options().output_is_executable();
+      symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL,
+                                      Symbol_table::PREDEFINED,
+                                      tls_segment, 0, 0,
+                                      elfcpp::STT_TLS,
+                                      elfcpp::STB_LOCAL,
+                                      elfcpp::STV_HIDDEN, 0,
+                                      (is_exec
+                                       ? Symbol::SEGMENT_END
+                                       : Symbol::SEGMENT_START),
+                                      true);
+    }
+  this->tls_base_symbol_defined_ = true;
+}
+
+// Create a GOT entry for the TLS module index.
+
+template<bool big_endian>
+unsigned int
+Target_arm<big_endian>::got_mod_index_entry(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj<32, big_endian>* object)
+{
+  if (this->got_mod_index_offset_ == -1U)
+    {
+      gold_assert(symtab != NULL && layout != NULL && object != NULL);
+      Reloc_section* rel_dyn = this->rel_dyn_section(layout);
+      Output_data_got<32, big_endian>* got = this->got_section(symtab, layout);
+      unsigned int got_offset = got->add_constant(0);
+      rel_dyn->add_local(object, 0, elfcpp::R_ARM_TLS_DTPMOD32, got,
+                         got_offset);
+      got->add_constant(0);
+      this->got_mod_index_offset_ = got_offset;
+    }
+  return this->got_mod_index_offset_;
+}
+
+// Optimize the TLS relocation type based on what we know about the
+// symbol.  IS_FINAL is true if the final address of this symbol is
+// known at link time.
+
+template<bool big_endian>
+tls::Tls_optimization
+Target_arm<big_endian>::optimize_tls_reloc(bool, int)
+{
+  // FIXME: Currently we do not do any TLS optimization.
+  return tls::TLSOPT_NONE;
+}
+
 // Report an unsupported relocation against a local symbol.
 
 template<bool big_endian>
@@ -6929,6 +7042,97 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
                 object->name().c_str(), r_type);
       break;
 
+
+      // These are initial TLS relocs, which are expected when
+      // linking.
+    case elfcpp::R_ARM_TLS_GD32:       // Global-dynamic
+    case elfcpp::R_ARM_TLS_LDM32:      // Local-dynamic
+    case elfcpp::R_ARM_TLS_LDO32:      // Alternate local-dynamic
+    case elfcpp::R_ARM_TLS_IE32:       // Initial-exec
+    case elfcpp::R_ARM_TLS_LE32:       // Local-exec
+      {
+       bool output_is_shared = parameters->options().shared();
+       const tls::Tls_optimization optimized_type
+            = Target_arm<big_endian>::optimize_tls_reloc(!output_is_shared,
+                                                        r_type);
+       switch (r_type)
+         {
+         case elfcpp::R_ARM_TLS_GD32:          // Global-dynamic
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a pair of GOT entries for the module index and
+               // dtv-relative offset.
+                Output_data_got<32, big_endian>* got
+                    = target->got_section(symtab, layout);
+                unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+               unsigned int shndx = lsym.get_st_shndx();
+               bool is_ordinary;
+               shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+               if (!is_ordinary)
+                 object->error(_("local symbol %u has bad shndx %u"),
+                             r_sym, shndx);
+                else
+                 got->add_local_pair_with_rel(object, r_sym, shndx,
+                                              GOT_TYPE_TLS_PAIR,
+                                              target->rel_dyn_section(layout),
+                                              elfcpp::R_ARM_TLS_DTPMOD32, 0);
+             }
+           else
+             // FIXME: TLS optimization not supported yet.
+             gold_unreachable();
+           break;
+
+         case elfcpp::R_ARM_TLS_LDM32:         // Local-dynamic
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the module index.
+               target->got_mod_index_entry(symtab, layout, object);
+             }
+           else
+             // FIXME: TLS optimization not supported yet.
+             gold_unreachable();
+           break;
+
+         case elfcpp::R_ARM_TLS_LDO32:         // Alternate local-dynamic
+           break;
+
+         case elfcpp::R_ARM_TLS_IE32:          // Initial-exec
+           layout->set_has_static_tls();
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the tp-relative offset.
+                Output_data_got<32, big_endian>* got
+                    = target->got_section(symtab, layout);
+                unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+               got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+                                       target->rel_dyn_section(layout),
+                                       elfcpp::R_ARM_TLS_TPOFF32);
+             }
+           else
+             // FIXME: TLS optimization not supported yet.
+             gold_unreachable();
+           break;
+
+         case elfcpp::R_ARM_TLS_LE32:          // Local-exec
+           layout->set_has_static_tls();
+           if (output_is_shared)
+             {
+               // We need to create a dynamic relocation.
+                gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+                unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+               Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+               rel_dyn->add_local(object, r_sym, elfcpp::R_ARM_TLS_TPOFF32,
+                                  output_section, data_shndx,
+                                  reloc.get_r_offset());
+             }
+           break;
+
+         default:
+           gold_unreachable();
+         }
+      }
+      break;
+
     default:
       unsupported_reloc_local(object, r_type);
       break;
@@ -7185,6 +7389,84 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
                 object->name().c_str(), r_type);
       break;
 
+      // These are initial tls relocs, which are expected when
+      // linking.
+    case elfcpp::R_ARM_TLS_GD32:       // Global-dynamic
+    case elfcpp::R_ARM_TLS_LDM32:      // Local-dynamic
+    case elfcpp::R_ARM_TLS_LDO32:      // Alternate local-dynamic
+    case elfcpp::R_ARM_TLS_IE32:       // Initial-exec
+    case elfcpp::R_ARM_TLS_LE32:       // Local-exec
+      {
+       const bool is_final = gsym->final_value_is_known();
+       const tls::Tls_optimization optimized_type
+            = Target_arm<big_endian>::optimize_tls_reloc(is_final, r_type);
+       switch (r_type)
+         {
+         case elfcpp::R_ARM_TLS_GD32:          // Global-dynamic
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a pair of GOT entries for the module index and
+               // dtv-relative offset.
+                Output_data_got<32, big_endian>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+                                             target->rel_dyn_section(layout),
+                                             elfcpp::R_ARM_TLS_DTPMOD32,
+                                             elfcpp::R_ARM_TLS_DTPOFF32);
+             }
+           else
+             // FIXME: TLS optimization not supported yet.
+             gold_unreachable();
+           break;
+
+         case elfcpp::R_ARM_TLS_LDM32:         // Local-dynamic
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the module index.
+               target->got_mod_index_entry(symtab, layout, object);
+             }
+           else
+             // FIXME: TLS optimization not supported yet.
+             gold_unreachable();
+           break;
+
+         case elfcpp::R_ARM_TLS_LDO32:         // Alternate local-dynamic
+           break;
+
+         case elfcpp::R_ARM_TLS_IE32:          // Initial-exec
+           layout->set_has_static_tls();
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the tp-relative offset.
+                Output_data_got<32, big_endian>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                                         target->rel_dyn_section(layout),
+                                         elfcpp::R_ARM_TLS_TPOFF32);
+             }
+           else
+             // FIXME: TLS optimization not supported yet.
+             gold_unreachable();
+           break;
+
+         case elfcpp::R_ARM_TLS_LE32:  // Local-exec
+           layout->set_has_static_tls();
+           if (parameters->options().shared())
+             {
+               // We need to create a dynamic relocation.
+                Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+                rel_dyn->add_global(gsym, elfcpp::R_ARM_TLS_TPOFF32,
+                                   output_section, object,
+                                    data_shndx, reloc.get_r_offset());
+             }
+           break;
+
+         default:
+           gold_unreachable();
+         }
+      }
+      break;
+
     default:
       unsupported_reloc_global(object, r_type, gsym);
       break;
@@ -7436,7 +7718,7 @@ Target_arm<big_endian>::Relocate::relocate(
     const Symbol_value<32>* psymval,
     unsigned char* view,
     Arm_address address,
-    section_size_type /* view_size */ )
+    section_size_type view_size)
 {
   typedef Arm_relocate_functions<big_endian> Arm_relocate_functions;
 
@@ -7584,6 +7866,10 @@ Target_arm<big_endian>::Relocate::relocate(
   switch(reloc_property->relative_address_base())
     {
     case Arm_reloc_property::RAB_NONE:
+    // Relocations with relative address bases RAB_TLS and RAB_tp are
+    // handled by relocate_tls.  So we do not need to do anything here.
+    case Arm_reloc_property::RAB_TLS:
+    case Arm_reloc_property::RAB_tp:
       break;
     case Arm_reloc_property::RAB_B_S:
       relative_address_base = sym_origin;
@@ -7887,6 +8173,18 @@ Target_arm<big_endian>::Relocate::relocate(
                                              relative_address_base);
       break;
 
+      // These are initial tls relocs, which are expected when
+      // linking.
+    case elfcpp::R_ARM_TLS_GD32:       // Global-dynamic
+    case elfcpp::R_ARM_TLS_LDM32:      // Local-dynamic
+    case elfcpp::R_ARM_TLS_LDO32:      // Alternate local-dynamic
+    case elfcpp::R_ARM_TLS_IE32:       // Initial-exec
+    case elfcpp::R_ARM_TLS_LE32:       // Local-exec
+      reloc_status =
+       this->relocate_tls(relinfo, target, relnum, rel, r_type, gsym, psymval,
+                          view, address, view_size);
+      break;
+
     default:
       gold_unreachable();
     }
@@ -7916,6 +8214,125 @@ Target_arm<big_endian>::Relocate::relocate(
   return true;
 }
 
+// Perform a TLS relocation.
+
+template<bool big_endian>
+inline typename Arm_relocate_functions<big_endian>::Status
+Target_arm<big_endian>::Relocate::relocate_tls(
+    const Relocate_info<32, big_endian>* relinfo,
+    Target_arm<big_endian>* target,
+    size_t relnum,
+    const elfcpp::Rel<32, big_endian>& rel,
+    unsigned int r_type,
+    const Sized_symbol<32>* gsym,
+    const Symbol_value<32>* psymval,
+    unsigned char* view,
+    elfcpp::Elf_types<32>::Elf_Addr,
+    section_size_type /*view_size*/ )
+{
+  typedef Arm_relocate_functions<big_endian> ArmRelocFuncs;
+  Output_segment* tls_segment = relinfo->layout->tls_segment();
+
+  const Sized_relobj<32, big_endian>* object = relinfo->object;
+
+  elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(object, 0);
+
+  const bool is_final = (gsym == NULL
+                        ? !parameters->options().shared()
+                        : gsym->final_value_is_known());
+  const tls::Tls_optimization optimized_type
+      = Target_arm<big_endian>::optimize_tls_reloc(is_final, r_type);
+  switch (r_type)
+    {
+    case elfcpp::R_ARM_TLS_GD32:       // Global-dynamic
+        {
+          unsigned int got_type = GOT_TYPE_TLS_PAIR;
+          unsigned int got_offset;
+          if (gsym != NULL)
+            {
+              gold_assert(gsym->has_got_offset(got_type));
+              got_offset = gsym->got_offset(got_type) - target->got_size();
+            }
+          else
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              got_offset = (object->local_got_offset(r_sym, got_type)
+                           - target->got_size());
+            }
+          if (optimized_type == tls::TLSOPT_NONE)
+            {
+              // Relocate the field with the offset of the pair of GOT
+              // entries.
+              Relocate_functions<32, big_endian>::rel32(view, got_offset);
+              return ArmRelocFuncs::STATUS_OKAY;
+            }
+        }
+      break;
+
+    case elfcpp::R_ARM_TLS_LDM32:      // Local-dynamic
+      if (optimized_type == tls::TLSOPT_NONE)
+        {
+          // Relocate the field with the offset of the GOT entry for
+          // the module index.
+          unsigned int got_offset;
+          got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
+                       - target->got_size());
+          Relocate_functions<32, big_endian>::rel32(view, got_offset);
+         return ArmRelocFuncs::STATUS_OKAY;
+        }
+      break;
+
+    case elfcpp::R_ARM_TLS_LDO32:      // Alternate local-dynamic
+      Relocate_functions<32, big_endian>::rel32(view, value);
+      return ArmRelocFuncs::STATUS_OKAY;
+
+    case elfcpp::R_ARM_TLS_IE32:       // Initial-exec
+      if (optimized_type == tls::TLSOPT_NONE)
+        {
+          // Relocate the field with the offset of the GOT entry for
+          // the tp-relative offset of the symbol.
+         unsigned int got_type = GOT_TYPE_TLS_OFFSET;
+          unsigned int got_offset;
+          if (gsym != NULL)
+            {
+              gold_assert(gsym->has_got_offset(got_type));
+              got_offset = gsym->got_offset(got_type);
+            }
+          else
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              got_offset = object->local_got_offset(r_sym, got_type);
+            }
+          // All GOT offsets are relative to the end of the GOT.
+          got_offset -= target->got_size();
+          Relocate_functions<32, big_endian>::rel32(view, got_offset);
+         return ArmRelocFuncs::STATUS_OKAY;
+        }
+      break;
+
+    case elfcpp::R_ARM_TLS_LE32:       // Local-exec
+      // If we're creating a shared library, a dynamic relocation will
+      // have been created for this location, so do not apply it now.
+      if (!parameters->options().shared())
+        {
+          gold_assert(tls_segment != NULL);
+          value = tls_segment->memsz() - value;
+          Relocate_functions<32, false>::rel32(view, value);
+        }
+      return ArmRelocFuncs::STATUS_OKAY;
+    
+    default:
+      gold_unreachable();
+    }
+
+  gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
+                        _("unsupported reloc %u"),
+                        r_type);
+  return ArmRelocFuncs::STATUS_BAD_RELOC;
+}
+
 // Relocate section data.
 
 template<bool big_endian>