Add support for COMDAT groups during incremental update. 2011-04-04 Cary Coutant * incremental-dump.cc (dump_incremental_inputs): Print COMDAT groups. * incremental.cc (Incremental_inputs::report_input_section): Fix comment, indentation. (Incremental_inputs::report_comdat_group): New function. (Output_section_incremental_inputs::set_final_data_size): Adjust size of data for incremental input file entry. (Output_section_incremental_inputs::write_info_blocks): Write COMDAT group count, COMDAT group signatures. (Sized_incr_relobj::do_layout): Record kept COMDAT group info from an unchanged input file. * incremental.h (Incremental_object_entry::Incremental_object_entry): Initialize new data member. (Incremental_object_entry::add_comdat_group): New function. (Incremental_object_entry::get_comdat_group_count): New function. (Incremental_object_entry::get_comdat_signature_key): New function. (Incremental_object_entry::groups_): New data member. (Incremental_inputs::report_comdat_group): New function. (Incremental_input_entry_reader::get_symbol_offset): Adjust size of data for incremental input file entry. (Incremental_input_entry_reader::get_comdat_group_count): New function. (Incremental_input_entry_reader::get_input_section): Adjust size of data for incremental input file entry. (Incremental_input_entry_reader::get_global_symbol_reader): Likewise. (Incremental_input_entry_reader::get_comdat_group_signature): New function. * object.cc (Sized_relobj::include_section_group): Report kept COMDAT groups for incremental links. diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc index 1a3cce9..3e9bc0a 100644 --- a/gold/incremental-dump.cc +++ b/gold/incremental-dump.cc @@ -153,6 +153,8 @@ dump_incremental_inputs(const char* argv0, const char* filename, input_file.get_first_dyn_reloc()); printf(" Dynamic reloc count: %d\n", input_file.get_dyn_reloc_count()); + printf(" COMDAT group count: %d\n", + input_file.get_comdat_group_count()); break; case INCREMENTAL_INPUT_ARCHIVE: printf("Archive\n"); @@ -212,6 +214,11 @@ dump_incremental_inputs(const char* argv0, const char* filename, static_cast(info.sh_size), info.name); } + + unsigned int ncomdat = input_file.get_comdat_group_count(); + for (unsigned int i = 0; i < ncomdat; ++i) + printf(" Comdat group: %s\n", + input_file.get_comdat_group_signature(i)); } // Get a view of the .symtab section. diff --git a/gold/incremental.cc b/gold/incremental.cc index 817000e..072a1fb 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -1020,9 +1020,7 @@ Incremental_inputs::report_object(Object* obj, unsigned int arg_serial, } } -// Record the input object file OBJ. If ARCH is not NULL, attach -// the object file to the archive. This is called by the -// Add_symbols task after finding out the type of the file. +// Record an input section SHNDX from object file OBJ. void Incremental_inputs::report_input_section(Object* obj, unsigned int shndx, @@ -1031,13 +1029,27 @@ Incremental_inputs::report_input_section(Object* obj, unsigned int shndx, Stringpool::Key key = 0; if (name != NULL) - this->strtab_->add(name, true, &key); + this->strtab_->add(name, true, &key); gold_assert(obj == this->current_object_); gold_assert(this->current_object_entry_ != NULL); this->current_object_entry_->add_input_section(shndx, key, sh_size); } +// Record a kept COMDAT group belonging to object file OBJ. + +void +Incremental_inputs::report_comdat_group(Object* obj, const char* name) +{ + Stringpool::Key key = 0; + + if (name != NULL) + this->strtab_->add(name, true, &key); + gold_assert(obj == this->current_object_); + gold_assert(this->current_object_entry_ != NULL); + this->current_object_entry_->add_comdat_group(key); +} + // Record that the input argument INPUT is a script SCRIPT. This is // called by read_script after parsing the script and reading the list // of inputs added by this script. @@ -1165,14 +1177,17 @@ Output_section_incremental_inputs::set_final_data_size() gold_assert(entry != NULL); (*p)->set_info_offset(info_offset); // Input section count, global symbol count, local symbol offset, - // local symbol count, first dynamic reloc, dynamic reloc count. - info_offset += 24; + // local symbol count, first dynamic reloc, dynamic reloc count, + // comdat group count. + info_offset += 28; // Each input section. info_offset += (entry->get_input_section_count() * (8 + 2 * sizeof_addr)); // Each global symbol. const Object::Symbols* syms = entry->object()->get_global_symbols(); info_offset += syms->size() * 20; + // Each comdat group. + info_offset += entry->get_comdat_group_count() * 4; } break; case INCREMENTAL_INPUT_SHARED_LIBRARY: @@ -1416,13 +1431,15 @@ Output_section_incremental_inputs::write_info_blocks( unsigned int nlocals = relobj->output_local_symbol_count(); unsigned int first_dynrel = relobj->first_dyn_reloc(); unsigned int ndynrel = relobj->dyn_reloc_count(); + unsigned int ncomdat = entry->get_comdat_group_count(); Swap32::writeval(pov, nsections); Swap32::writeval(pov + 4, nsyms); Swap32::writeval(pov + 8, static_cast(locals_offset)); Swap32::writeval(pov + 12, nlocals); Swap32::writeval(pov + 16, first_dynrel); Swap32::writeval(pov + 20, ndynrel); - pov += 24; + Swap32::writeval(pov + 24, ncomdat); + pov += 28; // Build a temporary array to map input section indexes // from the original object file index to the index in the @@ -1499,6 +1516,17 @@ Output_section_incremental_inputs::write_info_blocks( pov += 20; } + // For each kept COMDAT group, write the group signature. + for (unsigned int i = 0; i < ncomdat; i++) + { + Stringpool::Key key = entry->get_comdat_signature_key(i); + off_t name_offset = 0; + if (key != 0) + name_offset = strtab->get_offset_from_key(key); + Swap32::writeval(pov, name_offset); + pov += 4; + } + delete[] index_map; } break; @@ -1854,6 +1882,20 @@ Sized_incr_relobj::do_layout( out_sections[i] = os; this->section_offsets()[i] = static_cast
(sect.sh_offset); } + + // Process the COMDAT groups. + unsigned int ncomdat = this->input_reader_.get_comdat_group_count(); + for (unsigned int i = 0; i < ncomdat; i++) + { + const char* signature = this->input_reader_.get_comdat_group_signature(i); + if (signature == NULL || signature[0] == '\0') + this->error(_("COMDAT group has no signature")); + bool keep = layout->find_or_add_kept_section(signature, this, i, true, + true, NULL); + if (!keep) + this->error(_("COMDAT group %s included twice in incremental link"), + signature); + } } // Layout sections whose layout was deferred while waiting for diff --git a/gold/incremental.h b/gold/incremental.h index afa0dd5..998e69e 100644 --- a/gold/incremental.h +++ b/gold/incremental.h @@ -325,7 +325,7 @@ class Incremental_object_entry : public Incremental_input_entry Incremental_object_entry(Stringpool::Key filename_key, Object* obj, unsigned int arg_serial, Timespec mtime) : Incremental_input_entry(filename_key, arg_serial, mtime), obj_(obj), - is_member_(false), sections_() + is_member_(false), sections_(), groups_() { this->sections_.reserve(obj->shnum()); } // Get the object. @@ -368,6 +368,21 @@ class Incremental_object_entry : public Incremental_input_entry get_input_section_size(unsigned int n) const { return this->sections_[n].sh_size_; } + // Add a kept COMDAT group. + void + add_comdat_group(Stringpool::Key signature_key) + { this->groups_.push_back(signature_key); } + + // Return the number of COMDAT groups. + unsigned int + get_comdat_group_count() const + { return this->groups_.size(); } + + // Return the stringpool key for the signature of the Nth comdat group. + Stringpool::Key + get_comdat_signature_key(unsigned int n) const + { return this->groups_[n]; } + protected: virtual Incremental_input_type do_type() const @@ -400,6 +415,9 @@ class Incremental_object_entry : public Incremental_input_entry off_t sh_size_; }; std::vector sections_; + + // COMDAT groups. + std::vector groups_; }; // Class for recording shared library input files. @@ -546,6 +564,10 @@ class Incremental_inputs report_input_section(Object* obj, unsigned int shndx, const char* name, off_t sh_size); + // Record a kept COMDAT group belonging to object file OBJ. + void + report_comdat_group(Object* obj, const char* name); + // Record the info for input script SCRIPT. void report_script(Script_info* script, unsigned int arg_serial, @@ -814,7 +836,7 @@ class Incremental_inputs_reader || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); unsigned int section_count = this->get_input_section_count(); - return (this->info_offset_ + 24 + return (this->info_offset_ + 28 + section_count * input_section_entry_size + symndx * 20); } @@ -869,6 +891,16 @@ class Incremental_inputs_reader return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 20); } + // Return the COMDAT group count -- for objects only. + unsigned int + get_comdat_group_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 24); + } + // Return the object count -- for scripts only. unsigned int get_object_count() const @@ -939,7 +971,7 @@ class Incremental_inputs_reader { Input_section_info info; const unsigned char* p = (this->inputs_->p_ - + this->info_offset_ + 24 + + this->info_offset_ + 28 + n * input_section_entry_size); unsigned int name_offset = Swap32::readval(p); info.name = this->inputs_->get_string(name_offset); @@ -957,12 +989,27 @@ class Incremental_inputs_reader || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); unsigned int section_count = this->get_input_section_count(); const unsigned char* p = (this->inputs_->p_ - + this->info_offset_ + 24 + + this->info_offset_ + 28 + section_count * input_section_entry_size + n * 20); return Incremental_global_symbol_reader(p); } + // Return the signature of the Nth comdat group -- for objects only. + const char* + get_comdat_group_signature(unsigned int n) const + { + unsigned int section_count = this->get_input_section_count(); + unsigned int symbol_count = this->get_global_symbol_count(); + const unsigned char* p = (this->inputs_->p_ + + this->info_offset_ + 28 + + section_count * input_section_entry_size + + symbol_count * 20 + + n * 4); + unsigned int name_offset = Swap32::readval(p); + return this->inputs_->get_string(name_offset); + } + // Return the output symbol index for the Nth global symbol -- for shared // libraries only. Sets *IS_DEF to TRUE if the symbol is defined in this // input file. diff --git a/gold/object.cc b/gold/object.cc index be080c2..3d26f17 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -825,6 +825,13 @@ Sized_relobj::include_section_group( is_comdat = true; } + if (is_comdat && include_group) + { + Incremental_inputs* incremental_inputs = layout->incremental_inputs(); + if (incremental_inputs != NULL) + incremental_inputs->report_comdat_group(this, signature.c_str()); + } + size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word); std::vector shndxes;