[GOLD][PATCH] Handle initial TLS relocations in static linking.

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


Sorry, I forgot the patch.  Here it is.

-Doug

2010/2/23 Doug Kwan (關振德) <dougkwan@google.com>:
> Hi,
>
>     This bug adds code to handle initial TLS relocations in static
> linking.  It also fixes the relocation operations of TLS relocations
> incorrectly implemented.  It also fixed two other problems.  The
> trailing dots from section name prefixes ".ARM.exidx." and
> ".ARM.extab." are removed by this for ARM ELF specifications
> conformance.   We also skip special gc processing for EXIDX section if
> --gc-sections is not used.  The hook is shared by both GC and ICF.
> Using only --icf but not --gc-sections caused gold crashing.   This
> patch was tested by running the gold test suite on an ARM system.
> Only one test failed and it was not a new failure.
>
> -Doug
>
> 2010-02-23  Doug Kwan  <dougkwan@google.com>
>
>        * arm.cc (Arm_output_data_got): New class.
>        (ARM_TCB_SIZE): New constant
>        (Target_arm): Use Arm_output_data_got instead of Output_data_got.
>        (Arm_output_section::fix_exidx_coverage): Add a parameter for layout.
>        If user uses a script with a SECTIONS clause, issue only a warning
>        for a misplaced EXIDX input section.  Otherwise, issue an error.
>        (Arm_relobj::do_gc_process_relocs): Exit early if we are not doing
>        garbage collection.
>        (Target_arm::got_mode_index_entry): Handle static linking.
>        (Target_arm::Scan::local): Ditto.
>        (Target_arm::Scan::global): Ditto.
>        (Target_arm::Relocate::relocate_tls): Handle static linking.  Fix
>        all incorrectly implemented relocations.
>        (Target_arm::fix_exidx_coverage): Pass layout to
>        Arm_output_section::fix_exidx_coverage.
>        * layout.cc (Layout::section_name_mapping): Remove trailing dots
>        from ".ARM.exidx." and ".ARM.extab.".
>
-------------- next part --------------
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.85
diff -u -u -p -r1.85 arm.cc
--- gold/arm.cc	23 Feb 2010 17:45:38 -0000	1.85
+++ gold/arm.cc	24 Feb 2010 05:29:40 -0000
@@ -84,6 +84,9 @@ template<bool big_endian>
 class Arm_relocate_functions;
 
 template<bool big_endian>
+class Arm_output_data_got;
+
+template<bool big_endian>
 class Target_arm;
 
 // For convenience.
@@ -97,6 +100,9 @@ const int32_t THM_MAX_BWD_BRANCH_OFFSET 
 const int32_t THM2_MAX_FWD_BRANCH_OFFSET = (((1 << 24) - 2) + 4);
 const int32_t THM2_MAX_BWD_BRANCH_OFFSET = (-(1 << 24) + 4);
 
+// Thread Control Block size.
+const size_t ARM_TCB_SIZE = 8;
+
 // The arm target class.
 //
 // This is a very simple port of gold for ARM-EABI.  It is intended for
@@ -1318,7 +1324,8 @@ class Arm_output_section : public Output
   // is a list of text input sections sorted in ascending order of their
   // output addresses.
   void
-  fix_exidx_coverage(const Text_section_list& sorted_text_section,
+  fix_exidx_coverage(Layout* layout,
+		     const Text_section_list& sorted_text_section,
 		     Symbol_table* symtab);
 
  private:
@@ -1778,6 +1785,142 @@ class Cortex_a8_reloc
   Arm_address destination_;
 };
 
