2010-07-13 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Tue, 13 Jul 2010 20:07:08 +0000 (20:07 +0000)
committerDoug Kwan <dougkwan@google.com>
Tue, 13 Jul 2010 20:07:08 +0000 (20:07 +0000)
* arm.cc (Arm_input_section::Arm_input_section): For a
SHT_ARM_EXIDX section, always keeps the input sections.
(Arm_input_section::set_exidx_section_link): New method.
(Arm_exidx_input_section::Arm_exidx_input_section): Initialize
has_errors_ to false.
(Arm_exidx_input_section::has_errors,
Arm_exidx_input_section::set_has_errors): New methods.
(Arm_exidx_input_section::has_errors_): New data member.
(Arm_relobj::get_exidx_shndx_list): New method.
(Arm_output_section::append_text_sections_to_list): Do not skip
section without SHF_EXECINSTR.
(Arm_output_section::fix_exidx_coverage): Skip input sections with
errors.
  (Arm_relobj::make_exidx_input_section): Add new parameter for text
section header.  Make error messages more verbose.  Check for
a non-executable section linked to an EXIDX section.
(Arm_relobj::do_read_symbols): Remove error checking, which has been
moved to Arm_relobj::make_exidx_input_section.  Add an assertion to
check that there is no deferred EXIDX section if we exit early.
Instead of not making an EXIDX section in case of an error, make one
and set the has_errors flag of it.
(Target_arm::do_finalize_sections): Fix up links of EXIDX sections
in a relocatable link.
(Target_arm::do_relax): Look for the EXIDX output section instead of
assuming that it is called .ARM.exidx.
  (Target_arm::fix_exidx_coverage): Add a new parameter for input
section list.  Do not check for SHF_EXECINSTR section flags but
skip any input section with errors.
* output.cc (Output_section::Output_section): Initialize
always_keeps_input_sections_ to false.
(Output_section::add_input_section): Check for
always_keeps_input_sections_.
*  output.h (Output_section::always_keeps_input_sections,
Output_section::set_always_keeps_input_sections): New methods.
(Output_section::always_keeps_input_sections): New data member.

gold/ChangeLog
gold/arm.cc
gold/output.cc
gold/output.h

index 6dbbced..4f5833b 100644 (file)
@@ -1,3 +1,41 @@
+2010-07-13  Doug Kwan  <dougkwan@google.com>
+
+       * arm.cc (Arm_input_section::Arm_input_section): For a
+       SHT_ARM_EXIDX section, always keeps the input sections.
+       (Arm_input_section::set_exidx_section_link): New method.
+       (Arm_exidx_input_section::Arm_exidx_input_section): Initialize
+       has_errors_ to false.
+       (Arm_exidx_input_section::has_errors,
+       Arm_exidx_input_section::set_has_errors): New methods.
+       (Arm_exidx_input_section::has_errors_): New data member.
+       (Arm_relobj::get_exidx_shndx_list): New method.
+       (Arm_output_section::append_text_sections_to_list): Do not skip
+       section without SHF_EXECINSTR.
+       (Arm_output_section::fix_exidx_coverage): Skip input sections with
+       errors.
+       (Arm_relobj::make_exidx_input_section): Add new parameter for text
+       section header.  Make error messages more verbose.  Check for
+       a non-executable section linked to an EXIDX section.
+       (Arm_relobj::do_read_symbols): Remove error checking, which has been
+       moved to Arm_relobj::make_exidx_input_section.  Add an assertion to
+       check that there is no deferred EXIDX section if we exit early.
+       Instead of not making an EXIDX section in case of an error, make one
+       and set the has_errors flag of it.
+       (Target_arm::do_finalize_sections): Fix up links of EXIDX sections
+       in a relocatable link.
+       (Target_arm::do_relax): Look for the EXIDX output section instead of
+       assuming that it is called .ARM.exidx.
+       (Target_arm::fix_exidx_coverage): Add a new parameter for input
+       section list.  Do not check for SHF_EXECINSTR section flags but
+       skip any input section with errors.
+       * output.cc (Output_section::Output_section): Initialize
+       always_keeps_input_sections_ to false.
+       (Output_section::add_input_section): Check for
+       always_keeps_input_sections_.
+       *  output.h (Output_section::always_keeps_input_sections,
+       Output_section::set_always_keeps_input_sections): New methods.
+       (Output_section::always_keeps_input_sections): New data member.
+
 2010-07-13  Rafael Espindola  <espindola@google.com>
 
        * fileread.cc (try_extra_search_path, find_file): Move to Input_file.
