diff options
author | Cary Coutant <ccoutant@google.com> | 2010-08-12 22:01:11 +0000 |
---|---|---|
committer | Cary Coutant <ccoutant@google.com> | 2010-08-12 22:01:11 +0000 |
commit | 09ec0418c0d4144afba5947499425e27900d953f (patch) | |
tree | b50da7eeed399f6421cdc6027cbf2dabd8652c83 /gold/incremental.h | |
parent | 2010-08-12 Daniel Jacobowitz <dan@codesourcery.com> (diff) | |
download | binutils-gdb-09ec0418c0d4144afba5947499425e27900d953f.tar.gz binutils-gdb-09ec0418c0d4144afba5947499425e27900d953f.tar.bz2 binutils-gdb-09ec0418c0d4144afba5947499425e27900d953f.zip |
elfcpp/ChangeLog:
* elfcpp.h (enum SHT): Add SHT_GNU_INCREMENTAL_SYMTAB,
SHT_GNU_INCREMENTAL_RELOCS.
gold/ChangeLog:
* archive.cc: Include incremental.h.
(Archive::Archive): Initialize incremental_info_.
(Archive::include_member): Record archive members in incremental info.
(Add_archive_symbols::run): Record begin and end of an archive in
incremental info.
(Lib_group::include_member): Record objects in incremental info.
* archive.h (Incremental_archive_entry): Forward declaration.
(Archive::set_incremental_info): New member function.
(Archive::incremental_info): New member function.
(Archive::Unused_symbol_iterator): New class.
(Archive::unused_symbols_begin): New member function.
(Archive::unused_symbols_end): New member function.
(Archive::incremental_info_): New data member.
* incremental-dump.cc (find_input_containing_global): New function.
(dump_incremental_inputs): Dump new incremental info sections.
* incremental.cc: Include symtab.h.
(Output_section_incremental_inputs): New class.
(Sized_incremental_binary::do_find_incremental_inputs_sections): Support
new incremental info sections.
(Sized_incremental_binary::do_check_inputs): Likewise.
(Incremental_inputs::report_archive): Remove.
(Incremental_inputs::report_archive_begin): New function.
(Incremental_inputs::report_archive_end): New function.
(Incremental_inputs::report_object): New function.
(Incremental_inputs::finalize_inputs): Remove.
(Incremental_inputs::report_input_section): New function.
(Incremental_inputs::report_script): Rewrite.
(Incremental_inputs::finalize): Do nothing but finalize string table.
(Incremental_inputs::create_incremental_inputs_section_data): Remove.
(Incremental_inputs::sized_create_inputs_section_data): Remove.
(Incremental_inputs::create_data_sections): New function.
(Incremental_inputs::relocs_entsize): New function.
(Output_section_incremental_inputs::set_final_data_size): New function.
(Output_section_incremental_inputs::do_write): New function.
(Output_section_incremental_inputs::write_header): New function.
(Output_section_incremental_inputs::write_input_files): New function.
(Output_section_incremental_inputs::write_info_blocks): New function.
(Output_section_incremental_inputs::write_symtab): New function.
* incremental.h (Incremental_script_entry): Forward declaration.
(Incremental_object_entry): Forward declaration.
(Incremental_archive_entry): Forward declaration.
(Incremental_inputs): Forward declaration.
(Incremental_inputs_header_data): Remove.
(Incremental_inputs_header): Remove.
(Incremental_inputs_header_write): Remove.
(Incremental_inputs_entry_data): Remove.
(Incremental_inputs_entry): Remove.
(Incremental_inputs_entry_write): Remove.
(enum Incremental_input_type): Add INCREMENTAL_INPUT_ARCHIVE_MEMBER.
(Incremental_binary::find_incremental_inputs_sections): Add parameters.
(Incremental_binary::do_find_incremental_inputs_sections): Likewise.
(Sized_ncremental_binary::do_find_incremental_inputs_sections):
Likewise.
(Incremental_input_entry): New class.
(Incremental_script_entry): New class.
(Incremental_object_entry): New class.
(Incremental_archive_entry): New class.
(Incremental_inputs::Incremental_inputs): Initialize new data members.
(Incremental_inputs::report_inputs): Remove.
(Incremental_inputs::report_archive): Remove.
(Incremental_inputs::report_archive_begin): New function.
(Incremental_inputs::report_archive_end): New function.
(Incremental_inputs::report_object): Change prototype.
(Incremental_inputs::report_input_section): New function.
(Incremental_inputs::report_script): Change prototype.
(Incremental_inputs::get_reloc_count): New function.
(Incremental_inputs::set_reloc_count): New function.
(Incremental_inputs::create_data_sections): New function.
(Incremental_inputs::create_incremental_inputs_section_data): Remove.
(Incremental_inputs::inputs_section): New function.
(Incremental_inputs::symtab_section): New function.
(Incremental_inputs::relocs_section): New function.
(Incremental_inputs::get_stringpool): Add const.
(Incremental_inputs::command_line): Add const.
(Incremental_inputs::inputs): Remove.
(Incremental_inputs::command_line_key): New function.
(Incremental_inputs::input_file_count): New function.
(Incremental_inputs::input_files): New function.
(Incremental_inputs::relocs_entsize): New function.
(Incremental_inputs::sized_create_inputs_section_data): Remove.
(Incremental_inputs::finalize_inputs): Remove.
(Incremental_inputs::Input_info): Remove.
(Incremental_inputs::lock_): Remove.
(Incremental_inputs::inputs_): Change type.
(Incremental_inputs::inputs_map_): Remove.
(Incremental_inputs::current_object_entry_): New data member.
(Incremental_inputs::inputs_section_): New data member.
(Incremental_inputs::symtab_section_): New data member.
(Incremental_inputs::relocs_section_): New data member.
(Incremental_inputs::reloc_count_): New data member.
(Incremental_inputs_reader): New class.
(Incremental_symtab_reader): New class.
(Incremental_relocs_reader): New class.
* layout.cc (Layout::finalize): Move finalization of incremental info
and creation of incremental info sections to follow finalization of
symbol table. Set offsets for postprocessing sections.
(Layout::create_incremental_info_sections): Call
Incremental_inputs::create_data_sections. Add incremental symtab
and relocs sections. Set sh_entsize and sh_link fields. Arrange for
sections to layout after input sections.
* layout.h (struct Timespec): Forward declaration.
(Layout::incremental_inputs): Add const.
(Layout::create_incremental_info_sections): Add parameter.
* main.cc (main): Remove call to Incremental_inputs::report_inputs.
* object.cc: Include incremental.h.
(Relobj::finalize_incremental_relocs): New function.
(Sized_relobj::do_layout): Record input sections in incremental info.
* object.h (Object::output_section): New function.
(Object::output_section_offset): Moved from Relobj.
(Object::get_incremental_reloc_base): New function.
(Object::get_incremental_reloc_count): New function.
(Object::do_output_section): New function.
(Object::do_output_section_offset): Moved from Relobj.
(Object::do_get_incremental_reloc_base): New function.
(Object::do_get_incremental_reloc_count): New function.
(Object::Object): Initialize new data members.
(Relobj::output_section): Renamed do_output_section and moved to
protected.
(Relobj::output_section_offset): Moved to Object.
(Relobj::do_get_incremental_reloc_base): New function.
(Relobj::do_get_incremental_reloc_count): New function.
(Relobj::allocate_incremental_reloc_counts): New function.
(Relobj::count_incremental_reloc): New function.
(Relobj::finalize_incremental_relocs): New function.
(Relobj::next_incremental_reloc_index): New function.
(Relobj::reloc_counts_): New data member.
(Relobj::reloc_bases_): New data member.
(Sized_relobj::do_relocate_sections): Add parameter. Change caller.
(Sized_relobj::relocate_sections): Add parameter. Change all callers.
(Sized_relobj::incremental_relocs_scan): New function.
(Sized_relobj::incremental_relocs_scan_reltype): New function.
(Sized_relobj::incremental_relocs_write): New function.
(Sized_relobj::incremental_relocs_write_reltype): New function.
* plugin.cc (Plugin_manager::add_input_file): Rewrite test for
incremental link.
* readsyms.cc (Read_symbols::do_read_symbols): Move reporting of
archives and object files elsewhere.
(Add_symbols::run): Report object files here.
(Finish_group::run): Report end of archive at end of group.
* reloc.cc: Include layout.h, incremental.h.
(Sized_relobj::do_read_relocs): Need relocations for incremental link.
(Sized_relobj::do_scan_relocs): Record relocations for incremental link.
(Sized_relobj::incremental_relocs_scan): New function.
(Sized_relobj::incremental_relocs_scan_reltype): New function.
(Sized_relobj::do_relocate_sections): Write incremental relocations.
(Sized_relobj::incremental_relocs_write): New function.
(Sized_relobj::incremental_relocs_write_reltype): New function.
* script.cc (read_input_script): Rewrite test for incremental link.
Change call to Incremental_inputs::report_script.
* symtab.h (Symbol_table::first_global_index): New function.
(Symbol_table::output_count): New function.
Diffstat (limited to 'gold/incremental.h')
-rw-r--r-- | gold/incremental.h | 982 |
1 files changed, 693 insertions, 289 deletions
diff --git a/gold/incremental.h b/gold/incremental.h index a94f39719c9..6fb1a324e74 100644 --- a/gold/incremental.h +++ b/gold/incremental.h @@ -1,6 +1,6 @@ // inremental.h -- incremental linking support for gold -*- C++ -*- -// 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. @@ -38,221 +38,21 @@ namespace gold class Archive; class Input_argument; class Incremental_inputs_checker; +class Incremental_script_entry; +class Incremental_object_entry; +class Incremental_archive_entry; +class Incremental_inputs; class Object; -class Output_section_data; // Incremental input type as stored in .gnu_incremental_inputs. enum Incremental_input_type { - INCREMENTAL_INPUT_INVALID = 0, INCREMENTAL_INPUT_OBJECT = 1, - INCREMENTAL_INPUT_ARCHIVE = 2, - INCREMENTAL_INPUT_SHARED_LIBRARY = 3, - INCREMENTAL_INPUT_SCRIPT = 4 -}; - -// Header of the .gnu_incremental_input section. -struct Incremental_inputs_header_data -{ - // Incremental linker version. - elfcpp::Elf_Word version; - - // Numer of input files in the link. - elfcpp::Elf_Word input_file_count; - - // Offset of command line options in .gnu_incremental_strtab. - elfcpp::Elf_Word command_line_offset; - - // Padding. - elfcpp::Elf_Word reserved; -}; - -// Reader class for .gnu_incremental_inputs header. See -// Incremental_inputs_header_data for fields descriptions. - -template<int size, bool big_endian> -class Incremental_inputs_header -{ - private: - typedef Incremental_inputs_header_data Data_type; - typedef elfcpp::Convert<32, big_endian> Convert32; - - public: - Incremental_inputs_header(const unsigned char *p) - : p_(reinterpret_cast<const Data_type*>(p)) - { } - - static const int data_size = sizeof(Data_type); - - elfcpp::Elf_Word - get_version() const - { return Convert32::convert_host(this->p_->version); } - - elfcpp::Elf_Word - get_input_file_count() const - { return Convert32::convert_host(this->p_->input_file_count); } - - elfcpp::Elf_Word - get_command_line_offset() const - { return Convert32::convert_host(this->p_->command_line_offset); } - - elfcpp::Elf_Word - get_reserved() const - { return Convert32::convert_host(this->p_->reserved); } - - private: - const Data_type* p_; -}; - -// Writer class for .gnu_incremental_inputs header. See -// Incremental_inputs_header_data for fields descriptions. - -template<int size, bool big_endian> -class Incremental_inputs_header_write -{ - private: - typedef Incremental_inputs_header_data Data_type; - typedef elfcpp::Convert<32, big_endian> Convert32; - - public: - Incremental_inputs_header_write(unsigned char *p) - : p_(reinterpret_cast<Data_type*>(p)) - { } - - static const int data_size = sizeof(Data_type); - - void - put_version(elfcpp::Elf_Word v) - { this->p_->version = Convert32::convert_host(v); } - - void - put_input_file_count(elfcpp::Elf_Word v) - { this->p_->input_file_count = Convert32::convert_host(v); } - - void - put_command_line_offset(elfcpp::Elf_Word v) - { this->p_->command_line_offset = Convert32::convert_host(v); } - - void - put_reserved(elfcpp::Elf_Word v) - { this->p_->reserved = Convert32::convert_host(v); } - - private: - Data_type* p_; -}; - -// Data stored in .gnu_incremental_input after the header for each of the -// Incremental_input_header_data::input_file_count input entries. -struct Incremental_inputs_entry_data -{ - // Offset of file name in .gnu_incremental_strtab section. - elfcpp::Elf_Word filename_offset; - - // Offset of data in .gnu_incremental_input. - elfcpp::Elf_Word data_offset; - - // Timestamp (in seconds). - elfcpp::Elf_Xword timestamp_sec; - - // Nano-second part of timestamp (if supported). - elfcpp::Elf_Word timestamp_nsec; - - // Type of the input entry. - elfcpp::Elf_Half input_type; - - // Padding. - elfcpp::Elf_Half reserved; -}; - -// Reader class for an .gnu_incremental_inputs entry. See -// Incremental_inputs_entry_data for fields descriptions. -template<int size, bool big_endian> -class Incremental_inputs_entry -{ - private: - typedef Incremental_inputs_entry_data Data_type; - typedef elfcpp::Convert<32, big_endian> Convert32; - typedef elfcpp::Convert<64, big_endian> Convert64; - - public: - Incremental_inputs_entry(const unsigned char *p) - : p_(reinterpret_cast<const Data_type*>(p)) - { } - - static const int data_size = sizeof(Data_type); - - elfcpp::Elf_Word - get_filename_offset() - { return Convert32::convert_host(this->p_->filename_offset); } - - elfcpp::Elf_Word - get_data_offset() - { return Convert32::convert_host(this->p_->data_offset); } - - elfcpp::Elf_Xword - get_timestamp_sec() - { return Convert64::convert_host(this->p_->timestamp_sec); } - - elfcpp::Elf_Word - get_timestamp_nsec() - { return Convert32::convert_host(this->p_->timestamp_nsec); } - - elfcpp::Elf_Word - get_input_type() - { return Convert32::convert_host(this->p_->input_type); } - - elfcpp::Elf_Word - get_reserved() - { return Convert32::convert_host(this->p_->reserved); } - - private: - const Data_type* p_; -}; - -// Writer class for an .gnu_incremental_inputs entry. See -// Incremental_inputs_entry_data for fields descriptions. -template<int size, bool big_endian> -class Incremental_inputs_entry_write -{ - private: - typedef Incremental_inputs_entry_data Data_type; - typedef elfcpp::Convert<32, big_endian> Convert32; - typedef elfcpp::Convert<64, big_endian> Convert64; - - public: - Incremental_inputs_entry_write(unsigned char *p) - : p_(reinterpret_cast<Data_type*>(p)) - { } - - static const int data_size = sizeof(Data_type); - - void - put_filename_offset(elfcpp::Elf_Word v) - { this->p_->filename_offset = Convert32::convert_host(v); } - - void - put_data_offset(elfcpp::Elf_Word v) - { this->p_->data_offset = Convert32::convert_host(v); } - - void - put_timestamp_sec(elfcpp::Elf_Xword v) - { this->p_->timestamp_sec = Convert64::convert_host(v); } - - void - put_timestamp_nsec(elfcpp::Elf_Word v) - { this->p_->timestamp_nsec = Convert32::convert_host(v); } - - void - put_input_type(elfcpp::Elf_Word v) - { this->p_->input_type = Convert32::convert_host(v); } - - void - put_reserved(elfcpp::Elf_Word v) - { this->p_->reserved = Convert32::convert_host(v); } - - private: - Data_type* p_; + INCREMENTAL_INPUT_ARCHIVE_MEMBER = 2, + INCREMENTAL_INPUT_ARCHIVE = 3, + INCREMENTAL_INPUT_SHARED_LIBRARY = 4, + INCREMENTAL_INPUT_SCRIPT = 5 }; // An object representing the ELF file we edit during an incremental build. @@ -315,20 +115,27 @@ class Incremental_binary }; // Get a View given a Location. - View view(Location loc) + View + view(Location loc) { return View(this->view(loc.file_offset, loc.data_size)); } // Report an error. void error(const char* format, ...) const ATTRIBUTE_PRINTF_2; - // Find the .gnu_incremental_inputs section. It selects the first section - // of type SHT_GNU_INCREMENTAL_INPUTS. Returns false if such a section - // is not found. + // Find the .gnu_incremental_inputs and related sections. It selects the + // first section of type SHT_GNU_INCREMENTAL_INPUTS, + // SHT_GNU_INCRMENTAL_SYMTAB, and SHT_GNU_INCREMENTAL_RELOCS. + // Returns false if the sections are not found. bool - find_incremental_inputs_section(Location* location, - unsigned int* strtab_shndx) - { return do_find_incremental_inputs_section(location, strtab_shndx); } + find_incremental_inputs_sections(unsigned int* p_inputs_shndx, + unsigned int* p_symtab_shndx, + unsigned int* p_relocs_shndx, + unsigned int* p_strtab_shndx) + { + return do_find_incremental_inputs_sections(p_inputs_shndx, p_symtab_shndx, + p_relocs_shndx, p_strtab_shndx); + } // Check the .gnu_incremental_inputs section to see whether an incremental // build is possible. @@ -343,8 +150,10 @@ class Incremental_binary protected: // Find incremental inputs section. virtual bool - do_find_incremental_inputs_section(Location* location, - unsigned int* strtab_shndx) = 0; + 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) = 0; // Check the .gnu_incremental_inputs section to see whether an incremental // build is possible. @@ -370,8 +179,10 @@ class Sized_incremental_binary : public Incremental_binary protected: virtual bool - do_find_incremental_inputs_section(Location* location, - unsigned int* strtab_shndx); + 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); virtual bool do_check_inputs(Incremental_inputs* incremental_inputs); @@ -383,11 +194,13 @@ class Sized_incremental_binary : public Incremental_binary // 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. + Incremental_binary* open_incremental_binary(Output_file* file); // Code invoked early during an incremental link that checks what files need // to be relinked. + class Incremental_checker { public: @@ -415,135 +228,726 @@ class Incremental_checker Incremental_inputs* incremental_inputs_; }; +// Base class for recording each input file. + +class Incremental_input_entry +{ + public: + Incremental_input_entry(Stringpool::Key filename_key, Timespec mtime) + : filename_key_(filename_key), offset_(0), info_offset_(0), mtime_(mtime) + { } + + // Return the type of input file. + Incremental_input_type + type() const + { return this->do_type(); } + + // Set the section offset of this input file entry. + void + set_offset(unsigned int offset) + { this->offset_ = offset; } + + // Set the section offset of the supplemental information for this entry. + void + set_info_offset(unsigned int info_offset) + { this->info_offset_ = info_offset; } + + // Get the section offset of this input file entry. + unsigned int + get_offset() const + { return this->offset_; } + + // Get the section offset of the supplemental information for this entry. + unsigned int + get_info_offset() const + { return this->info_offset_; } + + // Get the stringpool key for the input filename. + Stringpool::Key + get_filename_key() const + { return this->filename_key_; } + + // Get the modification time of the input file. + const Timespec& + get_mtime() const + { return this->mtime_; } + + // Return a pointer to the derived Incremental_script_entry object. + // Return NULL for input entries that are not script files. + Incremental_script_entry* + script_entry() + { return this->do_script_entry(); } + + // Return a pointer to the derived Incremental_object_entry object. + // Return NULL for input entries that are not object files. + Incremental_object_entry* + object_entry() + { return this->do_object_entry(); } + + // Return a pointer to the derived Incremental_archive_entry object. + // Return NULL for input entries that are not archive files. + Incremental_archive_entry* + archive_entry() + { return this->do_archive_entry(); } + + protected: + // Return the type of input file. + virtual Incremental_input_type + do_type() const = 0; + + // Return a pointer to the derived Incremental_script_entry object. + // Return NULL for input entries that are not script files. + virtual Incremental_script_entry* + do_script_entry() + { return NULL; } + + // Return a pointer to the derived Incremental_object_entry object. + // Return NULL for input entries that are not object files. + virtual Incremental_object_entry* + do_object_entry() + { return NULL; } + + // Return a pointer to the derived Incremental_archive_entry object. + // Return NULL for input entries that are not archive files. + virtual Incremental_archive_entry* + do_archive_entry() + { return NULL; } + + private: + // Key of the filename string in the section stringtable. + Stringpool::Key filename_key_; + + // Offset of the entry in the output section. + unsigned int offset_; + + // Offset of the extra information in the output section. + unsigned int info_offset_; + + // Last modification time of the file. + Timespec mtime_; +}; + +// Class for recording input scripts. + +class Incremental_script_entry : public Incremental_input_entry +{ + public: + Incremental_script_entry(Stringpool::Key filename_key, Script_info* script, + Timespec mtime) + : Incremental_input_entry(filename_key, mtime), script_(script) + { } + + protected: + virtual Incremental_input_type + do_type() const + { return INCREMENTAL_INPUT_SCRIPT; } + + // Return a pointer to the derived Incremental_script_entry object. + virtual Incremental_script_entry* + do_script_entry() + { return this; } + + private: + // Information about the script file. + Script_info* script_; +}; + +// Class for recording input object files. + +class Incremental_object_entry : public Incremental_input_entry +{ + public: + Incremental_object_entry(Stringpool::Key filename_key, Object* obj, + Timespec mtime) + : Incremental_input_entry(filename_key, mtime), obj_(obj), + is_member_(false), sections_() + { + if (!obj_->is_dynamic()) + this->sections_.reserve(obj->shnum()); + } + + // Get the object. + Object* + object() const + { return this->obj_; } + + // Record that this object is an archive member. + void + set_is_member() + { this->is_member_ = true; } + + // Return true if this object is an archive member. + bool + is_member() const + { return this->is_member_; } + + // Add an input section. + void + add_input_section(unsigned int shndx, Stringpool::Key name_key, off_t sh_size) + { + if (shndx >= this->sections_.size()) + this->sections_.resize(shndx + 1); + this->sections_[shndx].name_key = name_key; + this->sections_[shndx].sh_size = sh_size; + } + + // Return the number of input sections in this object. + unsigned int + get_input_section_count() const + { return this->sections_.size(); } + + // Return the stringpool key of the Nth input section. + Stringpool::Key + get_input_section_name_key(unsigned int n) const + { return this->sections_[n].name_key; } + + // Return the size of the Nth input section. + off_t + get_input_section_size(unsigned int n) const + { return this->sections_[n].sh_size; } + + protected: + virtual Incremental_input_type + do_type() const + { + return (this->is_member_ + ? INCREMENTAL_INPUT_ARCHIVE_MEMBER + : (this->obj_->is_dynamic() + ? INCREMENTAL_INPUT_SHARED_LIBRARY + : INCREMENTAL_INPUT_OBJECT)); + } + + // Return a pointer to the derived Incremental_object_entry object. + virtual Incremental_object_entry* + do_object_entry() + { return this; } + + private: + // The object file itself. + Object* obj_; + + // Whether this object is an archive member. + bool is_member_; + + // Input sections. + struct Input_section + { + Stringpool::Key name_key; + off_t sh_size; + }; + std::vector<Input_section> sections_; +}; + +// Class for recording archive library input files. + +class Incremental_archive_entry : public Incremental_input_entry +{ + public: + Incremental_archive_entry(Stringpool::Key filename_key, Archive*, + Timespec mtime) + : Incremental_input_entry(filename_key, mtime), members_(), unused_syms_() + { } + + // Add a member object to the archive. + void + add_object(Incremental_object_entry* obj_entry) + { + this->members_.push_back(obj_entry); + obj_entry->set_is_member(); + } + + // Add an unused global symbol to the archive. + void + add_unused_global_symbol(Stringpool::Key symbol_key) + { this->unused_syms_.push_back(symbol_key); } + + // Return the number of member objects included in the link. + unsigned int + get_member_count() + { return this->members_.size(); } + + // Return the Nth member object. + Incremental_object_entry* + get_member(unsigned int n) + { return this->members_[n]; } + + // Return the number of unused global symbols in this archive. + unsigned int + get_unused_global_symbol_count() + { return this->unused_syms_.size(); } + + // Return the Nth unused global symbol. + Stringpool::Key + get_unused_global_symbol(unsigned int n) + { return this->unused_syms_[n]; } + + protected: + virtual Incremental_input_type + do_type() const + { return INCREMENTAL_INPUT_ARCHIVE; } + + // Return a pointer to the derived Incremental_archive_entry object. + virtual Incremental_archive_entry* + do_archive_entry() + { return this; } + + private: + // Members of the archive that have been included in the link. + std::vector<Incremental_object_entry*> members_; + + // Unused global symbols from this archive. + std::vector<Stringpool::Key> unused_syms_; +}; + // This class contains the information needed during an incremental // build about the inputs necessary to build the .gnu_incremental_inputs. + class Incremental_inputs { public: + typedef std::vector<Incremental_input_entry*> Input_list; + Incremental_inputs() - : lock_(new Lock()), inputs_(NULL), command_line_key_(0), - strtab_(new Stringpool()) + : inputs_(), command_line_(), command_line_key_(0), + strtab_(new Stringpool()), current_object_(NULL), + current_object_entry_(NULL), inputs_section_(NULL), + symtab_section_(NULL), relocs_section_(NULL), + reloc_count_(0) { } + ~Incremental_inputs() { delete this->strtab_; } // Record the command line. void report_command_line(int argc, const char* const* argv); - // Record the input arguments obtained from parsing the command line. + // Record the initial info for archive file ARCHIVE. + void + report_archive_begin(Archive* arch); + + // Record the final info for archive file ARCHIVE. + void + report_archive_end(Archive* arch); + + // Record the info for object file OBJ. If ARCH is not NULL, + // attach the object file to the archive. void - report_inputs(const Input_arguments& inputs) - { this->inputs_ = &inputs; } + report_object(Object* obj, Archive* arch); - // Record that the input argument INPUT is an archive ARCHIVE. + // Record an input section belonging to object file OBJ. void - report_archive(const Input_argument* input, Archive* archive); + report_input_section(Object* obj, unsigned int shndx, const char* name, + off_t sh_size); - // Record that the input argument INPUT is to an object OBJ. + // Record the info for input script SCRIPT. void - report_object(const Input_argument* input, Object* obj); + report_script(const std::string& filename, Script_info* script, + Timespec mtime); + + // Return the running count of incremental relocations. + unsigned int + get_reloc_count() const + { return this->reloc_count_; } - // Record that the input argument INPUT is to an script SCRIPT. + // Update the running count of incremental relocations. void - report_script(const Input_argument* input, Timespec mtime, - Script_info* script); + set_reloc_count(unsigned int count) + { this->reloc_count_ = count; } // Prepare for layout. Called from Layout::finalize. void finalize(); - // Create the content of the .gnu_incremental_inputs section. + // Create the .gnu_incremental_inputs and related sections. + void + create_data_sections(Symbol_table* symtab); + + // Return the .gnu_incremental_inputs section. Output_section_data* - create_incremental_inputs_section_data(); + inputs_section() const + { return this->inputs_section_; } + + // Return the .gnu_incremental_symtab section. + Output_data_space* + symtab_section() const + { return this->symtab_section_; } + + // Return the .gnu_incremental_relocs section. + Output_data_space* + relocs_section() const + { return this->relocs_section_; } // Return the .gnu_incremental_strtab stringpool. Stringpool* - get_stringpool() + get_stringpool() const { return this->strtab_; } // Return the canonical form of the command line, as will be stored in // .gnu_incremental_strtab. const std::string& - command_line() + command_line() const { return this->command_line_; } - // Return the input files found in the command line. - const Input_arguments* - inputs() + // Return the stringpool key of the command line. + Stringpool::Key + command_line_key() const + { return this->command_line_key_; } + + // Return the number of input files. + int + input_file_count() const + { return this->inputs_.size(); } + + // Return the input files. + const Input_list& + input_files() const { return this->inputs_; } + // Return the sh_entsize value for the .gnu_incremental_relocs section. + unsigned int + relocs_entsize() const; + private: - // Code for each of the four possible variants of create_inputs_section_data. - template<int size, bool big_endian> - Output_section_data* - sized_create_inputs_section_data(); + // The list of input files. + Input_list inputs_; - // Compute indexes in the order in which the inputs should appear in - // .gnu_incremental_inputs and put file names to the stringtable. - // This needs to be done after all the scripts are parsed. + // Canonical form of the command line, as will be stored in + // .gnu_incremental_strtab. + std::string command_line_; - void - finalize_inputs(Input_argument_list::const_iterator begin, - Input_argument_list::const_iterator end, - unsigned int* index); + // The key of the command line string in the string pool. + Stringpool::Key command_line_key_; + + // The .gnu_incremental_strtab string pool associated with the + // .gnu_incremental_inputs. + Stringpool* strtab_; + + // Keep track of the object currently being processed. + Object* current_object_; + Incremental_object_entry* current_object_entry_; + + // The .gnu_incremental_inputs section. + Output_section_data* inputs_section_; - // Additional data about an input needed for an incremental link. - // None of these pointers is owned by the structure. - struct Input_info + // The .gnu_incremental_symtab section. + Output_data_space* symtab_section_; + + // The .gnu_incremental_relocs section. + Output_data_space* relocs_section_; + + // Total count of incremental relocations. Updated during Scan_relocs + // phase at the completion of each object file. + unsigned int reloc_count_; +}; + +// Reader class for .gnu_incremental_inputs section. + +template<int size, bool big_endian> +class Incremental_inputs_reader +{ + private: + 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; + + public: + Incremental_inputs_reader(const unsigned char* p, elfcpp::Elf_strtab& strtab) + : p_(p), strtab_(strtab) + { this->input_file_count_ = Swap32::readval(this->p_ + 4); } + + // Return the version number. + unsigned int + version() const + { return Swap32::readval(this->p_); } + + // Return the count of input file entries. + unsigned int + input_file_count() const + { return this->input_file_count_; } + + // Return the command line. + const char* + command_line() const { - Input_info() - : type(INCREMENTAL_INPUT_INVALID), archive(NULL), filename_key(0), - index(0) - { } + unsigned int offset = Swap32::readval(this->p_ + 8); + return this->get_string(offset); + } - // Type of the file pointed by this argument. - Incremental_input_type type; + // Reader class for an input file entry and its supplemental info. + class Incremental_input_entry_reader + { + public: + Incremental_input_entry_reader(const Incremental_inputs_reader* inputs, + unsigned int offset) + : inputs_(inputs), offset_(offset) + { + this->info_offset_ = Swap32::readval(inputs->p_ + offset + 4); + int type = Swap16::readval(this->inputs_->p_ + offset + 20); + this->type_ = static_cast<Incremental_input_type>(type); + } + + // Return the filename. + const char* + filename() const + { + unsigned int offset = Swap32::readval(this->inputs_->p_ + this->offset_); + return this->inputs_->get_string(offset); + } - union + // Return the timestamp. + Timespec + get_mtime() const + { + Timespec t; + const unsigned char* p = this->inputs_->p_ + this->offset_ + 8; + t.seconds = Swap64::readval(p); + t.nanoseconds = Swap32::readval(p+8); + return t; + } + + // Return the type of input file. + Incremental_input_type + type() const + { return this->type_; } + + // Return the input section count -- for objects only. + unsigned int + get_input_section_count() const { - // Present if type == INCREMENTAL_INPUT_ARCHIVE. - Archive* archive; + gold_assert(this->type_ == INCREMENTAL_INPUT_OBJECT + || this->type_ == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + return Swap32::readval(this->inputs_->p_ + this->info_offset_); + } + + // Return the offset of the supplemental info for symbol SYMNDX -- + // for objects only. + unsigned int + get_symbol_offset(unsigned int symndx) const + { + gold_assert(this->type_ == INCREMENTAL_INPUT_OBJECT + || this->type_ == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + unsigned int section_count = this->get_input_section_count(); + return (this->info_offset_ + 8 + + section_count * input_section_entry_size + + symndx * 16); + } + + // Return the global symbol count -- for objects & shared libraries only. + unsigned int + get_global_symbol_count() const + { + switch (this->type_) + { + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4); + case INCREMENTAL_INPUT_SHARED_LIBRARY: + return Swap32::readval(this->inputs_->p_ + this->info_offset_); + default: + gold_unreachable(); + } + } + + // Return the member count -- for archives only. + unsigned int + get_member_count() const + { + gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE); + return Swap32::readval(this->inputs_->p_ + this->info_offset_); + } - // Present if type == INCREMENTAL_INPUT_OBJECT or - // INCREMENTAL_INPUT_SHARED_LIBRARY. - Object* object; + // Return the unused symbol count -- for archives only. + unsigned int + get_unused_symbol_count() const + { + gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE); + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4); + } - // Present if type == INCREMENTAL_INPUT_SCRIPT. - Script_info* script; + // Return the input file offset for archive member N -- for archives only. + unsigned int + get_member_offset(unsigned int n) const + { + gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE); + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + + 8 + n * 4); + } + + // Return the Nth unused global symbol -- for archives only. + const char* + get_unused_symbol(unsigned int n) const + { + gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE); + unsigned int member_count = this->get_member_count(); + unsigned int offset = Swap32::readval(this->inputs_->p_ + + this->info_offset_ + 8 + + member_count * 4 + + n * 4); + return this->inputs_->get_string(offset); + } + + // Information about an input section. + struct Input_section_info + { + const char* name; + unsigned int output_shndx; + off_t sh_offset; + off_t sh_size; }; - // Key of the filename string in the section stringtable. - Stringpool::Key filename_key; + // Return info about the Nth input section -- for objects only. + Input_section_info + get_input_section(unsigned int n) const + { + Input_section_info info; + const unsigned char* p = (this->inputs_->p_ + + this->info_offset_ + 8 + + n * input_section_entry_size); + unsigned int name_offset = Swap32::readval(p); + info.name = this->inputs_->get_string(name_offset); + info.output_shndx = Swap32::readval(p + 4); + info.sh_offset = Swap::readval(p + 8); + info.sh_size = Swap::readval(p + 8 + size / 8); + return info; + } + + // Information about a global symbol. + struct Global_symbol_info + { + unsigned int output_symndx; + unsigned int next_offset; + unsigned int reloc_count; + unsigned int reloc_offset; + }; - // Position of the entry information in the output section. - unsigned int index; + // Return info about the Nth global symbol -- for objects only. + Global_symbol_info + get_global_symbol_info(unsigned int n) const + { + Global_symbol_info info; + unsigned int section_count = this->get_input_section_count(); + const unsigned char* p = (this->inputs_->p_ + + this->info_offset_ + 8 + + section_count * input_section_entry_size + + n * 16); + info.output_symndx = Swap32::readval(p); + info.next_offset = Swap32::readval(p + 4); + info.reloc_count = Swap::readval(p + 8); + info.reloc_offset = Swap::readval(p + 12); + return info; + } - // Last modification time of the file. - Timespec mtime; + private: + // Size of an input section entry. + static const unsigned int input_section_entry_size = 8 + 2 * size / 8; + // The reader instance for the containing section. + const Incremental_inputs_reader* inputs_; + // The type of input file. + Incremental_input_type type_; + // Section offset to the input file entry. + unsigned int offset_; + // Section offset to the supplemental info for the input file. + unsigned int info_offset_; }; - typedef std::map<const Input_argument*, Input_info> Inputs_info_map; + // Return a reader for the Nth input file entry. + Incremental_input_entry_reader + input_file(unsigned int n) const + { + gold_assert(n < this->input_file_count_); + Incremental_input_entry_reader input(this, 16 + n * 24); + return input; + } + + private: + // Lookup a string in the ELF string table. + const char* get_string(unsigned int offset) const + { + const char* s; + if (this->strtab_.get_c_string(offset, &s)) + return s; + return NULL; + } + + // Base address of the .gnu_incremental_inputs section. + const unsigned char* p_; + // The associated ELF string table. + elfcpp::Elf_strtab strtab_; + // The number of input file entries in this section. + unsigned int input_file_count_; +}; + +// Reader class for the .gnu_incremental_symtab section. - // A lock guarding access to inputs_ during the first phase of linking, when - // report_ function may be called from multiple threads. - Lock* lock_; +template<bool big_endian> +class Incremental_symtab_reader +{ + public: + Incremental_symtab_reader(const unsigned char* p) : p_(p) + { } - // The list of input arguments obtained from parsing the command line. - const Input_arguments* inputs_; + // Return the list head for symbol table entry N. + unsigned int get_list_head(unsigned int n) + { return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4 * n); } - // A map containing additional information about the input elements. - Inputs_info_map inputs_map_; + private: + // Base address of the .gnu_incremental_relocs section. + const unsigned char* p_; +}; - // Canonical form of the command line, as will be stored in - // .gnu_incremental_strtab. - std::string command_line_; +// Reader class for the .gnu_incremental_relocs section. - // The key of the command line string in the string pool. - Stringpool::Key command_line_key_; +template<int size, bool big_endian> +class Incremental_relocs_reader +{ + private: + // Size of each field. + static const unsigned int field_size = size / 8; - // The .gnu_incremental_strtab string pool associated with the - // .gnu_incremental_inputs. - Stringpool* strtab_; + public: + typedef typename elfcpp::Elf_types<size>::Elf_Addr Address; + typedef typename elfcpp::Elf_types<size>::Elf_Swxword Addend; + + // Size of each entry. + static const unsigned int reloc_size = 8 + 2 * field_size; + + Incremental_relocs_reader(const unsigned char* p) : p_(p) + { } + + // Return the relocation type for relocation entry at offset OFF. + unsigned int + get_r_type(unsigned int off) + { + return elfcpp::Swap<32, big_endian>::readval(this->p_ + off); + } + + // Return the output section index for relocation entry at offset OFF. + unsigned int + get_r_shndx(unsigned int off) + { + return elfcpp::Swap<32, big_endian>::readval(this->p_ + off + 4); + } + + // Return the output section offset for relocation entry at offset OFF. + Address + get_r_offset(unsigned int off) + { + return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8); + } + + // Return the addend for relocation entry at offset OFF. + Addend + get_r_addend(unsigned int off) + { + return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8 + + this->field_size); + } + + private: + // Base address of the .gnu_incremental_relocs section. + const unsigned char* p_; }; } // End namespace gold. |