gdb/testsuite/
[binutils-gdb.git] / gold / merge.cc
index 1369938a557ae4cc5b37d5a208145cc0925d53b0..6e44ddd44711440aa3b385a0c8531ea80c00bb5a 100644 (file)
@@ -204,6 +204,12 @@ Object_merge_map::initialize_input_to_output_map(
   Input_merge_map* map = this->get_input_merge_map(shndx);
   gold_assert(map != NULL);
 
+  gold_assert(initialize_map->empty());
+  // We know how many entries we are going to add.
+  // reserve_unordered_map takes an expected count of buckets, not a
+  // count of elements, so double it to try to reduce collisions.
+  reserve_unordered_map(initialize_map, map->entries.size() * 2);
+
   for (Input_merge_map::Entries::const_iterator p = map->entries.begin();
        p != map->entries.end();
        ++p)
@@ -298,6 +304,26 @@ Output_merge_base::do_is_merge_section_for(const Relobj* object,
   return this->merge_map_.is_merge_section_for(object, shndx);
 }
 
+// Record a merged input section for script processing.
+
+void
+Output_merge_base::record_input_section(Relobj* relobj, unsigned int shndx)
+{
+  gold_assert(this->keeps_input_sections_ && relobj != NULL);
+  // If this is the first input section, record it.  We need do this because
+  // this->input_sections_ is unordered.
+  if (this->first_relobj_ == NULL)
+    {
+      this->first_relobj_ = relobj;
+      this->first_shndx_ = shndx;
+    }
+
+  std::pair<Input_sections::iterator, bool> result =
+    this->input_sections_.insert(Section_id(relobj, shndx));
+  // We should insert a merge section once only.
+  gold_assert(result.second);
+}
+
 // Class Output_merge_data.
 
 // Compute the hash code for a fixed-size constant.
@@ -408,6 +434,10 @@ Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx)
       this->add_mapping(object, shndx, i, entsize, k);
     }
 
+  // For script processing, we keep the input sections.
+  if (this->keeps_input_sections())
+    record_input_section(object, shndx);
+
   return true;
 }
 
@@ -419,7 +449,10 @@ Output_merge_data::set_final_data_size()
 {
   // Release the memory we don't need.
   this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->len_));
-  gold_assert(this->p_ != NULL);
+  // An Output_merge_data object may be empty and realloc is allowed
+  // to return a NULL pointer in this case.  An Output_merge_data is empty
+  // if all its input sections have sizes that are not multiples of entsize.
+  gold_assert(this->p_ != NULL || this->len_ == 0);
   this->set_data_size(this->len_);
 }
 
@@ -465,7 +498,7 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
   const unsigned char* pdata = object->section_contents(shndx, &len, false);
 
   const Char_type* p = reinterpret_cast<const Char_type*>(pdata);
-  const Char_type* pend = p + len;
+  const Char_type* pend = p + len / sizeof(Char_type);
 
   if (len % sizeof(Char_type) != 0)
     {
@@ -485,8 +518,10 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
        {
          if (pl >= pend)
            {
-             object->error(_("entry in mergeable string section "
-                             "not null terminated"));
+             gold_warning(_("%s: last entry in mergeable string section '%s' "
+                            "not null terminated"),
+                          object->name().c_str(),
+                          object->section_name(shndx).c_str());
              break;
            }
        }
@@ -506,6 +541,10 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
 
   this->input_count_ += count;
 
+  // For script processing, we keep the input sections.
+  if (this->keeps_input_sections())
+    record_input_section(object, shndx);
+
   return true;
 }