+// Arm_output_data_got class.  We derive this from Output_data_got to add
+// extra methods to handle TLS relocations in a static link.
+
+template<bool big_endian>
+class Arm_output_data_got : public Output_data_got<32, big_endian>
+{
+ public:
+  Arm_output_data_got(Symbol_table* symtab, Layout* layout)
+    : Output_data_got<32, big_endian>(), symbol_table_(symtab), layout_(layout)
+  { }
+
+  // Add a static entry for the GOT entry at OFFSET.  GSYM is a global
+  // symbol and R_TYPE is the code of a dynamic relocation that needs to be
+  // applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+  { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, gsym)); }
+
+  // Add a static reloc for the GOT entry at OFFSET.  RELOBJ is an object
+  // defining a local symbol with INDEX.  R_TYPE is the code of a dynamic
+  // relocation that needs to be applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type,
+		   Sized_relobj<32, big_endian>* relobj, unsigned int index)
+  {
+    this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj,
+						index));
+  }
+
+  // Add a GOT pair for R_ARM_TLS_GD32.  The creates a pair of GOT entries.
+  // The first one is initialized to be 1, which is the module index for
+  // the main executable and the second one 0.  A reloc of the type
+  // R_ARM_TLS_DTPOFF32 will be created for the second GOT entry and will
+  // be applied by gold.  GSYM is a global symbol.
+  void
+  add_tls_gd32_with_static_reloc(unsigned int got_type, Symbol* gsym);
+
+  // Same as the above but for a local symbol in OBJECT with INDEX.
+  void
+  add_tls_gd32_with_static_reloc(unsigned int got_type,
+				 Sized_relobj<32, big_endian>* object,
+				 unsigned int index);
+
+ protected:
+  // Write out the GOT table.
+  void
+  do_write(Output_file*);
+
+ private:
+  // This class represent dynamic relocations that need to be applied by
+  // gold because we are using TLS relocations in a static link.
+  class Static_reloc
+  {
+   public:
+    Static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(true)
+    { this->u_.global.symbol = gsym; }
+
+    Static_reloc(unsigned int got_offset, unsigned int r_type,
+	  Sized_relobj<32, big_endian>* relobj, unsigned int index)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false)
+    {
+      this->u_.local.relobj = relobj;
+      this->u_.local.index = index;
+    }
+
+    // Return the GOT offset.
+    unsigned int
+    got_offset() const
+    { return this->got_offset_; }
+
+    unsigned int
+    r_type() const
+    { return this->r_type_; }
+
+    bool
+    symbol_is_global() const
+    { return this->symbol_is_global_; }
+
+    // For a relocation against a global symbol, the global symbol.
+    Symbol*
+    symbol() const
+    {
+      gold_assert(this->symbol_is_global_);
+      return this->u_.global.symbol;
+    }
+
+    // For a relocation against a local symbol, the defining object.
+    Sized_relobj<32, big_endian>*
+    relobj() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.relobj;
+    }
+
+    // For a relocation against a local symbol, the local symbol index.
+    unsigned int
+    index() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.index;
+    }
+
+   private:
+    // GOT offset of the entry to which this relocation is applied.
+    unsigned int got_offset_;
+    // Type of relocation.
+    unsigned int r_type_;
+    // Whether this relocation is against a global symbol.
+    bool symbol_is_global_;
+    // A global or local symbol.
+    union
+    {
+      struct
+      {
+	// For a global symbol, the symbol itself.
+	Symbol* symbol;
+      } global;
+      struct
+      {
+	// For a local symbol, the object defining object.
+	Sized_relobj<32, big_endian>* relobj;
+	// For a local symbol, the symbol index.
+	unsigned int index;
+      } local;
+    } u_;
+  };
+
+  // Symbol table of the output object.
+  Symbol_table* symbol_table_;
+  // Layout of the output object.
+  Layout* layout_;
+  // Static relocs to be applied to the GOT.
+  std::vector<Static_reloc> static_relocs_;
+};
+
 // Utilities for manipulating integers of up to 32-bits
 
 namespace utils
@@ -2332,7 +2475,7 @@ class Target_arm : public Sized_target<3
   optimize_tls_reloc(bool is_final, int r_type);
 
   // Get the GOT section, creating it if necessary.
-  Output_data_got<32, big_endian>*
+  Arm_output_data_got<big_endian>*
   got_section(Symbol_table*, Layout*);
 
   // Get the GOT PLT section.
