aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2008-03-12 04:38:42 +0000
committerIan Lance Taylor <iant@google.com>2008-03-12 04:38:42 +0000
commit1650c4ff500bc54eea33d31ae9396434a3e13733 (patch)
tree36c7a4a10c6005e8ab65e0afb8b9230d49a50c39
parente00eeb0a11ba17abc1166adb7f94097ae37c470c (diff)
downloadfsf-binutils-gdb-1650c4ff500bc54eea33d31ae9396434a3e13733.zip
fsf-binutils-gdb-1650c4ff500bc54eea33d31ae9396434a3e13733.tar.gz
fsf-binutils-gdb-1650c4ff500bc54eea33d31ae9396434a3e13733.tar.bz2
Combine read-only .eh_frame sections with read-write .eh_frame
sections.
-rw-r--r--gold/layout.cc47
-rw-r--r--gold/layout.h4
-rw-r--r--gold/object.cc9
-rw-r--r--gold/output.cc21
-rw-r--r--gold/output.h12
5 files changed, 89 insertions, 4 deletions
diff --git a/gold/layout.cc b/gold/layout.cc
index 6a47064..978828f 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -520,7 +520,7 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* 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<size, big_endian>* 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 1712db9..714c374 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 98bcb62..109dce4 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -226,7 +226,7 @@ Sized_relobj<size, big_endian>::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<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
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;
diff --git a/gold/output.cc b/gold/output.cc
index 622e983..044a035 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 a004515..3ce27f6 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