diff --git a/gold/arm.cc b/gold/arm.cc index 3dc2f22..c937c36 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -6800,13 +6800,13 @@ Arm_output_data_got::do_write(Output_file* of) 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); + Output_section* tls_section = this->layout_->tls_section(); + gold_assert(tls_section != 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()); + align_address(ARM_TCB_SIZE, tls_section->addralign()); for (size_t i = 0; i < this->static_relocs_.size(); ++i) { @@ -8679,6 +8679,23 @@ Target_arm::Relocate::relocate( return true; } +template +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 @@ -8697,7 +8714,6 @@ Target_arm::Relocate::relocate_tls( { typedef Arm_relocate_functions 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::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 = relocated_sec->address() - + tls_section->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..ed842ce 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