@@ -2506,7 +2649,7 @@ class Target_arm : public Sized_target<3
 	  Cortex_a8_relocs_info;
 
   // The GOT section.
-  Output_data_got<32, big_endian>* got_;
+  Arm_output_data_got<big_endian>* got_;
   // The PLT section.
   Output_data_plt_arm<big_endian>* plt_;
   // The GOT PLT section.
@@ -3791,14 +3934,14 @@ Arm_relocate_functions<big_endian>::thm_
 // Get the GOT section, creating it if necessary.
 
 template<bool big_endian>
-Output_data_got<32, big_endian>*
+Arm_output_data_got<big_endian>*
 Target_arm<big_endian>::got_section(Symbol_table* symtab, Layout* layout)
 {
   if (this->got_ == NULL)
     {
       gold_assert(symtab != NULL && layout != NULL);
 
-      this->got_ = new Output_data_got<32, big_endian>();
+      this->got_ = new Arm_output_data_got<big_endian>(symtab, layout);
 
       Output_section* os;
       os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
@@ -3806,7 +3949,6 @@ Target_arm<big_endian>::got_section(Symb
 					    | elfcpp::SHF_WRITE),
 					   this->got_, false, true, true,
 					   false);
-
       // The old GNU linker creates a .got.plt section.  We just
       // create another set of data in the .got section.  Note that we
       // always create a PLT if we create a GOT, although the PLT
@@ -5382,6 +5524,7 @@ Arm_output_section<big_endian>::append_t
 template<bool big_endian>
 void
 Arm_output_section<big_endian>::fix_exidx_coverage(
+    Layout* layout,
     const Text_section_list& sorted_text_sections,
     Symbol_table* symtab)
 {
@@ -5445,9 +5588,18 @@ Arm_output_section<big_endian>::fix_exid
       if (known_input_sections.find(sid) == known_input_sections.end())
 	{
 	  // This is odd.  We have not seen this EXIDX input section before.
-	  // We cannot do fix-up.
-	  gold_error(_("EXIDX section %u of %s is not in EXIDX output section"),
-		     exidx_shndx, exidx_relobj->name().c_str());
+	  // We cannot do fix-up.  If we saw a SECTIONS clause in a script,
+	  // issue a warning instead.  We assume the user knows what he
+	  // or she is doing.  Otherwise, this is an error.
+	  if (layout->script_options()->saw_sections_clause())
+	    gold_warning(_("unwinding may not work because EXIDX input section"
+			   " %u of %s is not in EXIDX output section"),
+			 exidx_shndx, exidx_relobj->name().c_str());
+	  else
+	    gold_error(_("unwinding may not work because EXIDX input section"
+			 " %u of %s is not in EXIDX output section"),
+		       exidx_shndx, exidx_relobj->name().c_str());
+
 	  exidx_fixup.add_exidx_cantunwind_as_needed();
 	  continue;
 	}
@@ -6273,6 +6425,11 @@ Arm_relobj<big_endian>::do_gc_process_re
   // First, call base class method to process relocations in this object.
   Sized_relobj<32, big_endian>::do_gc_process_relocs(symtab, layout, rd);
 
+  // If --gc-sections is not specified, there is nothing more to do.
+  // This happens when --icf is used but --gc-sections is not.
+  if (!parameters->options().gc_sections())
+    return;
+  
   unsigned int shnum = this->shnum();
   const unsigned int shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
   const unsigned char* pshdrs = this->get_view(this->elf_file()->shoff(),
@@ -6479,6 +6636,196 @@ Stub_addend_reader<elfcpp::SHT_REL, big_
     }
 }
 
+// Arm_output_data_got methods.
+
+// Add a GOT pair for R_ARM_TLS_GD32.  The creates a pair of GOT entries.
+// The first one is initialized to be 1, which is the module index for
+// the main executable and the second one 0.  A reloc of the type
+// R_ARM_TLS_DTPOFF32 will be created for the second GOT entry and will
+// be applied by gold.  GSYM is a global symbol.
+//
+template<bool big_endian>
+void
+Arm_output_data_got<big_endian>::add_tls_gd32_with_static_reloc(
+    unsigned int got_type,
+    Symbol* gsym)
+{
+  if (gsym->has_got_offset(got_type))
+    return;
+
+  // We are doing a static link.  Just mark it as belong to module 1,
+  // the executable.
+  unsigned int got_offset = this->add_constant(1);
+  gsym->set_got_offset(got_type, got_offset); 
+  got_offset = this->add_constant(0);
+  this->static_relocs_.push_back(Static_reloc(got_offset,
+					      elfcpp::R_ARM_TLS_DTPOFF32,
+					      gsym));
+}
+
+// Same as the above but for a local symbol.
+
+template<bool big_endian>
+void
+Arm_output_data_got<big_endian>::add_tls_gd32_with_static_reloc(
+  unsigned int got_type,
+  Sized_relobj<32, big_endian>* object,
+  unsigned int index)
+{
+  if (object->local_has_got_offset(index, got_type))
+    return;
+
+  // We are doing a static link.  Just mark it as belong to module 1,
+  // the executable.
+  unsigned int got_offset = this->add_constant(1);
+  object->set_local_got_offset(index, got_type, got_offset);
+  got_offset = this->add_constant(0);
+  this->static_relocs_.push_back(Static_reloc(got_offset, 
+					      elfcpp::R_ARM_TLS_DTPOFF32, 
+					      object, index));
+}
+
+template<bool big_endian>
+void
+Arm_output_data_got<big_endian>::do_write(Output_file* of)
+{
+  // Call parent to write out GOT.
+  Output_data_got<32, big_endian>::do_write(of);
+
+  // We are done if there is no fix up.
+  if (this->static_relocs_.empty())
+    return;
+
+  gold_assert(parameters->doing_static_link());
+
+  const off_t offset = this->offset();
+  const section_size_type oview_size =
+    convert_to_section_size_type(this->data_size());
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+  Output_segment* tls_segment = this->layout_->tls_segment();
+  gold_assert(tls_segment != NULL);
+  
+  // The thread pointer $tp points to the TCB, which is followed by the
+  // TLS.  So we need to adjust $tp relative addressing by this amount.
+  Arm_address aligned_tcb_size =
+    align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment());
+
+  for (size_t i = 0; i < this->static_relocs_.size(); ++i)
+    {
+      Static_reloc& reloc(this->static_relocs_[i]);
+      
+      const Sized_symbol<32>* sym;
+
+      Symbol_value<32> symval;
+      const Symbol_value<32> *psymval;
+      bool is_defined_in_discarded_section;
+      Sized_relobj<32, big_endian>* object = NULL;
+      unsigned int shndx = elfcpp::SHN_UNDEF;
+	  bool is_ordinary;
+      if (!reloc.symbol_is_global())
+	{
+	  sym = NULL;
+	  object = reloc.relobj();
+	  psymval = object->local_symbol(reloc.index());
+
+          // If the local symbol belongs to a section we are discarding,
+          // and that section is a debug section, try to find the
+          // corresponding kept section and map this symbol to its
+          // counterpart in the kept section.  The symbol must not 
+          // correspond to a section we are folding.
+	  shndx = psymval->input_shndx(&is_ordinary);
+	  is_defined_in_discarded_section =
+	    (is_ordinary
+	     && shndx != elfcpp::SHN_UNDEF
+	     && !object->is_section_included(shndx)
+	     && !this->symbol_table_->is_section_folded(object, shndx));
+	}
+      else
+	{
+	  const Symbol* gsym = reloc.symbol();
+	  gold_assert(gsym != NULL);
+	  if (gsym->is_forwarder())
+	    gsym = this->symbol_table_->resolve_forwards(gsym);
+
+	  sym = static_cast<const Sized_symbol<32>*>(gsym);
+	  if (sym->has_symtab_index())
+	    symval.set_output_symtab_index(sym->symtab_index());
+	  else
+	    symval.set_no_output_symtab_entry();
+	  symval.set_output_value(sym->value());
+	  psymval = &symval;
+
+	  is_defined_in_discarded_section =
+	    (gsym->is_defined_in_discarded_section()
+	     && gsym->is_undefined());
+
+	  // We need to figure out input object and section index if the
+	  // symbol is in a discarded_section.
+	  if (is_defined_in_discarded_section)
+	    {
+	      gold_assert(gsym->source() == Symbol::FROM_OBJECT
+			  && !gsym->in_dyn());
+	      object =
+		static_cast<Sized_relobj<32, big_endian>*>(gsym->object());
+	      shndx = gsym->shndx(&is_ordinary);
+	    }
+	}
+
+      Symbol_value<32> symval2;
+      if (is_defined_in_discarded_section)
+	{
+	  gold_assert(object != NULL && shndx != elfcpp::SHN_UNDEF);
+	  std::string name = object->section_name(shndx);
+	  Comdat_behavior comdat_behavior = get_comdat_behavior(name.c_str());
+	  if (comdat_behavior == CB_PRETEND)
+	    {
+	      // FIXME: This case does not work for global symbols.
+	      // We have no place to store the original section index.
+	      // Fortunately this does not matter for comdat sections,
+	      // only for sections explicitly discarded by a linker
+	      // script.
+	      bool found;
+	      Arm_address value = object->map_to_kept_section(shndx, &found);
+	      if (found)
+		symval2.set_output_value(value + psymval->input_value());
+	      else
+		symval2.set_output_value(0);
+	    }
+	  else
+	    {
+	      // We don't need to issue a warning since a warning about the
+	      // same discarded symbol will be issue in the initial TLS
+	      // relocation.	
+	      symval2.set_output_value(0);
+	    }
+	  symval2.set_no_output_symtab_entry();
+	  psymval = &symval2;
+	}
+
+      unsigned got_offset = reloc.got_offset();
+      gold_assert(got_offset < oview_size);
+
+      typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+      Valtype* wv = reinterpret_cast<Valtype*>(oview + got_offset);
+      Valtype x;
+      switch (reloc.r_type())
+	{
+	case elfcpp::R_ARM_TLS_DTPOFF32:
+	  x = psymval->value(object, 0);
+	  break;
+	case elfcpp::R_ARM_TLS_TPOFF32:
+	  x = psymval->value(object, 0) + aligned_tcb_size;
+	  break;
+	default:
+	  gold_unreachable();
+	}
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+    }
+
+  of->write_output_view(offset, oview_size, oview);
+}
+
 // A class to handle the PLT data.
 
 template<bool big_endian>
