This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch][gold] Fix R_ARM_TLS_LE32 when there is no TLS segment
- From: Rafael Espindola <espindola at google dot com>
- To: Binutils <binutils at sourceware dot org>
- Cc: Doug Kwan (éæå) <dougkwan at google dot com>, Ian Lance Taylor <iant at google dot com>
- Date: Thu, 20 May 2010 13:14:45 -0400
- Subject: [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