* merge.h (Output_merge_string::Merged_string): Remove object, shndx,
[binutils-gdb.git] / gold / arm.cc
index d19d04c4bc25de52d934a254a9639bc765b0e8e1..aadac32dec937720a419171f5c5db290a8025037 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
@@ -4116,22 +4153,20 @@ Target_arm<big_endian>::got_section(Symbol_table* symtab, Layout* layout)
 
       this->got_ = new Arm_output_data_got<big_endian>(symtab, layout);
 
-      Output_section* os;
-      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-                                          (elfcpp::SHF_ALLOC
-                                           | elfcpp::SHF_WRITE),
-                                          this->got_, false, false, false,
-                                          true);
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_WRITE),
+                                     this->got_, false, false, false, true);
       // The old GNU linker creates a .got.plt section.  We just
       // create another set of data in the .got section.  Note that we
       // always create a PLT if we create a GOT, although the PLT
       // might be empty.
       this->got_plt_ = new Output_data_space(4, "** GOT PLT");
-      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-                                          (elfcpp::SHF_ALLOC
-                                           | elfcpp::SHF_WRITE),
-                                          this->got_plt_, false, false,
-                                          false, false);
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_WRITE),
+                                     this->got_plt_, false, false, false,
+                                     false);
 
       // The first three entries are reserved.
       this->got_plt_->set_current_data_size(3 * 4);
@@ -5657,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();
@@ -5733,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;
@@ -5819,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.
@@ -5846,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
@@ -6447,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.
@@ -6538,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;
     }
@@ -6606,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);
        }
     }
 }
@@ -8308,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.
@@ -8410,6 +8510,13 @@ Target_arm<big_endian>::Relocate::relocate(
              // be converted into an NOP.
              is_weakly_undefined_without_plt = true;
            }
+         else if (gsym->is_undefined() && reloc_property->uses_symbol())
+           {
+             // This relocation uses the symbol value but the symbol is
+             // undefined.  Exit early and have the caller reporting an
+             // error.
+             return true;
+           }
          else
            {
              // Set thumb bit if symbol:
@@ -10964,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;
        }
     }
@@ -11420,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)
 {
@@ -11432,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.