@@ -6764,11 +7111,22 @@ Target_arm<big_endian>::got_mod_index_en
   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);
+      Arm_output_data_got<big_endian>* got = this->got_section(symtab, layout);
+      unsigned int got_offset;
+      if (!parameters->doing_static_link())
+	{
+	  got_offset = got->add_constant(0);
+	  Reloc_section* rel_dyn = this->rel_dyn_section(layout);
+	  rel_dyn->add_local(object, 0, elfcpp::R_ARM_TLS_DTPMOD32, got,
+			     got_offset);
+	}
+      else
+	{
+	  // We are doing a static link.  Just mark it as belong to module 1,
+	  // the executable.
+	  got_offset = got->add_constant(1);
+	}
+
       got->add_constant(0);
       this->got_mod_index_offset_ = got_offset;
     }
@@ -7010,7 +7368,7 @@ Target_arm<big_endian>::Scan::local(Symb
     case elfcpp::R_ARM_GOT_PREL:
       {
 	// The symbol requires a GOT entry.
-	Output_data_got<32, big_endian>* got =
+	Arm_output_data_got<big_endian>* got =
 	  target->got_section(symtab, layout);
 	unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
 	if (got->add_local(object, r_sym, GOT_TYPE_STANDARD))
@@ -7063,20 +7421,27 @@ Target_arm<big_endian>::Scan::local(Symb
 	      {
 	        // Create a pair of GOT entries for the module index and
 	        // dtv-relative offset.
-                Output_data_got<32, big_endian>* got
+                Arm_output_data_got<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
+		  {
+		    object->error(_("local symbol %u has bad shndx %u"),
+				  r_sym, shndx);
+		    break;
+		  }
+
+		if (!parameters->doing_static_link())
 		  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
+		  got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR,
+						      object, r_sym);
 	      }
 	    else
 	      // FIXME: TLS optimization not supported yet.
@@ -7101,13 +7466,25 @@ Target_arm<big_endian>::Scan::local(Symb
 	    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);
+		// Create a GOT entry for the tp-relative offset.
+		Arm_output_data_got<big_endian>* got
+		  = target->got_section(symtab, layout);
+		unsigned int r_sym =
+		   elfcpp::elf_r_sym<32>(reloc.get_r_info());
+		if (!parameters->doing_static_link())
+		    got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+					    target->rel_dyn_section(layout),
+					    elfcpp::R_ARM_TLS_TPOFF32);
+		else if (!object->local_has_got_offset(r_sym,
+						       GOT_TYPE_TLS_OFFSET))
+		  {
+		    got->add_local(object, r_sym, GOT_TYPE_TLS_OFFSET);
+		    unsigned int got_offset =
+		      object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
+		    got->add_static_reloc(got_offset,
+					  elfcpp::R_ARM_TLS_TPOFF32, object,
+					  r_sym);
+		  }
 	      }
 	    else
 	      // FIXME: TLS optimization not supported yet.