index ddfe543..aadac32 100644 (file)
@@ -1324,7 +1324,10 @@ class Arm_output_section : public Output_section
   Arm_output_section(const char* name, elfcpp::Elf_Word type,
                     elfcpp::Elf_Xword flags)
     : Output_section(name, type, flags)
-  { }
+  {
+    if (type == elfcpp::SHT_ARM_EXIDX)
+      this->set_always_keeps_input_sections();
+  }
 
   ~Arm_output_section()
   { }
@@ -1352,6 +1355,10 @@ class Arm_output_section : public Output_section
                     Symbol_table* symtab,
                     bool merge_exidx_entries);
 
+  // Link an EXIDX section into its corresponding text section.
+  void
+  set_exidx_section_link();
+
  private:
   // For convenience.
   typedef Output_section::Input_section Input_section;
@@ -1376,7 +1383,7 @@ class Arm_exidx_input_section
   Arm_exidx_input_section(Relobj* relobj, unsigned int shndx,
                          unsigned int link, uint32_t size, uint32_t addralign)
     : relobj_(relobj), shndx_(shndx), link_(link), size_(size),
-      addralign_(addralign)
+      addralign_(addralign), has_errors_(false)
   { }
 
   ~Arm_exidx_input_section()
@@ -1409,6 +1416,16 @@ class Arm_exidx_input_section
   addralign() const
   { return this->addralign_; }
 
+  // Whether there are any errors in the EXIDX input section.
+  bool
+  has_errors() const
+  { return this->has_errors_; }
+
+  // Set has-errors flag.
+  void
+  set_has_errors()
+  { this->has_errors_ = true; }
+
  private:
   // Object containing this.
   Relobj* relobj_;
@@ -1420,6 +1437,8 @@ class Arm_exidx_input_section
   uint32_t size_;
   // Address alignment of this.  For ARM 32-bit is sufficient.
   uint32_t addralign_;
+  // Whether this has any errors.
+  bool has_errors_;
 };
 
 // Arm_relobj class.
@@ -1581,6 +1600,22 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
   merge_flags_and_attributes() const
   { return this->merge_flags_and_attributes_; }
   
+  // Export list of EXIDX section indices.
+  void
+  get_exidx_shndx_list(std::vector<unsigned int>* list) const
+  {
+    list->clear();
+    for (Exidx_section_map::const_iterator p = this->exidx_section_map_.begin();
+        p != this->exidx_section_map_.end();
+        ++p)
+      {
+       if (p->second->shndx() == p->first)
+         list->push_back(p->first);
+      }
+    // Sort list to make result independent of implementation of map. 
+    std::sort(list->begin(), list->end());
+  }
+
  protected:
   // Post constructor setup.
   void
@@ -1653,7 +1688,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
   void
   make_exidx_input_section(unsigned int shndx,
                           const elfcpp::Shdr<32, big_endian>& shdr,
-                          unsigned int text_shndx);
+                          unsigned int text_shndx,
+                          const elfcpp::Shdr<32, big_endian>& text_shdr);
 
   // Return the output address of either a plain input section or a
   // relaxed input section.  SHNDX is the section index.
@@ -2764,7 +2800,8 @@ class Target_arm : public Sized_target<32, big_endian>
 
   // Fix .ARM.exidx section coverage.
   void
-  fix_exidx_coverage(Layout*, Arm_output_section<big_endian>*, Symbol_table*);
+  fix_exidx_coverage(Layout*, const Input_objects*,
+                    Arm_output_section<big_endian>*, Symbol_table*);
 
   // Functors for STL set.
   struct output_section_address_less_than
