From: Ian Lance Taylor Date: Wed, 12 Mar 2008 04:38:42 +0000 (+0000) Subject: Combine read-only .eh_frame sections with read-write .eh_frame X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1650c4ff500bc54eea33d31ae9396434a3e13733;p=binutils-gdb.git Combine read-only .eh_frame sections with read-write .eh_frame sections. --- diff --git a/gold/layout.cc b/gold/layout.cc index 6a47064a700..978828f16aa 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -520,7 +520,7 @@ Layout::layout_eh_frame(Sized_relobj* object, off_t* off) { gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS); - gold_assert(shdr.get_sh_flags() == elfcpp::SHF_ALLOC); + gold_assert((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0); const char* const name = ".eh_frame"; Output_section* os = this->choose_output_section(object, @@ -531,6 +531,16 @@ Layout::layout_eh_frame(Sized_relobj* object, if (os == NULL) return NULL; + // On some targets gcc assumes that a read-only .eh_frame section + // will be merged with a read-write .eh_frame section. + if ((shdr.get_sh_flags() & elfcpp::SHF_WRITE) != 0 + && (os->flags() & elfcpp::SHF_WRITE) == 0) + { + elfcpp::Elf_Xword new_flags = os->flags() | elfcpp::SHF_WRITE; + this->write_enable_output_section(os, new_flags); + os->set_flags(new_flags); + } + if (this->eh_frame_section_ == NULL) { this->eh_frame_section_ = os; @@ -778,6 +788,41 @@ Layout::allocate_output_section(Output_section* os, elfcpp::Elf_Xword flags) this->attach_to_segment(os, flags); } +// We have to move an existing output section from the read-only +// segment to the writable segment. + +void +Layout::write_enable_output_section(Output_section* os, + elfcpp::Elf_Xword flags) +{ + gold_assert((os->flags() & elfcpp::SHF_WRITE) == 0); + gold_assert(os->type() == elfcpp::SHT_PROGBITS); + gold_assert((flags & elfcpp::SHF_WRITE) != 0); + gold_assert((flags & elfcpp::SHF_ALLOC) != 0); + + if (parameters->options().relocatable()) + return; + + if (this->script_options_->saw_sections_clause()) + return; + + Segment_list::iterator p; + for (p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() == elfcpp::PT_LOAD + && ((*p)->flags() & elfcpp::PF_W) == 0) + { + (*p)->remove_output_section(os); + break; + } + } + gold_assert(p != this->segment_list_.end()); + + this->attach_to_segment(os, flags); +} + // Return the number of segments we expect to see. size_t diff --git a/gold/layout.h b/gold/layout.h index 1712db95ea4..714c374e9c0 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -477,6 +477,10 @@ class Layout void allocate_output_section(Output_section*, elfcpp::Elf_Xword flags); + // Turn a read-only output section into a read-write output section. + void + write_enable_output_section(Output_section*, elfcpp::Elf_Xword flags); + // Set the final file offsets of all the segments. off_t set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx); diff --git a/gold/object.cc b/gold/object.cc index 98bcb62e802..109dce49318 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -226,7 +226,7 @@ Sized_relobj::check_eh_frame_flags( { return (shdr->get_sh_size() > 0 && shdr->get_sh_type() == elfcpp::SHT_PROGBITS - && shdr->get_sh_flags() == elfcpp::SHF_ALLOC); + && (shdr->get_sh_flags() & elfcpp::SHF_ALLOC) != 0); } // Return whether there is a GNU .eh_frame section, given the section @@ -275,8 +275,11 @@ Sized_relobj::do_read_symbols(Read_symbols_data* sd) const unsigned char* namesu = sd->section_names->data(); const char* names = reinterpret_cast(namesu); - if (this->find_eh_frame(pshdrs, names, sd->section_names_size)) - this->has_eh_frame_ = true; + if (memmem(names, sd->section_names_size, ".eh_frame", 10) != NULL) + { + if (this->find_eh_frame(pshdrs, names, sd->section_names_size)) + this->has_eh_frame_ = true; + } sd->symbols = NULL; sd->symbols_size = 0; diff --git a/gold/output.cc b/gold/output.cc index 622e9837862..044a035828a 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -2376,6 +2376,27 @@ Output_segment::add_output_section(Output_section* os, pdl->push_back(os); } +// Remove an Output_section from this segment. It is an error if it +// is not present. + +void +Output_segment::remove_output_section(Output_section* os) +{ + // We only need this for SHT_PROGBITS. + gold_assert(os->type() == elfcpp::SHT_PROGBITS); + for (Output_data_list::iterator p = this->output_data_.begin(); + p != this->output_data_.end(); + ++p) + { + if (*p == os) + { + this->output_data_.erase(p); + return; + } + } + gold_unreachable(); +} + // Add an Output_data (which is not an Output_section) to the start of // a segment. diff --git a/gold/output.h b/gold/output.h index a004515dc9a..3ce27f6a502 100644 --- a/gold/output.h +++ b/gold/output.h @@ -1714,6 +1714,13 @@ class Output_section : public Output_data flags() const { return this->flags_; } + // Set the section flags. This may only be used with the Layout + // code when it is prepared to move the section to a different + // segment. + void + set_flags(elfcpp::Elf_Xword flags) + { this->flags_ = flags; } + // Return the entsize field. uint64_t entsize() const @@ -2523,6 +2530,11 @@ class Output_segment add_initial_output_section(Output_section* os, elfcpp::Elf_Word seg_flags) { this->add_output_section(os, seg_flags, true); } + // Remove an Output_section from this segment. It is an error if it + // is not present. + void + remove_output_section(Output_section* os); + // Add an Output_data (which is not an Output_section) to the start // of this segment. void