@@ -7351,7 +7728,7 @@ Target_arm<big_endian>::Scan::global(Sym
     case elfcpp::R_ARM_GOT_PREL:
       {
 	// The symbol requires a GOT entry.
-	Output_data_got<32, big_endian>* got =
+	Arm_output_data_got<big_endian>* got =
 	  target->got_section(symtab, layout);
 	if (gsym->final_value_is_known())
 	  got->add_global(gsym, GOT_TYPE_STANDARD);
@@ -7408,12 +7785,15 @@ Target_arm<big_endian>::Scan::global(Sym
 	      {
 	        // Create a pair of GOT entries for the module index and
 	        // dtv-relative offset.
-                Output_data_got<32, big_endian>* got
+                Arm_output_data_got<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);
+		if (!parameters->doing_static_link())
+		  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
+		  got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR, gsym);
 	      }
 	    else
 	      // FIXME: TLS optimization not supported yet.
@@ -7438,12 +7818,21 @@ Target_arm<big_endian>::Scan::global(Sym
 	    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);
+		// Create a GOT entry for the tp-relative offset.
+		Arm_output_data_got<big_endian>* got
+		  = target->got_section(symtab, layout);
+		if (!parameters->doing_static_link())
+		  got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+					   target->rel_dyn_section(layout),
+					   elfcpp::R_ARM_TLS_TPOFF32);
+		else if (!gsym->has_got_offset(GOT_TYPE_TLS_OFFSET))
+		  {
+		    got->add_global(gsym, GOT_TYPE_TLS_OFFSET);
+		    unsigned int got_offset =
+		       gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+		    got->add_static_reloc(got_offset,
+					  elfcpp::R_ARM_TLS_TPOFF32, gsym);
+		  }
 	      }
 	    else
 	      // FIXME: TLS optimization not supported yet.