@@ -5655,10 +5692,6 @@ void
 Arm_output_section<big_endian>::append_text_sections_to_list(
     Text_section_list* list)
 {
-  // We only care about text sections.
-  if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0)
-    return;
-
   gold_assert((this->flags() & elfcpp::SHF_ALLOC) != 0);
 
   for (Input_section_list::const_iterator p = this->input_sections().begin();
@@ -5731,9 +5764,10 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
       const Arm_exidx_input_section* exidx_input_section =
         arm_relobj->exidx_input_section_by_link(shndx);
 
-      // If this text section has no EXIDX section, force an EXIDX_CANTUNWIND
-      // entry pointing to the end of the last seen EXIDX section.
-      if (exidx_input_section == NULL)
+      // If this text section has no EXIDX section or if the EXIDX section
+      // has errors, force an EXIDX_CANTUNWIND entry pointing to the end
+      // of the last seen EXIDX section.
+      if (exidx_input_section == NULL || exidx_input_section->has_errors())
        {
          exidx_fixup.add_exidx_cantunwind_as_needed();
          continue;
@@ -5817,15 +5851,20 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
       if (processed_input_sections.find(Section_id(p->relobj(), p->shndx()))
          == processed_input_sections.end())
        {
-         // We only discard a known EXIDX section because its linked
-         // text section has been folded by ICF.
+         // We discard a known EXIDX section because its linked
+         // text section has been folded by ICF.  We also discard an
+         // EXIDX section with error, the output does not matter in this
+         // case.  We do this to avoid triggering asserts.
          Arm_relobj<big_endian>* arm_relobj =
            Arm_relobj<big_endian>::as_arm_relobj(p->relobj());
          const Arm_exidx_input_section* exidx_input_section =
            arm_relobj->exidx_input_section_by_shndx(p->shndx());
          gold_assert(exidx_input_section != NULL);
-         unsigned int text_shndx = exidx_input_section->link();
-         gold_assert(symtab->is_section_folded(p->relobj(), text_shndx));
+         if (!exidx_input_section->has_errors())
+           {
+             unsigned int text_shndx = exidx_input_section->link();
+             gold_assert(symtab->is_section_folded(p->relobj(), text_shndx));
+           }
 
          // Remove this from link.  We also need to recount the
          // local symbols.
@@ -5844,6 +5883,28 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
   this->set_section_offsets_need_adjustment();
 }
 
+// Link EXIDX output sections to text output sections.
+
+template<bool big_endian>
+void
+Arm_output_section<big_endian>::set_exidx_section_link()
+{
+  gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX);
+  if (!this->input_sections().empty())
+    {
+      Input_section_list::const_iterator p = this->input_sections().begin();
+      Arm_relobj<big_endian>* arm_relobj =
+       Arm_relobj<big_endian>::as_arm_relobj(p->relobj());
+      unsigned exidx_shndx = p->shndx();
+      const Arm_exidx_input_section* exidx_input_section =
+       arm_relobj->exidx_input_section_by_shndx(exidx_shndx);
+      gold_assert(exidx_input_section != NULL);
+      unsigned int text_shndx = exidx_input_section->link();
+      Output_section* os = arm_relobj->output_section(text_shndx);
+      this->set_link_section(os);
+    }
+}
+
 // Arm_relobj methods.
 
 // Determine if an input section is scannable for stub processing.  SHDR is
@@ -6445,28 +6506,57 @@ void
 Arm_relobj<big_endian>::make_exidx_input_section(
     unsigned int shndx,
     const elfcpp::Shdr<32, big_endian>& shdr,
-    unsigned int text_shndx)
+    unsigned int text_shndx,
+    const elfcpp::Shdr<32, big_endian>& text_shdr)
 {
-  // Issue an error and ignore this EXIDX section if it points to a text
-  // section already has an EXIDX section.
-  if (this->exidx_section_map_[text_shndx] != NULL)
-    {
-      gold_error(_("EXIDX sections %u and %u both link to text section %u "
-                  "in %s"),
-                shndx, this->exidx_section_map_[text_shndx]->shndx(),
-                text_shndx, this->name().c_str());
-      return;
-    }
-
   // Create an Arm_exidx_input_section object for this EXIDX section.
   Arm_exidx_input_section* exidx_input_section =
     new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(),
                                shdr.get_sh_addralign());
-  this->exidx_section_map_[text_shndx] = exidx_input_section;
 
-  // Also map the EXIDX section index to this.
   gold_assert(this->exidx_section_map_[shndx] == NULL);
   this->exidx_section_map_[shndx] = exidx_input_section;
+
+  if (text_shndx == elfcpp::SHN_UNDEF || text_shndx >= this->shnum())
+    {
+      gold_error(_("EXIDX section %s(%u) links to invalid section %u in %s"),
+                this->section_name(shndx).c_str(), shndx, text_shndx,
+                this->name().c_str());
+      exidx_input_section->set_has_errors();
+    } 
+  else if (this->exidx_section_map_[text_shndx] != NULL)
+    {
+      unsigned other_exidx_shndx =
+       this->exidx_section_map_[text_shndx]->shndx();
+      gold_error(_("EXIDX sections %s(%u) and %s(%u) both link to text section"
+                  "%s(%u) in %s"),
+                this->section_name(shndx).c_str(), shndx,
+                this->section_name(other_exidx_shndx).c_str(),
+                other_exidx_shndx, this->section_name(text_shndx).c_str(),
+                text_shndx, this->name().c_str());
+      exidx_input_section->set_has_errors();
+    }
+  else
+     this->exidx_section_map_[text_shndx] = exidx_input_section;
+
+  // Check section flags of text section.
+  if ((text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+    {
+      gold_error(_("EXIDX section %s(%u) links to non-allocated section %s(%u) "
+                  " in %s"),
+                this->section_name(shndx).c_str(), shndx,
+                this->section_name(text_shndx).c_str(), text_shndx,
+                this->name().c_str());
+      exidx_input_section->set_has_errors();
+    }
+  else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0)
+    // I would like to make this an error but currenlty ld just ignores
+    // this.
+    gold_warning(_("EXIDX section %s(%u) links to non-executable section "
+                  "%s(%u) in %s"),
+                this->section_name(shndx).c_str(), shndx,
+                this->section_name(text_shndx).c_str(), text_shndx,
+                this->name().c_str());
 }
 
 // Read the symbol information.
