Combine read-only .eh_frame sections with read-write .eh_frame
authorIan Lance Taylor <iant@google.com>
Wed, 12 Mar 2008 04:38:42 +0000 (04:38 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 12 Mar 2008 04:38:42 +0000 (04:38 +0000)
sections.

gold/layout.cc
gold/layout.h
gold/object.cc
gold/output.cc
gold/output.h

index 6a47064a7007eff3bfa46b2eb989da477741672a..978828f16aad07d39d2d6f2667b84f79aee64c45 100644 (file)
@@ -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
index 1712db95ea4646c4f0fdb754c65b8a9f6fbda220..714c374e9c0f012291f23961598a0ab8aa7eba5c 100644 (file)
@@ -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);
index 98bcb62e802771767aa0ffa8ae1bc4719a3adb08..109dce49318a436118412b58d7334c07ec8a2eee 100644 (file)
@@ -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;
index 622e98378621ef0b7ae1d1e444c765aa0722b22d..044a035828aa42c973eb2ab4f1d67243f8d31c08 100644 (file)
@@ -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.
 
index a004515dc9a0b63e468b2c4d74c81ae6a2504281..3ce27f6a50216c7f0301f0189ec133b4ee2fc25f 100644 (file)
@@ -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