@@ -8233,10 +8622,11 @@ Target_arm<big_endian>::Relocate::reloca
     const Sized_symbol<32>* gsym,
     const Symbol_value<32>* psymval,
     unsigned char* view,
-    elfcpp::Elf_types<32>::Elf_Addr,
+    elfcpp::Elf_types<32>::Elf_Addr address,
     section_size_type /*view_size*/ )
 {
   typedef Arm_relocate_functions<big_endian> ArmRelocFuncs;
+  typedef Relocate_functions<32, big_endian> RelocFuncs;
   Output_segment* tls_segment = relinfo->layout->tls_segment();
 
   const Sized_relobj<32, big_endian>* object = relinfo->object;
@@ -8268,9 +8658,12 @@ Target_arm<big_endian>::Relocate::reloca
             }
           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);
+	      Arm_address got_entry =
+		target->got_plt_section()->address() + got_offset;
+	      
+              // Relocate the field with the PC relative offset of the pair of
+              // GOT entries.
+	      RelocFuncs::pcrel32(view, got_entry, address);
               return ArmRelocFuncs::STATUS_OKAY;
             }
         }
@@ -8284,13 +8677,18 @@ Target_arm<big_endian>::Relocate::reloca
           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);
+	  Arm_address got_entry =
+	    target->got_plt_section()->address() + got_offset;
+
+          // Relocate the field with the PC relative offset of the pair of
+          // GOT entries.
+          RelocFuncs::pcrel32(view, got_entry, address);
 	  return ArmRelocFuncs::STATUS_OKAY;
         }
       break;
 
     case elfcpp::R_ARM_TLS_LDO32:	// Alternate local-dynamic