@@ -6536,19 +6626,21 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
       else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX)
        {
          unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link());
-         if (text_shndx >= this->shnum())
-           gold_error(_("EXIDX section %u linked to invalid section %u"),
-                      i, text_shndx);
-         else if (text_shndx == elfcpp::SHN_UNDEF)
+         if (text_shndx == elfcpp::SHN_UNDEF)
            deferred_exidx_sections.push_back(i);
          else
-           this->make_exidx_input_section(i, shdr, text_shndx);
+           {
+             elfcpp::Shdr<32, big_endian> text_shdr(pshdrs
+                                                    + text_shndx * shdr_size);
+             this->make_exidx_input_section(i, shdr, text_shndx, text_shdr);
+           }
        }
     }
 
   // This is rare.
   if (!must_merge_flags_and_attributes)
     {
+      gold_assert(deferred_exidx_sections.empty());
       this->merge_flags_and_attributes_ = false;
       return;
     }
@@ -6604,15 +6696,14 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
        {
          unsigned int shndx = deferred_exidx_sections[i];
          elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size);
-         unsigned int text_shndx;
+         unsigned int text_shndx = elfcpp::SHN_UNDEF;
          Reloc_map::const_iterator it = reloc_map.find(shndx);
-         if (it != reloc_map.end()
-             && find_linked_text_section(pshdrs + it->second * shdr_size,
-                                         psyms, &text_shndx))
-           this->make_exidx_input_section(shndx, shdr, text_shndx);
-         else
-           gold_error(_("EXIDX section %u has no linked text section."),
-                      shndx);
+         if (it != reloc_map.end())
+           find_linked_text_section(pshdrs + it->second * shdr_size,
+                                    psyms, &text_shndx);
+         elfcpp::Shdr<32, big_endian> text_shdr(pshdrs
+                                                + text_shndx * shdr_size);
+         this->make_exidx_input_section(shndx, shdr, text_shndx, text_shdr);
        }
     }
 }
@@ -8306,6 +8397,17 @@ Target_arm<big_endian>::do_finalize_sections(
                                      attributes_section, false, false, false,
                                      false);
     }
+
+  // Fix up links in section EXIDX headers.
+  for (Layout::Section_list::const_iterator p = layout->section_list().begin();
+       p != layout->section_list().end();
+       ++p)
+    if ((*p)->type() == elfcpp::SHT_ARM_EXIDX)
+      {
+       Arm_output_section<big_endian>* os =
+         Arm_output_section<big_endian>::as_arm_output_section(*p);
+       os->set_exidx_section_link();
+      }
 }
 
 // Return whether a direct absolute static relocation needs to be applied.
@@ -10969,12 +11071,28 @@ Target_arm<big_endian>::do_relax(
       group_sections(layout, stub_group_size, stubs_always_after_branch);
      
       // Also fix .ARM.exidx section coverage.
-      Output_section* os = layout->find_output_section(".ARM.exidx");
-      if (os != NULL && os->type() == elfcpp::SHT_ARM_EXIDX)
+      Arm_output_section<big_endian>* exidx_output_section = NULL;
+      for (Layout::Section_list::const_iterator p =
+            layout->section_list().begin();
+          p != layout->section_list().end();
+          ++p)
+       if ((*p)->type() == elfcpp::SHT_ARM_EXIDX)
+         {
+           if (exidx_output_section == NULL)
+             exidx_output_section =
+               Arm_output_section<big_endian>::as_arm_output_section(*p);
+           else
+             // We cannot handle this now.
+             gold_error(_("multiple SHT_ARM_EXIDX sections %s and %s in a "
+                          "non-relocatable link"),
+                         exidx_output_section->name(),
+                         (*p)->name());
+         }
+
+      if (exidx_output_section != NULL)
        {
-         Arm_output_section<big_endian>* exidx_output_section =
-           Arm_output_section<big_endian>::as_arm_output_section(os);
-         this->fix_exidx_coverage(layout, exidx_output_section, symtab);
+         this->fix_exidx_coverage(layout, input_objects, exidx_output_section,
+                                  symtab);
          done_exidx_fixup = true;
        }
     }
