[GOLD][PATCH] Handle 32-bit initial TLS relocations for ARM target.

Doug Kwan (關振德) dougkwan@google.com
Wed Feb 17 21:24:00 GMT 2010


I'm sorry about attaching the wrong patch.  Here is the correct one.

-Doug


2010/2/17 Doug Kwan (關振德) <dougkwan@google.com>:
> Hi,
>
>      This patch adds some support for initial TLS relocations for the
> ARM target.  It is required for running the gold test suite on an ARM
> system running Ubuntu.  It is not yet complete.  There are known
> issues:
>
> -TLS relocations in static output objects do not work.
> -12-bit TLS relocations not supported.
> -TLS optimization not supported.
> -Additional TLS relocations defined in
> http://www.lsd.ic.unicamp.br/~oliva/writeups/TLS/RFC-TLSDESC-ARM.txt
> not supported.
>
> These will be fixed or implemented later.   This patch allows most of
> the tests in the test suite to build.
>
> -Doug
>
> 2010-02-18  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.
>
-------------- next part --------------
Index: gold/arm-reloc.def
===================================================================
RCS file: /cvs/src/src/gold/arm-reloc.def,v
retrieving revision 1.2
diff -u -u -p -r1.2 arm-reloc.def
--- gold/arm-reloc.def	4 Feb 2010 03:32:18 -0000	1.2
+++ gold/arm-reloc.def	17 Feb 2010 21:19:13 -0000
@@ -165,11 +165,11 @@ RD(GNU_VTENTRY       , STATIC  , Y, DATA
 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: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.81
diff -u -u -p -r1.81 arm.cc
--- gold/arm.cc	13 Feb 2010 02:04:20 -0000	1.81
+++ gold/arm.cc	17 Feb 2010 21:19:13 -0000
@@ -81,6 +81,9 @@ template<bool big_endian>
 class Arm_relobj;
 
 template<bool big_endian>
+class Arm_relocate_functions;
+
+template<bool big_endian>
 class Target_arm;
 
 // For convenience.
@@ -1835,11 +1838,12 @@ class Target_arm : public Sized_target<3
   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.
@@ -2284,6 +2288,16 @@ class Target_arm : public Sized_target<3
 	  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,
@@ -2295,6 +2309,11 @@ class Target_arm : public Sized_target<3
     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*);
@@ -2311,6 +2330,15 @@ class Target_arm : public Sized_target<3
   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
@@ -2323,6 +2351,10 @@ class Target_arm : public Sized_target<3
   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.
@@ -2437,7 +2469,11 @@ class Target_arm : public Sized_target<3
   // 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;
@@ -2464,6 +2500,10 @@ class Target_arm : public Sized_target<3
   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.
@@ -6519,6 +6559,79 @@ Target_arm<big_endian>::make_plt_entry(S
   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>
@@ -6769,6 +6882,97 @@ Target_arm<big_endian>::Scan::local(Symb
 		 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;
@@ -7018,6 +7222,84 @@ Target_arm<big_endian>::Scan::global(Sym
 		 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;
@@ -7269,7 +7551,7 @@ Target_arm<big_endian>::Relocate::reloca
     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;
 
@@ -7417,6 +7699,10 @@ Target_arm<big_endian>::Relocate::reloca
   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;
@@ -7720,6 +8006,18 @@ Target_arm<big_endian>::Relocate::reloca
 					      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();
     }
@@ -7749,6 +8047,125 @@ Target_arm<big_endian>::Relocate::reloca
   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>


More information about the Binutils mailing list