-      Relocate_functions<32, big_endian>::rel32(view, value);
+      RelocFuncs::rel32(view, value);
       return ArmRelocFuncs::STATUS_OKAY;
 
     case elfcpp::R_ARM_TLS_IE32:	// Initial-exec
@@ -8311,9 +8709,15 @@ Target_arm<big_endian>::Relocate::reloca
               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);
+
+	  Arm_address got_entry =
+	    target->got_plt_section()->address() + got_offset;
+
+          // Relocate the field with the PC relative offset of the GOT entry.
+	  RelocFuncs::pcrel32(view, got_entry, address);
 	  return ArmRelocFuncs::STATUS_OKAY;
         }
       break;
@@ -8324,8 +8728,13 @@ Target_arm<big_endian>::Relocate::reloca
       if (!parameters->options().shared())
         {
           gold_assert(tls_segment != NULL);
-          value = tls_segment->memsz() - value;
-          Relocate_functions<32, false>::rel32(view, value);
+
+	  // $tp points to the TCB, which is followed by the TLS, so we
+	  // need to add TCB size to the offset.
+	  Arm_address aligned_tcb_size =
+	    align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment());
+          RelocFuncs::rel32(view, value + aligned_tcb_size);
+
         }
       return ArmRelocFuncs::STATUS_OKAY;
     
@@ -10413,7 +10822,7 @@ Target_arm<big_endian>::fix_exidx_covera
       arm_output_section->append_text_sections_to_list(&sorted_text_sections);
     } 
 
-  exidx_section->fix_exidx_coverage(sorted_text_sections, symtab);
+  exidx_section->fix_exidx_coverage(layout, sorted_text_sections, symtab);
 }
 
 Target_selector_arm<false> target_selector_arm;
Index: gold/layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.165
diff -u -u -p -r1.165 layout.cc
--- gold/layout.cc	9 Feb 2010 20:29:44 -0000	1.165
+++ gold/layout.cc	24 Feb 2010 05:29:40 -0000
@@ -3569,9 +3569,9 @@ const Layout::Section_name_mapping Layou
   MAPPING_INIT(".gnu.linkonce.lr.", ".lrodata"),
   MAPPING_INIT(".gnu.linkonce.l.", ".ldata"),
   MAPPING_INIT(".gnu.linkonce.lb.", ".lbss"),
-  MAPPING_INIT(".ARM.extab.", ".ARM.extab"),
+  MAPPING_INIT(".ARM.extab", ".ARM.extab"),
   MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
-  MAPPING_INIT(".ARM.exidx.", ".ARM.exidx"),
+  MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
   MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
 };
 #undef MAPPING_INIT


More information about the Binutils mailing list