@@ -11425,6 +11543,7 @@ template<bool big_endian>
 void
 Target_arm<big_endian>::fix_exidx_coverage(
     Layout* layout,
+    const Input_objects* input_objects,
     Arm_output_section<big_endian>* exidx_section,
     Symbol_table* symtab)
 {
@@ -11437,15 +11556,30 @@ Target_arm<big_endian>::fix_exidx_coverage(
   typedef std::set<Output_section*, output_section_address_less_than>
       Sorted_output_section_list;
   Sorted_output_section_list sorted_output_sections;
-  Layout::Section_list section_list;
-  layout->get_allocated_sections(&section_list);
-  for (Layout::Section_list::const_iterator p = section_list.begin();
-       p != section_list.end();
+
+  // Find out all the output sections of input sections pointed by
+  // EXIDX input sections.
+  for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+       p != input_objects->relobj_end();
        ++p)
     {
-      // We only care about output sections that contain executable code.
-      if (((*p)->flags() & elfcpp::SHF_EXECINSTR) != 0)
-       sorted_output_sections.insert(*p);
+      Arm_relobj<big_endian>* arm_relobj =
+       Arm_relobj<big_endian>::as_arm_relobj(*p);
+      std::vector<unsigned int> shndx_list;
+      arm_relobj->get_exidx_shndx_list(&shndx_list);
+      for (size_t i = 0; i < shndx_list.size(); ++i)
+       {
+         const Arm_exidx_input_section* exidx_input_section =
+           arm_relobj->exidx_input_section_by_shndx(shndx_list[i]);
+         gold_assert(exidx_input_section != NULL);
+         if (!exidx_input_section->has_errors())
+           {
+             unsigned int text_shndx = exidx_input_section->link();
+             Output_section *os = arm_relobj->output_section(text_shndx);
+             if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+               sorted_output_sections.insert(os);
+           }
+       }
     }
 
   // Go over the output sections in ascending order of output addresses.
index 3ac8a3d..a487eb8 100644 (file)
@@ -1949,6 +1949,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     is_entsize_zero_(false),
     section_offsets_need_adjustment_(false),
     is_noload_(false),
+    always_keeps_input_sections_(false),
     tls_offset_(0),
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps)
@@ -2038,8 +2039,10 @@ Output_section::add_input_section(Layout* layout,
     {
       // Keep information about merged input sections for rebuilding fast
       // lookup maps if we have sections-script or we do relaxation.
-      bool keeps_input_sections =
-       have_sections_script || parameters->target().may_relax();
+      bool keeps_input_sections = (this->always_keeps_input_sections_
+                                  || have_sections_script
+                                  || parameters->target().may_relax());
+
       if (this->add_merge_input_section(object, shndx, sh_flags, entsize,
                                        addralign, keeps_input_sections))
        {
@@ -2100,7 +2103,8 @@ Output_section::add_input_section(Layout* layout,
   // the future, we keep track of the sections.  If the
   // --section-ordering-file option is used to specify the order of
   // sections, we need to keep track of sections.
-  if (have_sections_script
+  if (this->always_keeps_input_sections_
+      || have_sections_script
       || !this->input_sections_.empty()
       || this->may_sort_attached_input_sections()
       || this->must_sort_attached_input_sections()
index 7355718..894773d 100644 (file)
@@ -3468,6 +3468,19 @@ class Output_section : public Output_data
   input_sections() const
   { return this->input_sections_; }
 
+  // Whether this always keeps an input section list
+  bool
+  always_keeps_input_sections() const
+  { return this->always_keeps_input_sections_; }
+
+  // Always keep an input section list.
+  void
+  set_always_keeps_input_sections()
+  {
+    gold_assert(this->current_data_size_for_child() == 0);
+    this->always_keeps_input_sections_ = true;
+  }
+
  private:
   // We only save enough information to undo the effects of section layout.
   class Checkpoint_output_section
@@ -3784,6 +3797,8 @@ class Output_section : public Output_data
   bool section_offsets_need_adjustment_ : 1;
   // Whether this is a NOLOAD section.
   bool is_noload_ : 1;
+  // Whether this always keeps input section.
+  bool always_keeps_input_sections_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;