This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch][gold] Fix R_ARM_TLS_LE32 when there is no TLS segment


The attached patch fixes R_ARM_TLS_LE32 relocations when there is no TLS
segment. This can happen with linker scripts. I think the old code was
also wrong in the case we have a .tbss and a .tdata section. The relocations
would be correct for the section with the largest address, but not for the
other one.

2010-05-20  Rafael Espindola  <espindola@google.com>

	* arm.cc (relocated_section): New.
	(Target_arm<big_endian>::Relocate::relocate_tls): Use
	relocated_section and Layout::tls_section.
	* layout.cc (Layout::Layout): Initialize tls_section_.
	(Layout::compute_tls_section): New.
	* layout.h (Layout::tls_section, Layout::compute_tls_section,
	Layout::tls_section_): New.

(Cheers,
-- 
Rafael Ãvila de EspÃndola
diff --git a/gold/arm.cc b/gold/arm.cc
index 3dc2f22..d3aa60b 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -8679,6 +8679,23 @@ Target_arm<big_endian>::Relocate::relocate(
   return true;
 }
 
+template<bool big_endian>
+Output_section *
+relocated_section(const Relocate_info<32, big_endian>* relinfo,
+                  const elfcpp::Rel<32, big_endian>& rel,
+                  const Sized_symbol<32>* gsym)
+{
+  if (gsym)
+    return gsym->output_section();
+  unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+  const Symbol_value<32>* sym_val =
+      relinfo->object->local_symbol(r_sym);
+  bool is_ordinary;
+  unsigned int input_shndx = sym_val->input_shndx(&is_ordinary);
+  gold_assert(is_ordinary);
+  return relinfo->object->output_section(input_shndx);
+}
+
 // Perform a TLS relocation.
 
 template<bool big_endian>
@@ -8697,7 +8714,6 @@ Target_arm<big_endian>::Relocate::relocate_tls(
 {
   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;
 
@@ -8797,14 +8813,16 @@ Target_arm<big_endian>::Relocate::relocate_tls(
       // have been created for this location, so do not apply it now.
       if (!parameters->options().shared())
         {
-          gold_assert(tls_segment != NULL);
-
+          Output_section* tls_section = relinfo->layout->tls_section();
 	  // $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);
+	    align_address(ARM_TCB_SIZE, tls_section->addralign());
 
+	  Output_section *relocated_sec = relocated_section(relinfo, rel, gsym);
+	  Arm_address section_offset = tls_section->address() -
+              relocated_sec->address();
+	  RelocFuncs::rel32(view, section_offset + value + aligned_tcb_size);
         }
       return ArmRelocFuncs::STATUS_OKAY;
     
diff --git a/gold/layout.cc b/gold/layout.cc
index 36cfa8b..0c99ced 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -174,6 +174,7 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
     special_output_list_(),
     section_headers_(NULL),
     tls_segment_(NULL),
+    tls_section_(NULL),
     relro_segment_(NULL),
     increase_relro_(0),
     symtab_section_(NULL),
@@ -1524,6 +1525,30 @@ Layout::prepare_for_relaxation()
   this->record_output_section_data_from_script_ = true;
 }
 
+Output_section*
+Layout::compute_tls_section() const
+{
+  // Check that this method is used only once.
+  gold_assert(this->tls_section_ == NULL);
+
+  uint64_t align = 0;
+  Layout::Section_list list = this->section_list();
+  for (Section_list::iterator i = list.begin(); i != list.end(); ++i)
+  {
+    Output_section* sec = *i;
+    if (!(sec->flags() & elfcpp::SHF_TLS))
+      continue;
+    if (sec->addralign() > align)
+      align = sec->addralign();
+    if (this->tls_section_ == NULL ||
+        sec->address() > this->tls_section_->address())
+      this->tls_section_ = sec;
+  }
+  gold_assert(this->tls_section_);
+  gold_assert(this->tls_section_->addralign() == align);
+  return this->tls_section_;
+}
+
 // Relaxation loop body:  If target has no relaxation, this runs only once
 // Otherwise, the target relaxation hook is called at the end of
 // each iteration.  If the hook returns true, it means re-layout of
diff --git a/gold/layout.h b/gold/layout.h
index 912be31..6cde964 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -483,6 +483,16 @@ class Layout
   tls_segment() const
   { return this->tls_segment_; }
 
+  // Return the last TLS section. Asserts that there is one and that it
+  // is correctly aligned.
+  Output_section*
+  tls_section() const
+  {
+    if (this->tls_section_)
+      return this->tls_section_;
+    return this->compute_tls_section();
+  }
+
   // Return the normal symbol table.
   Output_section*
   symtab_section() const
@@ -867,6 +877,11 @@ class Layout
   void
   prepare_for_relaxation();
 
+  // Find the last TLS section. Asserts that there is one and that it
+  // is correctly aligned.
+  Output_section*
+  compute_tls_section() const;
+
   // Main body of the relaxation loop, which lays out the section.
   off_t
   relaxation_loop_body(int, Target*, Symbol_table*, Output_segment**,
@@ -968,6 +983,8 @@ class Layout
   Output_section_headers* section_headers_;
   // A pointer to the PT_TLS segment if there is one.
   Output_segment* tls_segment_;
+  // A cache pointer to the last SHF_TLS segction.
+  mutable Output_section* tls_section_;
   // A pointer to the PT_GNU_RELRO segment if there is one.
   Output_segment* relro_segment_;
   // A backend may increase the size of the PT_GNU_RELRO segment if

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]