sections.
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,
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;
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
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);
{
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
const unsigned char* namesu = sd->section_names->data();
const char* names = reinterpret_cast<const char*>(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;
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.
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
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