diff options
Diffstat (limited to 'gold/incremental.cc')
-rw-r--r-- | gold/incremental.cc | 786 |
1 files changed, 601 insertions, 185 deletions
diff --git a/gold/incremental.cc b/gold/incremental.cc index 01be470..b279c72 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -1,6 +1,6 @@ // inremental.cc -- incremental linking support for gold -// Copyright 2009 Free Software Foundation, Inc. +// Copyright 2009, 2010 Free Software Foundation, Inc. // Written by Mikolaj Zalewski <mikolajz@google.com>. // This file is part of gold. @@ -27,6 +27,7 @@ #include "elfcpp.h" #include "output.h" +#include "symtab.h" #include "incremental.h" #include "archive.h" #include "output.h" @@ -38,6 +39,73 @@ namespace gold { // we could think about backward (and forward?) compatibility. const unsigned int INCREMENTAL_LINK_VERSION = 1; +// This class manages the .gnu_incremental_inputs section, which holds +// the header information, a directory of input files, and separate +// entries for each input file. + +template<int size, bool big_endian> +class Output_section_incremental_inputs : public Output_section_data +{ + public: + Output_section_incremental_inputs(const Incremental_inputs* inputs, + const Symbol_table* symtab) + : Output_section_data(size / 8), inputs_(inputs), symtab_(symtab) + { } + + protected: + // Set the final data size. + void + set_final_data_size(); + + // Write the data to the file. + void + do_write(Output_file*); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** incremental_inputs")); } + + private: + // Write the section header. + unsigned char* + write_header(unsigned char* pov, unsigned int input_file_count, + section_offset_type command_line_offset); + + // Write the input file entries. + unsigned char* + write_input_files(unsigned char* oview, unsigned char* pov, + Stringpool* strtab); + + // Write the supplemental information blocks. + unsigned char* + write_info_blocks(unsigned char* oview, unsigned char* pov, + Stringpool* strtab, unsigned int* global_syms, + unsigned int global_sym_count); + + // Write the contents of the .gnu_incremental_symtab section. + void + write_symtab(unsigned char* pov, unsigned int* global_syms, + unsigned int global_sym_count); + + // Typedefs for writing the data to the output sections. + typedef elfcpp::Swap<size, big_endian> Swap; + typedef elfcpp::Swap<16, big_endian> Swap16; + typedef elfcpp::Swap<32, big_endian> Swap32; + typedef elfcpp::Swap<64, big_endian> Swap64; + + // Sizes of various structures. + static const int sizeof_addr = size / 8; + static const int header_size = 16; + static const int input_entry_size = 24; + + // The Incremental_inputs object. + const Incremental_inputs* inputs_; + + // The symbol table. + const Symbol_table* symtab_; +}; + // Inform the user why we don't do an incremental link. Not called in // the obvious case of missing output file. TODO: Is this helpful? @@ -77,77 +145,101 @@ Incremental_binary::error(const char* format, ...) const va_end(args); } +// Find the .gnu_incremental_inputs section and related sections. + template<int size, bool big_endian> bool -Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section( - Location* location, - unsigned int* strtab_shndx) +Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_sections( + unsigned int* p_inputs_shndx, + unsigned int* p_symtab_shndx, + unsigned int* p_relocs_shndx, + unsigned int* p_strtab_shndx) { - unsigned int shndx = this->elf_file_.find_section_by_type( - elfcpp::SHT_GNU_INCREMENTAL_INPUTS); - if (shndx == elfcpp::SHN_UNDEF) // Not found. + unsigned int inputs_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_INPUTS); + if (inputs_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + + unsigned int symtab_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_SYMTAB); + if (symtab_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + if (this->elf_file_.section_link(symtab_shndx) != inputs_shndx) return false; - *strtab_shndx = this->elf_file_.section_link(shndx); - *location = this->elf_file_.section_contents(shndx); + + unsigned int relocs_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_RELOCS); + if (relocs_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + if (this->elf_file_.section_link(relocs_shndx) != inputs_shndx) + return false; + + unsigned int strtab_shndx = this->elf_file_.section_link(inputs_shndx); + if (strtab_shndx == elfcpp::SHN_UNDEF + || strtab_shndx > this->elf_file_.shnum() + || this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB) + return false; + + if (p_inputs_shndx != NULL) + *p_inputs_shndx = inputs_shndx; + if (p_symtab_shndx != NULL) + *p_symtab_shndx = symtab_shndx; + if (p_relocs_shndx != NULL) + *p_relocs_shndx = relocs_shndx; + if (p_strtab_shndx != NULL) + *p_strtab_shndx = strtab_shndx; return true; } +// Determine whether an incremental link based on the existing output file +// can be done. + template<int size, bool big_endian> bool Sized_incremental_binary<size, big_endian>::do_check_inputs( Incremental_inputs* incremental_inputs) { - const int entry_size = - Incremental_inputs_entry_write<size, big_endian>::data_size; - const int header_size = - Incremental_inputs_header_write<size, big_endian>::data_size; - + unsigned int inputs_shndx; + unsigned int symtab_shndx; + unsigned int relocs_shndx; unsigned int strtab_shndx; - Location location; - if (!do_find_incremental_inputs_section(&location, &strtab_shndx)) + if (!do_find_incremental_inputs_sections(&inputs_shndx, &symtab_shndx, + &relocs_shndx, &strtab_shndx)) { explain_no_incremental(_("no incremental data from previous build")); return false; } - if (location.data_size < header_size - || strtab_shndx >= this->elf_file_.shnum() - || this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB) - { - explain_no_incremental(_("invalid incremental build data")); - return false; - } + Location inputs_location(this->elf_file_.section_contents(inputs_shndx)); + Location symtab_location(this->elf_file_.section_contents(symtab_shndx)); + Location relocs_location(this->elf_file_.section_contents(relocs_shndx)); Location strtab_location(this->elf_file_.section_contents(strtab_shndx)); - View data_view(view(location)); + + View inputs_view(view(inputs_location)); + View symtab_view(view(symtab_location)); + View relocs_view(view(relocs_location)); View strtab_view(view(strtab_location)); + elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size); - Incremental_inputs_header<size, big_endian> header(data_view.data()); - if (header.get_version() != INCREMENTAL_LINK_VERSION) - { - explain_no_incremental(_("different version of incremental build data")); - return false; - } + Incremental_inputs_reader<size, big_endian> + incoming_inputs(inputs_view.data(), strtab); - const char* command_line; - // We divide instead of multiplying to make sure there is no integer - // overflow. - size_t max_input_entries = (location.data_size - header_size) / entry_size; - if (header.get_input_file_count() > max_input_entries - || !strtab.get_c_string(header.get_command_line_offset(), &command_line)) + if (incoming_inputs.version() != INCREMENTAL_LINK_VERSION) { - explain_no_incremental(_("invalid incremental build data")); + explain_no_incremental(_("different version of incremental build data")); return false; } - if (incremental_inputs->command_line() != command_line) + if (incremental_inputs->command_line() != incoming_inputs.command_line()) { explain_no_incremental(_("command line changed")); return false; } // TODO: compare incremental_inputs->inputs() with entries in data_view. + return true; } @@ -182,8 +274,8 @@ make_sized_incremental_binary(Output_file* file, } // End of anonymous namespace. -// Create an Incremental_binary object for FILE. Returns NULL is this is not -// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE +// Create an Incremental_binary object for FILE. Returns NULL is this is not +// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE // should be opened. Incremental_binary* @@ -275,6 +367,8 @@ Incremental_checker::can_incrementally_link_output_file() return binary->check_inputs(this->incremental_inputs_); } +// Class Incremental_inputs. + // Add the command line to the string table, setting // command_line_key_. In incremental builds, the command line is // stored in .gnu_incremental_inputs so that the next linker run can @@ -289,7 +383,7 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv) // Copied from collect_argv in main.cc. for (int i = 1; i < argc; ++i) { - // Adding/removing these options should result in a full relink. + // Adding/removing these options should not result in a full relink. if (strcmp(argv[i], "--incremental-changed") == 0 || strcmp(argv[i], "--incremental-unchanged") == 0 || strcmp(argv[i], "--incremental-unknown") == 0) @@ -315,99 +409,104 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv) &this->command_line_key_); } -// Record that the input argument INPUT is an achive ARCHIVE. This is -// called by Read_symbols after finding out the type of the file. +// Record the input archive file ARCHIVE. This is called by the +// Add_archive_symbols task before determining which archive members +// to include. We create the Incremental_archive_entry here and +// attach it to the Archive, but we do not add it to the list of +// input objects until report_archive_end is called. void -Incremental_inputs::report_archive(const Input_argument* input, - Archive* archive) +Incremental_inputs::report_archive_begin(Archive* arch) { - Hold_lock hl(*this->lock_); + Stringpool::Key filename_key; + Timespec mtime = arch->file().get_mtime(); - Input_info info; - info.type = INCREMENTAL_INPUT_ARCHIVE; - info.archive = archive; - info.mtime = archive->file().get_mtime(); - this->inputs_map_.insert(std::make_pair(input, info)); + this->strtab_->add(arch->filename().c_str(), false, &filename_key); + Incremental_archive_entry* entry = + new Incremental_archive_entry(filename_key, arch, mtime); + arch->set_incremental_info(entry); } -// Record that the input argument INPUT is an object OBJ. This is -// called by Read_symbols after finding out the type of the file. +// Finish recording the input archive file ARCHIVE. This is called by the +// Add_archive_symbols task after determining which archive members +// to include. void -Incremental_inputs::report_object(const Input_argument* input, - Object* obj) +Incremental_inputs::report_archive_end(Archive* arch) { - Hold_lock hl(*this->lock_); - - Input_info info; - info.type = (obj->is_dynamic() - ? INCREMENTAL_INPUT_SHARED_LIBRARY - : INCREMENTAL_INPUT_OBJECT); - info.object = obj; - info.mtime = obj->input_file()->file().get_mtime(); - this->inputs_map_.insert(std::make_pair(input, info)); + Incremental_archive_entry* entry = arch->incremental_info(); + + gold_assert(entry != NULL); + + // Collect unused global symbols. + for (Archive::Unused_symbol_iterator p = arch->unused_symbols_begin(); + p != arch->unused_symbols_end(); + ++p) + { + Stringpool::Key symbol_key; + this->strtab_->add(*p, true, &symbol_key); + entry->add_unused_global_symbol(symbol_key); + } + this->inputs_.push_back(entry); } -// Record that the input argument INPUT is an script SCRIPT. This is -// called by read_script after parsing the script and reading the list -// of inputs added by this script. +// 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. void -Incremental_inputs::report_script(const Input_argument* input, - Timespec mtime, - Script_info* script) +Incremental_inputs::report_object(Object* obj, Archive* arch) { - Hold_lock hl(*this->lock_); + Stringpool::Key filename_key; + Timespec mtime = obj->input_file()->file().get_mtime(); + + this->strtab_->add(obj->name().c_str(), false, &filename_key); + Incremental_object_entry* obj_entry = + new Incremental_object_entry(filename_key, obj, mtime); + this->inputs_.push_back(obj_entry); - Input_info info; - info.type = INCREMENTAL_INPUT_SCRIPT; - info.script = script; - info.mtime = mtime; - this->inputs_map_.insert(std::make_pair(input, info)); + if (arch != NULL) + { + Incremental_archive_entry* arch_entry = arch->incremental_info(); + gold_assert(arch_entry != NULL); + arch_entry->add_object(obj_entry); + } + + this->current_object_ = obj; + this->current_object_entry_ = obj_entry; } -// Compute indexes in the order in which the inputs should appear in -// .gnu_incremental_inputs. This needs to be done after all the -// scripts are parsed. The function is first called for the command -// line inputs arguments and may call itself recursively for e.g. a -// list of elements of a group or a list of inputs added by a script. -// The [BEGIN; END) interval to analyze and *INDEX is the current -// value of the index (that will be updated). +// 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. void -Incremental_inputs::finalize_inputs( - Input_argument_list::const_iterator begin, - Input_argument_list::const_iterator end, - unsigned int* index) +Incremental_inputs::report_input_section(Object* obj, unsigned int shndx, + const char* name, off_t sh_size) { - for (Input_argument_list::const_iterator p = begin; p != end; ++p) - { - if (p->is_group()) - { - finalize_inputs(p->group()->begin(), p->group()->end(), index); - continue; - } + Stringpool::Key key = 0; - Inputs_info_map::iterator it = this->inputs_map_.find(&(*p)); - // TODO: turn it into an assert when the code will be more stable. - if (it == this->inputs_map_.end()) - { - gold_error("internal error: %s: incremental build info not provided", - (p->is_file() ? p->file().name() : "[group]")); - continue; - } - Input_info* info = &it->second; - info->index = *index; - (*index)++; - this->strtab_->add(p->file().name(), false, &info->filename_key); - if (info->type == INCREMENTAL_INPUT_SCRIPT) - { - finalize_inputs(info->script->inputs()->begin(), - info->script->inputs()->end(), - index); - } - } + if (name != NULL) + this->strtab_->add(name, true, &key); + + gold_assert(obj == this->current_object_); + this->current_object_entry_->add_input_section(shndx, key, sh_size); +} + +// 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. + +void +Incremental_inputs::report_script(const std::string& filename, + Script_info* script, Timespec mtime) +{ + Stringpool::Key filename_key; + + this->strtab_->add(filename.c_str(), false, &filename_key); + Incremental_script_entry* entry = + new Incremental_script_entry(filename_key, script, mtime); + this->inputs_.push_back(entry); } // Finalize the incremental link information. Called from @@ -416,108 +515,425 @@ Incremental_inputs::finalize_inputs( void Incremental_inputs::finalize() { - unsigned int index = 0; - finalize_inputs(this->inputs_->begin(), this->inputs_->end(), &index); - - // Sanity check. - for (Inputs_info_map::const_iterator p = this->inputs_map_.begin(); - p != this->inputs_map_.end(); - ++p) - { - gold_assert(p->second.filename_key != 0); - } - + // Finalize the string table. this->strtab_->set_string_offsets(); } -// Create the content of the .gnu_incremental_inputs section. +// Create the .gnu_incremental_inputs, _symtab, and _relocs input sections. -Output_section_data* -Incremental_inputs::create_incremental_inputs_section_data() +void +Incremental_inputs::create_data_sections(Symbol_table* symtab) { switch (parameters->size_and_endianness()) { #ifdef HAVE_TARGET_32_LITTLE case Parameters::TARGET_32_LITTLE: - return this->sized_create_inputs_section_data<32, false>(); + this->inputs_section_ = + new Output_section_incremental_inputs<32, false>(this, symtab); + break; #endif #ifdef HAVE_TARGET_32_BIG case Parameters::TARGET_32_BIG: - return this->sized_create_inputs_section_data<32, true>(); + this->inputs_section_ = + new Output_section_incremental_inputs<32, true>(this, symtab); + break; #endif #ifdef HAVE_TARGET_64_LITTLE case Parameters::TARGET_64_LITTLE: - return this->sized_create_inputs_section_data<64, false>(); + this->inputs_section_ = + new Output_section_incremental_inputs<64, false>(this, symtab); + break; #endif #ifdef HAVE_TARGET_64_BIG case Parameters::TARGET_64_BIG: - return this->sized_create_inputs_section_data<64, true>(); + this->inputs_section_ = + new Output_section_incremental_inputs<64, true>(this, symtab); + break; #endif default: gold_unreachable(); } + this->symtab_section_ = new Output_data_space(4, "** incremental_symtab"); + this->relocs_section_ = new Output_data_space(4, "** incremental_relocs"); } -// Sized creation of .gnu_incremental_inputs section. +// Return the sh_entsize value for the .gnu_incremental_relocs section. +unsigned int +Incremental_inputs::relocs_entsize() const +{ + return 8 + 2 * parameters->target().get_size() / 8; +} + +// Class Output_section_incremental_inputs. + +// Finalize the offsets for each input section and supplemental info block, +// and set the final data size of the incremental output sections. template<int size, bool big_endian> -Output_section_data* -Incremental_inputs::sized_create_inputs_section_data() +void +Output_section_incremental_inputs<size, big_endian>::set_final_data_size() { - const int entry_size = - Incremental_inputs_entry_write<size, big_endian>::data_size; - const int header_size = - Incremental_inputs_header_write<size, big_endian>::data_size; - - unsigned int sz = header_size + entry_size * this->inputs_map_.size(); - unsigned char* buffer = new unsigned char[sz]; - unsigned char* inputs_base = buffer + header_size; - - Incremental_inputs_header_write<size, big_endian> header_writer(buffer); - gold_assert(this->command_line_key_ > 0); - int cmd_offset = this->strtab_->get_offset_from_key(this->command_line_key_); - - header_writer.put_version(INCREMENTAL_LINK_VERSION); - header_writer.put_input_file_count(this->inputs_map_.size()); - header_writer.put_command_line_offset(cmd_offset); - header_writer.put_reserved(0); - - for (Inputs_info_map::const_iterator it = this->inputs_map_.begin(); - it != this->inputs_map_.end(); - ++it) + const Incremental_inputs* inputs = this->inputs_; + const unsigned int sizeof_addr = size / 8; + const unsigned int rel_size = 8 + 2 * sizeof_addr; + + // Offset of each input entry. + unsigned int input_offset = this->header_size; + + // Offset of each supplemental info block. + unsigned int info_offset = this->header_size; + info_offset += this->input_entry_size * inputs->input_file_count(); + + // Count each input file and its supplemental information block. + for (Incremental_inputs::Input_list::const_iterator p = + inputs->input_files().begin(); + p != inputs->input_files().end(); + ++p) { - gold_assert(it->second.index < this->inputs_map_.size()); - - unsigned char* entry_buffer = - inputs_base + it->second.index * entry_size; - Incremental_inputs_entry_write<size, big_endian> entry(entry_buffer); - int filename_offset = - this->strtab_->get_offset_from_key(it->second.filename_key); - entry.put_filename_offset(filename_offset); - switch (it->second.type) - { - case INCREMENTAL_INPUT_SCRIPT: - entry.put_data_offset(0); - break; - case INCREMENTAL_INPUT_ARCHIVE: - case INCREMENTAL_INPUT_OBJECT: - case INCREMENTAL_INPUT_SHARED_LIBRARY: - // TODO: add per input data. Currently we store - // an out-of-bounds offset for future version of gold to reject - // such an incremental_inputs section. - entry.put_data_offset(0xffffffff); - break; - default: - gold_unreachable(); - } - entry.put_timestamp_sec(it->second.mtime.seconds); - entry.put_timestamp_nsec(it->second.mtime.nanoseconds); - entry.put_input_type(it->second.type); - entry.put_reserved(0); + // Set the offset of the input file entry. + (*p)->set_offset(input_offset); + input_offset += this->input_entry_size; + + // Set the offset of the supplemental info block. + switch ((*p)->type()) + { + case INCREMENTAL_INPUT_SCRIPT: + // No supplemental info for a script. + (*p)->set_info_offset(0); + break; + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + { + Incremental_object_entry *entry = (*p)->object_entry(); + gold_assert(entry != NULL); + (*p)->set_info_offset(info_offset); + // Input section count + global symbol count. + info_offset += 8; + // 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() * 16; + } + break; + case INCREMENTAL_INPUT_SHARED_LIBRARY: + { + Incremental_object_entry *entry = (*p)->object_entry(); + gold_assert(entry != NULL); + (*p)->set_info_offset(info_offset); + // Global symbol count. + info_offset += 4; + // Each global symbol. + const Object::Symbols* syms = entry->object()->get_global_symbols(); + unsigned int nsyms = syms != NULL ? syms->size() : 0; + info_offset += nsyms * 4; + } + break; + case INCREMENTAL_INPUT_ARCHIVE: + { + Incremental_archive_entry *entry = (*p)->archive_entry(); + gold_assert(entry != NULL); + (*p)->set_info_offset(info_offset); + // Member count + unused global symbol count. + info_offset += 8; + // Each member. + info_offset += (entry->get_member_count() * 4); + // Each global symbol. + info_offset += (entry->get_unused_global_symbol_count() * 4); + } + break; + default: + gold_unreachable(); + } } - return new Output_data_const_buffer(buffer, sz, 8, - "** incremental link inputs list"); + this->set_data_size(info_offset); + + // Set the size of the .gnu_incremental_symtab section. + inputs->symtab_section()->set_current_data_size(this->symtab_->output_count() + * sizeof(unsigned int)); + + // Set the size of the .gnu_incremental_relocs section. + inputs->relocs_section()->set_current_data_size(inputs->get_reloc_count() + * rel_size); +} + +// Write the contents of the .gnu_incremental_inputs and +// .gnu_incremental_symtab sections. + +template<int size, bool big_endian> +void +Output_section_incremental_inputs<size, big_endian>::do_write(Output_file* of) +{ + const Incremental_inputs* inputs = this->inputs_; + Stringpool* strtab = inputs->get_stringpool(); + + // Get a view into the .gnu_incremental_inputs section. + const off_t off = this->offset(); + const off_t oview_size = this->data_size(); + unsigned char* const oview = of->get_output_view(off, oview_size); + unsigned char* pov = oview; + + // Get a view into the .gnu_incremental_symtab section. + const off_t symtab_off = inputs->symtab_section()->offset(); + const off_t symtab_size = inputs->symtab_section()->data_size(); + unsigned char* const symtab_view = of->get_output_view(symtab_off, + symtab_size); + + // Allocate an array of linked list heads for the .gnu_incremental_symtab + // section. Each element corresponds to a global symbol in the output + // symbol table, and points to the head of the linked list that threads + // through the object file input entries. The value of each element + // is the section-relative offset to a global symbol entry in a + // supplemental information block. + unsigned int global_sym_count = this->symtab_->output_count(); + unsigned int* global_syms = new unsigned int[global_sym_count]; + memset(global_syms, 0, global_sym_count * sizeof(unsigned int)); + + // Write the section header. + Stringpool::Key command_line_key = inputs->command_line_key(); + pov = this->write_header(pov, inputs->input_file_count(), + strtab->get_offset_from_key(command_line_key)); + + // Write the list of input files. + pov = this->write_input_files(oview, pov, strtab); + + // Write the supplemental information blocks for each input file. + pov = this->write_info_blocks(oview, pov, strtab, global_syms, + global_sym_count); + + gold_assert(pov - oview == oview_size); + + // Write the .gnu_incremental_symtab section. + gold_assert(global_sym_count * 4 == symtab_size); + this->write_symtab(symtab_view, global_syms, global_sym_count); + + delete[] global_syms; + + of->write_output_view(off, oview_size, oview); + of->write_output_view(symtab_off, symtab_size, symtab_view); +} + +// Write the section header: version, input file count, offset of command line +// in the string table, and 4 bytes of padding. + +template<int size, bool big_endian> +unsigned char* +Output_section_incremental_inputs<size, big_endian>::write_header( + unsigned char* pov, + unsigned int input_file_count, + section_offset_type command_line_offset) +{ + Swap32::writeval(pov, INCREMENTAL_LINK_VERSION); + Swap32::writeval(pov + 4, input_file_count); + Swap32::writeval(pov + 8, command_line_offset); + Swap32::writeval(pov + 12, 0); + return pov + this->header_size; +} + +// Write the input file entries. + +template<int size, bool big_endian> +unsigned char* +Output_section_incremental_inputs<size, big_endian>::write_input_files( + unsigned char* oview, + unsigned char* pov, + Stringpool* strtab) +{ + const Incremental_inputs* inputs = this->inputs_; + + for (Incremental_inputs::Input_list::const_iterator p = + inputs->input_files().begin(); + p != inputs->input_files().end(); + ++p) + { + gold_assert(pov - oview == (*p)->get_offset()); + section_offset_type filename_offset = + strtab->get_offset_from_key((*p)->get_filename_key()); + const Timespec& mtime = (*p)->get_mtime(); + Swap32::writeval(pov, filename_offset); + Swap32::writeval(pov + 4, (*p)->get_info_offset()); + Swap64::writeval(pov + 8, mtime.seconds); + Swap32::writeval(pov + 16, mtime.nanoseconds); + Swap16::writeval(pov + 20, (*p)->type()); + Swap16::writeval(pov + 22, 0); + pov += this->input_entry_size; + } + return pov; +} + +// Write the supplemental information blocks. + +template<int size, bool big_endian> +unsigned char* +Output_section_incremental_inputs<size, big_endian>::write_info_blocks( + unsigned char* oview, + unsigned char* pov, + Stringpool* strtab, + unsigned int* global_syms, + unsigned int global_sym_count) +{ + const Incremental_inputs* inputs = this->inputs_; + unsigned int first_global_index = this->symtab_->first_global_index(); + + for (Incremental_inputs::Input_list::const_iterator p = + inputs->input_files().begin(); + p != inputs->input_files().end(); + ++p) + { + switch ((*p)->type()) + { + case INCREMENTAL_INPUT_SCRIPT: + // No supplemental info for a script. + break; + + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + { + gold_assert(pov - oview == (*p)->get_info_offset()); + Incremental_object_entry* entry = (*p)->object_entry(); + gold_assert(entry != NULL); + const Object* obj = entry->object(); + const Object::Symbols* syms = obj->get_global_symbols(); + // Write the input section count and global symbol count. + unsigned int nsections = entry->get_input_section_count(); + unsigned int nsyms = syms->size(); + Swap32::writeval(pov, nsections); + Swap32::writeval(pov + 4, nsyms); + pov += 8; + + // For each input section, write the name, output section index, + // offset within output section, and input section size. + for (unsigned int i = 0; i < nsections; i++) + { + Stringpool::Key key = entry->get_input_section_name_key(i); + off_t name_offset = 0; + if (key != 0) + name_offset = strtab->get_offset_from_key(key); + int out_shndx = 0; + off_t out_offset = 0; + off_t sh_size = 0; + Output_section* os = obj->output_section(i); + if (os != NULL) + { + out_shndx = os->out_shndx(); + out_offset = obj->output_section_offset(i); + sh_size = entry->get_input_section_size(i); + } + Swap32::writeval(pov, name_offset); + Swap32::writeval(pov + 4, out_shndx); + Swap::writeval(pov + 8, out_offset); + Swap::writeval(pov + 8 + sizeof_addr, sh_size); + pov += 8 + 2 * sizeof_addr; + } + + // For each global symbol, write its associated relocations, + // add it to the linked list of globals, then write the + // supplemental information: global symbol table index, + // linked list chain pointer, relocation count, and offset + // to the relocations. + for (unsigned int i = 0; i < nsyms; i++) + { + const Symbol* sym = (*syms)[i]; + unsigned int symtab_index = sym->symtab_index(); + unsigned int chain = 0; + unsigned int first_reloc = 0; + unsigned int nrelocs = obj->get_incremental_reloc_count(i); + if (nrelocs > 0) + { + gold_assert(symtab_index != -1U + && (symtab_index - first_global_index + < global_sym_count)); + first_reloc = obj->get_incremental_reloc_base(i); + chain = global_syms[symtab_index - first_global_index]; + global_syms[symtab_index - first_global_index] = + pov - oview; + } + Swap32::writeval(pov, symtab_index); + Swap32::writeval(pov + 4, chain); + Swap32::writeval(pov + 8, nrelocs); + Swap32::writeval(pov + 12, first_reloc * 3 * sizeof_addr); + pov += 16; + } + } + break; + + case INCREMENTAL_INPUT_SHARED_LIBRARY: + { + gold_assert(pov - oview == (*p)->get_info_offset()); + Incremental_object_entry* entry = (*p)->object_entry(); + gold_assert(entry != NULL); + const Object* obj = entry->object(); + const Object::Symbols* syms = obj->get_global_symbols(); + + // Write the global symbol count. + unsigned int nsyms = syms != NULL ? syms->size() : 0; + Swap32::writeval(pov, nsyms); + pov += 4; + + // For each global symbol, write the global symbol table index. + for (unsigned int i = 0; i < nsyms; i++) + { + const Symbol* sym = (*syms)[i]; + Swap32::writeval(pov, sym->symtab_index()); + pov += 4; + } + } + break; + + case INCREMENTAL_INPUT_ARCHIVE: + { + gold_assert(pov - oview == (*p)->get_info_offset()); + Incremental_archive_entry* entry = (*p)->archive_entry(); + gold_assert(entry != NULL); + + // Write the member count and unused global symbol count. + unsigned int nmembers = entry->get_member_count(); + unsigned int nsyms = entry->get_unused_global_symbol_count(); + Swap32::writeval(pov, nmembers); + Swap32::writeval(pov + 4, nsyms); + pov += 8; + + // For each member, write the offset to its input file entry. + for (unsigned int i = 0; i < nmembers; ++i) + { + Incremental_object_entry* member = entry->get_member(i); + Swap32::writeval(pov, member->get_offset()); + pov += 4; + } + + // For each global symbol, write the name offset. + for (unsigned int i = 0; i < nsyms; ++i) + { + Stringpool::Key key = entry->get_unused_global_symbol(i); + Swap32::writeval(pov, strtab->get_offset_from_key(key)); + pov += 4; + } + } + break; + + default: + gold_unreachable(); + } + } + return pov; +} + +// Write the contents of the .gnu_incremental_symtab section. + +template<int size, bool big_endian> +void +Output_section_incremental_inputs<size, big_endian>::write_symtab( + unsigned char* pov, + unsigned int* global_syms, + unsigned int global_sym_count) +{ + for (unsigned int i = 0; i < global_sym_count; ++i) + { + Swap32::writeval(pov, global_syms[i]); + pov += 4; + } } // Instantiate the templates we need. |