elfcpp/ChangeLog:
authorCary Coutant <ccoutant@google.com>
Thu, 12 Aug 2010 22:01:11 +0000 (22:01 +0000)
committerCary Coutant <ccoutant@google.com>
Thu, 12 Aug 2010 22:01:11 +0000 (22:01 +0000)
* 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.

18 files changed:
elfcpp/ChangeLog
elfcpp/elfcpp.h
gold/ChangeLog
gold/archive.cc
gold/archive.h
gold/incremental-dump.cc
gold/incremental.cc
gold/incremental.h
gold/layout.cc
gold/layout.h
gold/main.cc
gold/object.cc
gold/object.h
gold/plugin.cc
gold/readsyms.cc
gold/reloc.cc
gold/script.cc
gold/symtab.h

index 782b3cf40bd07f866d292f61f43b26c468b2627f..7488984e9ca83aacea0645f4985e2b0e26d5b018 100644 (file)
@@ -1,3 +1,8 @@
+2010-08-12  Cary Coutant  <ccoutant@google.com>
+
+       * elfcpp.h (enum SHT): Add SHT_GNU_INCREMENTAL_SYMTAB,
+       SHT_GNU_INCREMENTAL_RELOCS.
+
 2010-08-04  Ian Lance Taylor  <iant@google.com>
 
        * i386.h (R_386_IRELATIVE): Define.
index 52b8b2534ee8671e445bb15b238eccdf7688c0e0..c46fbf5a47f1e2866a1514c09542c4fc2274f55e 100644 (file)
@@ -365,6 +365,8 @@ enum SHT
   // The remaining values are not in the standard.
   // Incremental build data.
   SHT_GNU_INCREMENTAL_INPUTS = 0x6fff4700,
+  SHT_GNU_INCREMENTAL_SYMTAB = 0x6fff4701,
+  SHT_GNU_INCREMENTAL_RELOCS = 0x6fff4702,
   // Object attributes.
   SHT_GNU_ATTRIBUTES = 0x6ffffff5,
   // GNU style dynamic hash table.
index 90510b5f6e1514785df990df9caae2735d738f03..c77f2d7cc1bc38d330795d3063545bd417b521ae 100644 (file)
@@ -1,3 +1,157 @@
+2010-08-12  Cary Coutant  <ccoutant@google.com>
+
+       * 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.
+
 2010-08-12  Doug Kwan  <dougkwan@google.com>
 
        * arm.cc (Target_arm::merge_object_attributes): Check command line
index f1000a195de25c38588ae3960188767cc7fae337..8c34d5524b5814d9e86326fbb076ff70539926f4 100644 (file)
@@ -39,6 +39,7 @@
 #include "layout.h"
 #include "archive.h"
 #include "plugin.h"
+#include "incremental.h"
 
 namespace gold
 {
@@ -89,7 +90,8 @@ Archive::Archive(const std::string& name, Input_file* input_file,
   : name_(name), input_file_(input_file), armap_(), armap_names_(),
     extended_names_(), armap_checked_(), seen_offsets_(), members_(),
     is_thin_archive_(is_thin_archive), included_member_(false),
-    nested_archives_(), dirpath_(dirpath), task_(task), num_members_(0)
+    nested_archives_(), dirpath_(dirpath), task_(task), num_members_(0),
+    incremental_info_(NULL)
 {
   this->no_export_ =
     parameters->options().check_excluded_libs(input_file->found_name());
@@ -891,6 +893,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
   else
     {
       {
+       if (layout->incremental_inputs() != NULL)
+         layout->incremental_inputs()->report_object(obj, this);
        Read_symbols_data sd;
        obj->read_symbols(&sd);
        obj->layout(symtab, layout, &sd);
@@ -952,6 +956,11 @@ Add_archive_symbols::locks(Task_locker* tl)
 void
 Add_archive_symbols::run(Workqueue* workqueue)
 {
+  // For an incremental link, begin recording layout information.
+  Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+  if (incremental_inputs != NULL)
+    incremental_inputs->report_archive_begin(this->archive_);
+
   bool added = this->archive_->add_symbols(this->symtab_, this->layout_,
                                           this->input_objects_,
                                           this->mapfile_);
@@ -978,6 +987,11 @@ Add_archive_symbols::run(Workqueue* workqueue)
     this->input_group_->add_archive(this->archive_);
   else
     {
+      // For an incremental link, finish recording the layout information.
+      Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+      if (incremental_inputs != NULL)
+       incremental_inputs->report_archive_end(this->archive_);
+
       // We no longer need to know about this archive.
       delete this->archive_;
       this->archive_ = NULL;
@@ -1077,6 +1091,9 @@ Lib_group::include_member(Symbol_table* symtab, Layout* layout,
   obj->lock(this->task_);
   if (input_objects->add_object(obj))
     {
+      // FIXME: Record incremental link info for --start-lib/--end-lib.
+      if (layout->incremental_inputs() != NULL)
+       layout->incremental_inputs()->report_object(obj, NULL);
       obj->layout(symtab, layout, sd);
       obj->add_symbols(symtab, sd, layout);
       // Unlock the file for the next task.
@@ -1116,6 +1133,8 @@ void
 Add_lib_group_symbols::run(Workqueue*)
 {
   this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_);
+
+  // FIXME: Record incremental link info for --start_lib/--end_lib.
 }
 
 Add_lib_group_symbols::~Add_lib_group_symbols()
index bff34576ecae225bcea734052e33d9687497b787..9107d1e612fe519f52de0c8b4691043548e7d0f7 100644 (file)
@@ -1,6 +1,6 @@
 // archive.h -- archive support for gold      -*- C++ -*-
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -42,6 +42,7 @@ class Symbol_table;
 class Object;
 class Read_symbols_data;
 class Input_file_lib;
+class Incremental_archive_entry;
 
 // An entry in the archive map of offsets to members.
 struct Archive_member
@@ -164,6 +165,16 @@ class Archive
   no_export()
   { return this->no_export_; }
 
+  // Store a pointer to the incremental link info for the archive.
+  void
+  set_incremental_info(Incremental_archive_entry* info)
+  { this->incremental_info_ = info; }
+
+  // Return the pointer to the incremental link info for the archive.
+  Incremental_archive_entry*
+  incremental_info() const
+  { return this->incremental_info_; }
+
   // When we see a symbol in an archive we might decide to include the member,
   // not include the member or be undecided. This enum represents these
   // possibilities.
@@ -180,6 +191,69 @@ class Archive
                         Symbol** symp, std::string* why, char** tmpbufp,
                         size_t* tmpbuflen);
 
+ private:
+  struct Armap_entry;
+
+ public:
+  // Iterator class for unused global symbols.  This iterator is used
+  // for incremental links.
+
+  class Unused_symbol_iterator
+  {
+   public:
+    Unused_symbol_iterator(Archive* arch,
+                           std::vector<Armap_entry>::const_iterator it)
+      : arch_(arch), it_(it)
+    { this->skip_used_symbols(); }
+
+    const char*
+    operator*() const
+    { return this->arch_->armap_names_.data() + this->it_->name_offset; }
+
+    Unused_symbol_iterator&
+    operator++()
+    {
+      ++this->it_;
+      this->skip_used_symbols();
+      return *this;
+    }
+
+    bool
+    operator==(const Unused_symbol_iterator p) const
+    { return this->it_ == p.it_; }
+
+    bool
+    operator!=(const Unused_symbol_iterator p) const
+    { return this->it_ != p.it_; }
+
+   private:
+    // Skip over symbols defined by members that have been included.
+    void
+    skip_used_symbols()
+    {
+      while (this->it_ != this->arch_->armap_.end()
+            && (this->arch_->seen_offsets_.find(this->it_->file_offset)
+                != this->arch_->seen_offsets_.end()))
+       ++it_;
+    }
+
+    // The underlying archive.
+    Archive* arch_;
+
+    // The underlying iterator over all entries in the archive map.
+    std::vector<Armap_entry>::const_iterator it_;
+  };
+
+  // Return an iterator referring to the first unused symbol.
+  Unused_symbol_iterator
+  unused_symbols_begin()
+  { return Unused_symbol_iterator(this, this->armap_.begin()); }
+
+  // Return an iterator referring to the end of the unused symbols.
+  Unused_symbol_iterator
+  unused_symbols_end()
+  { return Unused_symbol_iterator(this, this->armap_.end()); }
+
  private:
   Archive(const Archive&);
   Archive& operator=(const Archive&);
@@ -312,6 +386,8 @@ class Archive
   unsigned int num_members_;
   // True if we exclude this library archive from automatic export.
   bool no_export_;
+  // The incremental link information for this archive.
+  Incremental_archive_entry* incremental_info_;
 };
 
 // This class is used to read an archive and pick out the desired
index e174b9969b9a66b416caea2a132c0f870d606409..98555cdb14622a9c77c17888f90a5ac6effa3e14 100644 (file)
@@ -1,6 +1,6 @@
-// inremental.cc -- incremental linking test/deubg tool
+// incremental.cc -- incremental linking test/debug tool
 
-// Copyright 2009 Free Software Foundation, Inc.
+// Copyright 2009, 2010 Free Software Foundation, Inc.
 // Written by Rafael Avila de Espindola <rafael.espindola@gmail.com>
 
 // This file is part of gold.
@@ -32,6 +32,7 @@
 
 #include <stdio.h>
 #include <errno.h>
+#include <time.h>
 
 #include "incremental.h"
 
@@ -42,16 +43,52 @@ namespace gold
 
 using namespace gold;
 
+template<int size, bool big_endian>
+static typename Incremental_inputs_reader<size, big_endian>::
+    Incremental_input_entry_reader
+find_input_containing_global(
+    Incremental_inputs_reader<size, big_endian>& incremental_inputs,
+    unsigned int offset,
+    unsigned int* symndx)
+{
+  typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+  for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
+    {
+      typename Inputs_reader::Incremental_input_entry_reader input_file =
+         incremental_inputs.input_file(i);
+      if (input_file.type() != INCREMENTAL_INPUT_OBJECT
+          && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
+        continue;
+      unsigned int nsyms = input_file.get_global_symbol_count();
+      if (offset >= input_file.get_symbol_offset(0)
+          && offset < input_file.get_symbol_offset(nsyms))
+       {
+         *symndx = (offset - input_file.get_symbol_offset(0)) / 16;
+         return input_file;
+       }
+    }
+  gold_unreachable();
+}
+
 template<int size, bool big_endian>
 static void
-dump_incremental_inputs(const char* argv0,
-                        const char* filename, Incremental_binary* inc)
+dump_incremental_inputs(const char* argv0, const char* filename,
+                       Incremental_binary* inc)
 {
   bool t;
-  unsigned int strtab_shndx;
-  Incremental_binary::Location location;
-
-  t = inc->find_incremental_inputs_section(&location, &strtab_shndx);
+  unsigned int inputs_shndx;
+  unsigned int isymtab_shndx;
+  unsigned int irelocs_shndx;
+  unsigned int istrtab_shndx;
+  typedef Incremental_binary::Location Location;
+  typedef Incremental_binary::View View;
+  typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+  typedef typename Inputs_reader::Incremental_input_entry_reader Entry_reader;
+
+  // Find the .gnu_incremental_inputs, _symtab, _relocs, and _strtab sections.
+
+  t = inc->find_incremental_inputs_sections(&inputs_shndx, &isymtab_shndx,
+                                           &irelocs_shndx, &istrtab_shndx);
   if (!t)
     {
       fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0,
@@ -59,105 +96,306 @@ dump_incremental_inputs(const char* argv0,
       exit (1);
     }
 
-  Incremental_binary::View inputs_view(inc->view(location));
-  const unsigned char* p = inputs_view.data();
+  elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc);
+
+  // Get a view of the .gnu_incremental_inputs section.
+
+  Location inputs_location(elf_file.section_contents(inputs_shndx));
+  View inputs_view(inc->view(inputs_location));
+
+  // Get the .gnu_incremental_strtab section as a string table.
 
-  Incremental_inputs_header<size, big_endian> incremental_header(p);
+  Location istrtab_location(elf_file.section_contents(istrtab_shndx));
+  View istrtab_view(inc->view(istrtab_location));
+  elfcpp::Elf_strtab istrtab(istrtab_view.data(), istrtab_location.data_size);
 
-  const unsigned char* incremental_inputs_base =
-    (p + sizeof(Incremental_inputs_header_data));
+  // Create a reader object for the .gnu_incremental_inputs section.
 
-  if (incremental_header.get_version() != 1)
+  Incremental_inputs_reader<size, big_endian>
+      incremental_inputs(inputs_view.data(), istrtab);
+
+  if (incremental_inputs.version() != 1)
     {
       fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0,
-              filename, incremental_header.get_version());
+              filename, incremental_inputs.version());
       exit(1);
     }
 
-  elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc);
-
-  if (elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
+  const char* command_line = incremental_inputs.command_line();
+  if (command_line == NULL)
     {
       fprintf(stderr,
-              "%s: %s: invalid string table section %u (type %d != %d)\n",
-              argv0, filename, strtab_shndx,
-              elf_file.section_type(strtab_shndx), elfcpp::SHT_STRTAB);
+              "%s: %s: failed to get link command line\n",
+              argv0, filename);
       exit(1);
     }
+  printf("Link command line: %s\n", command_line);
 
-  Incremental_binary::Location
-    strtab_location(elf_file.section_contents(strtab_shndx));
+  printf("\nInput files:\n");
+  for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
+    {
+      typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+      typename Inputs_reader::Incremental_input_entry_reader input_file =
+         incremental_inputs.input_file(i);
+
+      const char* objname = input_file.filename();
+      if (objname == NULL)
+       {
+         fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
+                 argv0, filename, i);
+         exit(1);
+       }
+      printf("[%d] %s\n", i, objname);
+
+      Timespec mtime = input_file.get_mtime();
+      printf("    Timestamp: %llu.%09d  %s",
+            static_cast<unsigned long long>(mtime.seconds),
+            mtime.nanoseconds,
+            ctime(&mtime.seconds));
+
+      Incremental_input_type input_type = input_file.type();
+      printf("    Type: ");
+      switch (input_type)
+       {
+       case INCREMENTAL_INPUT_OBJECT:
+         {
+           printf("Object\n");
+           printf("    Input section count: %d\n",
+                  input_file.get_input_section_count());
+           printf("    Symbol count: %d\n",
+                  input_file.get_global_symbol_count());
+         }
+         break;
+       case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
+         {
+           printf("Archive member\n");
+           printf("    Input section count: %d\n",
+                  input_file.get_input_section_count());
+           printf("    Symbol count: %d\n",
+                  input_file.get_global_symbol_count());
+         }
+         break;
+       case INCREMENTAL_INPUT_ARCHIVE:
+         {
+           printf("Archive\n");
+           printf("    Member count: %d\n", input_file.get_member_count());
+           printf("    Unused symbol count: %d\n",
+                  input_file.get_unused_symbol_count());
+         }
+         break;
+       case INCREMENTAL_INPUT_SHARED_LIBRARY:
+         {
+           printf("Shared library\n");
+           printf("    Symbol count: %d\n",
+                  input_file.get_global_symbol_count());
+         }
+         break;
+       case INCREMENTAL_INPUT_SCRIPT:
+         printf("Linker script\n");
+         break;
+       default:
+         fprintf(stderr, "%s: invalid file type for object %u: %d\n",
+                 argv0, i, input_type);
+         exit(1);
+       }
+    }
 
-  Incremental_binary::View strtab_view(inc->view(strtab_location));
-  p = strtab_view.data();
+  printf("\nInput sections:\n");
+  for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
+    {
+      typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+      typedef typename Inputs_reader::Incremental_input_entry_reader
+          Entry_reader;
+
+      Entry_reader input_file(incremental_inputs.input_file(i));
+
+      if (input_file.type() != INCREMENTAL_INPUT_OBJECT
+         && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
+       continue;
+
+      const char* objname = input_file.filename();
+      if (objname == NULL)
+       {
+         fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
+                 argv0, filename, i);
+         exit(1);
+       }
+
+      printf("[%d] %s\n", i, objname);
+
+      printf("    %3s  %6s  %8s  %8s  %s\n",
+            "n", "outndx", "offset", "size", "name");
+      unsigned int nsections = input_file.get_input_section_count();
+      for (unsigned int shndx = 0; shndx < nsections; ++shndx)
+       {
+         typename Entry_reader::Input_section_info info(
+             input_file.get_input_section(shndx));
+         printf("    %3d  %6d  %8lld  %8lld  %s\n", shndx,
+                info.output_shndx,
+                static_cast<long long>(info.sh_offset),
+                static_cast<long long>(info.sh_size),
+                info.name);
+       }
+    }
 
-  elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
-  const char* command_line;
-  elfcpp::Elf_Word command_line_offset =
-    incremental_header.get_command_line_offset();
-  t = strtab.get_c_string(command_line_offset, &command_line);
+  printf("\nGlobal symbols per input file:\n");
+  for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
+    {
+      typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+      typedef typename Inputs_reader::Incremental_input_entry_reader
+          Entry_reader;
+
+      Entry_reader input_file(incremental_inputs.input_file(i));
+
+      if (input_file.type() != INCREMENTAL_INPUT_OBJECT
+         && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
+       continue;
+
+      const char* objname = input_file.filename();
+      if (objname == NULL)
+       {
+         fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
+                 argv0, filename, i);
+         exit(1);
+       }
+
+      printf("[%d] %s\n", i, objname);
+
+      unsigned int nsyms = input_file.get_global_symbol_count();
+      if (nsyms > 0)
+       printf("    %6s  %8s  %8s  %8s  %8s\n",
+              "outndx", "offset", "chain", "#relocs", "rbase");
+      for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
+       {
+         typename Entry_reader::Global_symbol_info info(
+             input_file.get_global_symbol_info(symndx));
+         printf("    %6d  %8d  %8d  %8d  %8d\n",
+                info.output_symndx,
+                input_file.get_symbol_offset(symndx),
+                info.next_offset,
+                info.reloc_count,
+                info.reloc_offset);
+       }
+    }
 
-  if (!t)
+  // Get a view of the .symtab section.
+
+  unsigned int symtab_shndx = elf_file.find_section_by_type(elfcpp::SHT_SYMTAB);
+  if (symtab_shndx == elfcpp::SHN_UNDEF)  // Not found.
     {
-      fprintf(stderr,
-              "%s: %s: failed to get link command line: %zu out of range\n",
-              argv0, filename,
-              static_cast<size_t>(command_line_offset));
-      exit(1);
+      fprintf(stderr, "%s: %s: no symbol table section\n", argv0, filename);
+      exit (1);
     }
+  Location symtab_location(elf_file.section_contents(symtab_shndx));
+  View symtab_view(inc->view(symtab_location));
 
-  printf("Link command line: %s\n", command_line);
+  // Get a view of the .strtab section.
 
-  printf("Input files:\n");
-  for (unsigned i = 0; i < incremental_header.get_input_file_count(); ++i)
+  unsigned int strtab_shndx = elf_file.section_link(symtab_shndx);
+  if (strtab_shndx == elfcpp::SHN_UNDEF
+      || strtab_shndx > elf_file.shnum()
+      || elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
     {
-      const unsigned char* input_p = incremental_inputs_base +
-        i * sizeof(Incremental_inputs_entry_data);
-      Incremental_inputs_entry<size, big_endian> input(input_p);
-      const char* objname;
+      fprintf(stderr, "%s: %s: no string table section\n", argv0, filename);
+      exit (1);
+    }
+  Location strtab_location(elf_file.section_contents(strtab_shndx));
+  View strtab_view(inc->view(strtab_location));
+  elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
+
+  // Get a view of the .gnu_incremental_symtab section.
 
-      t = strtab.get_c_string(input.get_filename_offset(), &objname);
-      if (!t)
+  Location isymtab_location(elf_file.section_contents(isymtab_shndx));
+  View isymtab_view(inc->view(isymtab_location));
+
+  // Get a view of the .gnu_incremental_relocs section.
+
+  Location irelocs_location(elf_file.section_contents(irelocs_shndx));
+  View irelocs_view(inc->view(irelocs_location));
+
+  // The .gnu_incremental_symtab section contains entries that parallel
+  // the global symbols of the main symbol table.  The sh_info field
+  // of the main symbol table's section header tells us how many global
+  // symbols there are, but that count does not include any global
+  // symbols that were forced local during the link.  Therefore, we
+  // use the size of the .gnu_incremental_symtab section to deduce
+  // the number of global symbols + forced-local symbols there are
+  // in the symbol table.
+  unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  unsigned int nsyms = symtab_location.data_size / sym_size;
+  unsigned int nglobals = isymtab_location.data_size / 4;
+  unsigned int first_global = nsyms - nglobals;
+  unsigned const char* sym_p = symtab_view.data() + first_global * sym_size;
+  unsigned const char* isym_p = isymtab_view.data();
+
+  Incremental_symtab_reader<big_endian> isymtab(isymtab_view.data());
+  Incremental_relocs_reader<size, big_endian> irelocs(irelocs_view.data());
+
+  printf("\nGlobal symbol table:\n");
+  for (unsigned int i = 0; i < nglobals; i++)
+    {
+      elfcpp::Sym<size, big_endian> sym(sym_p);
+      const char* symname;
+      if (!strtab.get_c_string(sym.get_st_name(), &symname))
+       symname = "<unknown>";
+      printf("[%d] %s\n", first_global + i, symname);
+      unsigned int offset = isymtab.get_list_head(i);
+      while (offset > 0)
         {
-          fprintf(stderr,"%s: %s: failed to get file name for object %u:"
-                  " %zu out of range\n", argv0, filename, i,
-                  static_cast<size_t>(input.get_filename_offset()));
-          exit(1);
-        }
-      printf("  %s\n", objname);
-      printf("    Timestamp sec = %llu\n",
-             static_cast<unsigned long long>(input.get_timestamp_sec()));
-      printf("    Timestamp nsec = %d\n", input.get_timestamp_nsec());
-      printf("    Type = ");
-      // TODO: print the data at input->data_offset once we have it.
-      elfcpp::Elf_Word input_type = input.get_input_type();
-      switch (input_type)
-      {
-      case INCREMENTAL_INPUT_OBJECT:
-        printf("Object\n");
-        break;
-      case INCREMENTAL_INPUT_ARCHIVE:
-        printf("Archive\n");
-        break;
-      case INCREMENTAL_INPUT_SHARED_LIBRARY:
-        printf("Shared library\n");
-        break;
-      case INCREMENTAL_INPUT_SCRIPT:
-        printf("Linker script\n");
-        if (input.get_data_offset() != 0)
-          {
-            fprintf(stderr,"%s: %s: %u is a script but offset is not zero",
-                    argv0, filename, i);
-            exit(1);
-          }
-        break;
-      case INCREMENTAL_INPUT_INVALID:
-      default:
-        fprintf(stderr, "%s: invalid file type for object %u: %d\n",
-                argv0, i, input_type);
-        exit(1);
-      }
+         unsigned int sym_ndx;
+         Entry_reader input_file =
+             find_input_containing_global<size, big_endian>(incremental_inputs,
+                                                            offset, &sym_ndx);
+         typename Entry_reader::Global_symbol_info sym_info(
+             input_file.get_global_symbol_info(sym_ndx));
+         printf("    %s (first reloc: %d, reloc count: %d)",
+                input_file.filename(), sym_info.reloc_offset,
+                sym_info.reloc_count);
+         if (sym_info.output_symndx != first_global + i)
+           printf(" ** wrong output symndx (%d) **", sym_info.output_symndx);
+         printf("\n");
+         // Dump the relocations from this input file for this symbol.
+         unsigned int r_off = sym_info.reloc_offset;
+         for (unsigned int j = 0; j < sym_info.reloc_count; j++)
+           {
+             printf("      %4d  relocation type %3d  shndx %d"
+                    "  offset %016llx  addend %016llx  %s\n",
+                    r_off,
+                    irelocs.get_r_type(r_off),
+                    irelocs.get_r_shndx(r_off),
+                    static_cast<long long>(irelocs.get_r_offset(r_off)),
+                    static_cast<long long>(irelocs.get_r_addend(r_off)),
+                    symname);
+             r_off += irelocs.reloc_size;
+           }
+         offset = sym_info.next_offset;
+       }
+      sym_p += sym_size;
+      isym_p += 4;
     }
+
+  printf("\nUnused archive symbols:\n");
+  for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
+    {
+      Entry_reader input_file(incremental_inputs.input_file(i));
+
+      if (input_file.type() != INCREMENTAL_INPUT_ARCHIVE)
+       continue;
+
+      const char* objname = input_file.filename();
+      if (objname == NULL)
+       {
+         fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
+                 argv0, filename, i);
+         exit(1);
+       }
+
+      printf("[%d] %s\n", i, objname);
+      unsigned int nsyms = input_file.get_unused_symbol_count();
+      for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
+        printf("    %s\n", input_file.get_unused_symbol(symndx));
+    }
+
 }
 
 int
index 01be470dbea674001cc3927001d8ebec51e33207..b279c72ead39fba5cd1570c52e9359a953b2d03b 100644 (file)
@@ -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.
index a94f39719c961c864880aa515a2c423357eb62dd..6fb1a324e74ec91e99ccd41ef13061dd2ae0b569 100644 (file)
@@ -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.
index 3a01e92740938f9fca88dab27690c96d04cc935a..eb1322ae6affdfd82cb38ecdcdf6349ad9436ce0 100644 (file)
@@ -974,7 +974,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
       if (this->debug_abbrev_)
         this->debug_info_->set_abbreviations(this->debug_abbrev_);
     }
- else
 else
     {
       // FIXME: const_cast is ugly.
       Target* target = const_cast<Target*>(&parameters->target());
@@ -1886,12 +1886,6 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
       this->set_dynamic_symbol_size(symtab);
     }
   
-  if (this->incremental_inputs_)
-    {
-      this->incremental_inputs_->finalize();
-      this->create_incremental_info_sections();
-    }
-
   // Create segment headers.
   Output_segment_headers* segment_headers =
     (parameters->options().relocatable()
@@ -1951,6 +1945,13 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   // be called after the symbol table has been finalized.
   this->script_options_->finalize_symbols(symtab, this);
 
+  // Create the incremental inputs sections.
+  if (this->incremental_inputs_)
+    {
+      this->incremental_inputs_->finalize();
+      this->create_incremental_info_sections(symtab);
+    }
+
   // Create the .shstrtab section.
   Output_section* shstrtab_section = this->create_shstrtab();
 
@@ -1968,8 +1969,13 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   // If there are no sections which require postprocessing, we can
   // handle the section names now, and avoid a resize later.
   if (!this->any_postprocessing_sections_)
-    off = this->set_section_offsets(off,
+    {
+      off = this->set_section_offsets(off,
+                                     POSTPROCESSING_SECTIONS_PASS);
+      off =
+         this->set_section_offsets(off,
                                    STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS);
+    }
 
   file_header->set_section_info(this->section_headers_, shstrtab_section);
 
@@ -2294,37 +2300,65 @@ Layout::link_stabs_sections()
     }
 }
 
-// Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed
+// Create .gnu_incremental_inputs and related sections needed
 // for the next run of incremental linking to check what has changed.
 
 void
-Layout::create_incremental_info_sections()
+Layout::create_incremental_info_sections(Symbol_table* symtab)
 {
-  gold_assert(this->incremental_inputs_ != NULL);
+  Incremental_inputs* incr = this->incremental_inputs_;
+
+  gold_assert(incr != NULL);
+
+  // Create the .gnu_incremental_inputs, _symtab, and _relocs input sections.
+  incr->create_data_sections(symtab);
 
   // Add the .gnu_incremental_inputs section.
   const char *incremental_inputs_name =
     this->namepool_.add(".gnu_incremental_inputs", false, NULL);
-  Output_section* inputs_os =
+  Output_section* incremental_inputs_os =
     this->make_output_section(incremental_inputs_name,
                              elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0,
                              ORDER_INVALID, false);
-  Output_section_data* posd =
-      this->incremental_inputs_->create_incremental_inputs_section_data();
-  inputs_os->add_output_section_data(posd);
-  
+  incremental_inputs_os->add_output_section_data(incr->inputs_section());
+
+  // Add the .gnu_incremental_symtab section.
+  const char *incremental_symtab_name =
+    this->namepool_.add(".gnu_incremental_symtab", false, NULL);
+  Output_section* incremental_symtab_os =
+    this->make_output_section(incremental_symtab_name,
+                             elfcpp::SHT_GNU_INCREMENTAL_SYMTAB, 0,
+                             ORDER_INVALID, false);
+  incremental_symtab_os->add_output_section_data(incr->symtab_section());
+  incremental_symtab_os->set_entsize(4);
+
+  // Add the .gnu_incremental_relocs section.
+  const char *incremental_relocs_name =
+    this->namepool_.add(".gnu_incremental_relocs", false, NULL);
+  Output_section* incremental_relocs_os =
+    this->make_output_section(incremental_relocs_name,
+                             elfcpp::SHT_GNU_INCREMENTAL_RELOCS, 0,
+                             ORDER_INVALID, false);
+  incremental_relocs_os->add_output_section_data(incr->relocs_section());
+  incremental_relocs_os->set_entsize(incr->relocs_entsize());
+
   // Add the .gnu_incremental_strtab section.
   const char *incremental_strtab_name =
     this->namepool_.add(".gnu_incremental_strtab", false, NULL);
-  Output_section* strtab_os = this->make_output_section(incremental_strtab_name,
-                                                        elfcpp::SHT_STRTAB,
-                                                        0, ORDER_INVALID,
-                                                       false);
+  Output_section* incremental_strtab_os = this->make_output_section(incremental_strtab_name,
+                                                        elfcpp::SHT_STRTAB, 0,
+                                                        ORDER_INVALID, false);
   Output_data_strtab* strtab_data =
-    new Output_data_strtab(this->incremental_inputs_->get_stringpool());
-  strtab_os->add_output_section_data(strtab_data);
-  
-  inputs_os->set_link_section(strtab_data);
+      new Output_data_strtab(incr->get_stringpool());
+  incremental_strtab_os->add_output_section_data(strtab_data);
+
+  incremental_inputs_os->set_after_input_sections();
+  incremental_symtab_os->set_after_input_sections();
+  incremental_relocs_os->set_after_input_sections();
+
+  incremental_inputs_os->set_link_section(incremental_strtab_os);
+  incremental_symtab_os->set_link_section(incremental_inputs_os);
+  incremental_relocs_os->set_link_section(incremental_inputs_os);
 }
 
 // Return whether SEG1 should be before SEG2 in the output file.  This
index 6a3a16c6f50f8c8c0b096a5e9bb046195307e58c..87ee09ed961d5105e991f1d06370e996d6e441b5 100644 (file)
@@ -1,6 +1,6 @@
 // layout.h -- lay out output file sections for gold  -*- C++ -*-
 
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -58,6 +58,7 @@ class Output_reduced_debug_abbrev_section;
 class Output_reduced_debug_info_section;
 class Eh_frame;
 class Target;
+struct Timespec;
 
 // Return TRUE if SECNAME is the name of a compressed debug section.
 extern bool
@@ -662,7 +663,7 @@ class Layout
   // Return the object managing inputs in incremental build. NULL in
   // non-incremental builds.
   Incremental_inputs*
-  incremental_inputs()
+  incremental_inputs() const
   { return this->incremental_inputs_; }
 
   // For the target-specific code to add dynamic tags which are common
@@ -800,7 +801,7 @@ class Layout
   // Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed
   // for the next run of incremental linking to check what has changed.
   void
-  create_incremental_info_sections();
+  create_incremental_info_sections(Symbol_table*);
 
   // Find the first read-only PT_LOAD segment, creating one if
   // necessary.
index 631f1ac2d2c263cb7e34ebc9c07ac300b232c14c..91d519336910a0e42b622dd2534b92cb449dc659 100644 (file)
@@ -229,10 +229,7 @@ main(int argc, char** argv)
                &command_line.script_options());
 
   if (layout.incremental_inputs() != NULL)
-    {
-      layout.incremental_inputs()->report_command_line(argc, argv);
-      layout.incremental_inputs()->report_inputs(command_line.inputs());
-    }
+    layout.incremental_inputs()->report_command_line(argc, argv);
 
   if (parameters->options().section_ordering_file())
     layout.read_layout_from_file();
index 1bf73677f62e93e4f7dad294ed13f311784ebf54..b3d987056c73119633a51498818c489b84520392 100644 (file)
@@ -40,6 +40,7 @@
 #include "dynobj.h"
 #include "plugin.h"
 #include "compressed_output.h"
+#include "incremental.h"
 
 namespace gold
 {
@@ -346,6 +347,30 @@ Relobj::is_section_name_included(const char* name)
   return false;
 }
 
+// Finalize the incremental relocation information.  Allocates a block
+// of relocation entries for each symbol, and sets the reloc_bases_
+// array to point to the first entry in each block.  Returns the next
+// available reloation index.
+
+void
+Relobj::finalize_incremental_relocs(Layout* layout)
+{
+  unsigned int nsyms = this->get_global_symbols()->size();
+  this->reloc_bases_ = new unsigned int[nsyms];
+
+  gold_assert(this->reloc_bases_ != NULL);
+  gold_assert(layout->incremental_inputs() != NULL);
+
+  unsigned int rindex = layout->incremental_inputs()->get_reloc_count();
+  for (unsigned int i = 0; i < nsyms; ++i)
+    {
+      this->reloc_bases_[i] = rindex;
+      rindex += this->reloc_counts_[i];
+      this->reloc_counts_[i] = 0;
+    }
+  layout->incremental_inputs()->set_reloc_count(rindex);
+}
+
 // Class Sized_relobj.
 
 template<int size, bool big_endian>
@@ -1237,6 +1262,13 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
                }
            }
 
+         // Add the section to the incremental inputs layout.
+         Incremental_inputs* incremental_inputs = layout->incremental_inputs();
+         if (incremental_inputs != NULL)
+           incremental_inputs->report_input_section(this, i,
+                                                    discard ? NULL : name,
+                                                    shdr.get_sh_size());
+
           if (discard)
             {
              // Do not include this section in the link.
index 59b723fab40d802c918f141fdef28fc7bccf11a1..99ceabfb448734ffbfbaf31faa45eb164d89babf 100644 (file)
@@ -387,6 +387,18 @@ class Object
   section_addralign(unsigned int shndx)
   { return this->do_section_addralign(shndx); }
 
+  // Return the output section given a section index.
+  Output_section*
+  output_section(unsigned int shndx) const
+  { return this->do_output_section(shndx); }
+
+  // Given a section index, return the offset in the Output_section.
+  // The return value will be -1U if the section is specially mapped,
+  // such as a merge section.
+  uint64_t
+  output_section_offset(unsigned int shndx) const
+  { return this->do_output_section_offset(shndx); }
+
   // Read the symbol information.
   void
   read_symbols(Read_symbols_data* sd)
@@ -525,6 +537,16 @@ class Object
                        section_size_type* uncompressed_size) const
   { return this->do_section_is_compressed(shndx, uncompressed_size); }
 
+  // Return the index of the first incremental relocation for symbol SYMNDX.
+  unsigned int
+  get_incremental_reloc_base(unsigned int symndx) const
+  { return this->do_get_incremental_reloc_base(symndx); }
+
+  // Return the number of incremental relocations for symbol SYMNDX.
+  unsigned int
+  get_incremental_reloc_count(unsigned int symndx) const
+  { return this->do_get_incremental_reloc_count(symndx); }
+
  protected:
   // Returns NULL for Objects that are not plugin objects.  This method
   // is overridden in the Pluginobj class.
@@ -590,6 +612,17 @@ class Object
   virtual uint64_t
   do_section_addralign(unsigned int shndx) = 0;
 
+  // Return the output section given a section index--implemented
+  // by child class.
+  virtual Output_section*
+  do_output_section(unsigned int) const
+  { gold_unreachable(); }
+
+  // Get the offset of a section--implemented by child class.
+  virtual uint64_t
+  do_output_section_offset(unsigned int) const
+  { gold_unreachable(); }
+
   // Return the Xindex structure to use.
   virtual Xindex*
   do_initialize_xindex() = 0;
@@ -641,6 +674,18 @@ class Object
   do_section_is_compressed(unsigned int, section_size_type*) const
   { return false; }
 
+  // Return the index of the first incremental relocation for symbol SYMNDX--
+  // implemented by child class.
+  virtual unsigned int
+  do_get_incremental_reloc_base(unsigned int) const
+  { gold_unreachable(); }
+
+  // Return the number of incremental relocations for symbol SYMNDX--
+  // implemented by child class.
+  virtual unsigned int
+  do_get_incremental_reloc_count(unsigned int) const
+  { gold_unreachable(); }
+
  private:
   // This class may not be copied.
   Object(const Object&);
@@ -685,7 +730,9 @@ class Relobj : public Object
       map_to_relocatable_relocs_(NULL),
       object_merge_map_(NULL),
       relocs_must_follow_section_writes_(false),
-      sd_(NULL)
+      sd_(NULL),
+      reloc_counts_(NULL),
+      reloc_bases_(NULL)
   { }
 
   // During garbage collection, the Read_symbols_data pass for 
@@ -781,16 +828,6 @@ class Relobj : public Object
     return this->output_sections_[shndx] != NULL;
   }
 
-  // Given a section index, return the corresponding Output_section.
-  // The return value will be NULL if the section is not included in
-  // the link.
-  Output_section*
-  output_section(unsigned int shndx) const
-  {
-    gold_assert(shndx < this->output_sections_.size());
-    return this->output_sections_[shndx];
-  }
-
   // The the output section of the input section with index SHNDX.
   // This is only used currently to remove a section from the link in
   // relaxation.
@@ -801,13 +838,6 @@ class Relobj : public Object
     this->output_sections_[shndx] = os;
   }
   
-  // Given a section index, return the offset in the Output_section.
-  // The return value will be -1U if the section is specially mapped,
-  // such as a merge section.
-  uint64_t
-  output_section_offset(unsigned int shndx) const
-  { return this->do_output_section_offset(shndx); }
-
   // Set the offset of an input section within its output section.
   void
   set_section_offset(unsigned int shndx, uint64_t off)
@@ -856,6 +886,16 @@ class Relobj : public Object
   layout_deferred_sections(Layout* layout)
   { this->do_layout_deferred_sections(layout); }
 
+  // Return the index of the first incremental relocation for symbol SYMNDX.
+  virtual unsigned int
+  do_get_incremental_reloc_base(unsigned int symndx) const
+  { return this->reloc_bases_[symndx]; }
+
+  // Return the number of incremental relocations for symbol SYMNDX.
+  virtual unsigned int
+  do_get_incremental_reloc_count(unsigned int symndx) const
+  { return this->reloc_counts_[symndx]; }
+
  protected:
   // The output section to be used for each input section, indexed by
   // the input section number.  The output section is NULL if the
@@ -902,10 +942,6 @@ class Relobj : public Object
   virtual void
   do_relocate(const Symbol_table* symtab, const Layout*, Output_file* of) = 0;
 
-  // Get the offset of a section--implemented by child class.
-  virtual uint64_t
-  do_output_section_offset(unsigned int shndx) const = 0;
-
   // Set the offset of a section--implemented by child class.
   virtual void
   do_set_section_offset(unsigned int shndx, uint64_t off) = 0;
@@ -915,6 +951,16 @@ class Relobj : public Object
   virtual void
   do_layout_deferred_sections(Layout*) = 0;
 
+  // Given a section index, return the corresponding Output_section.
+  // The return value will be NULL if the section is not included in
+  // the link.
+  Output_section*
+  do_output_section(unsigned int shndx) const
+  {
+    gold_assert(shndx < this->output_sections_.size());
+    return this->output_sections_[shndx];
+  }
+
   // Return the vector mapping input sections to output sections.
   Output_sections&
   output_sections()
@@ -938,6 +984,46 @@ class Relobj : public Object
   set_relocs_must_follow_section_writes()
   { this->relocs_must_follow_section_writes_ = true; }
 
+  // Allocate the array for counting incremental relocations.
+  void
+  allocate_incremental_reloc_counts()
+  {
+    unsigned int nsyms = this->do_get_global_symbols()->size();
+    this->reloc_counts_ = new unsigned int[nsyms];
+    gold_assert(this->reloc_counts_ != NULL);
+    memset(this->reloc_counts_, 0, nsyms * sizeof(unsigned int));
+  }
+
+  // Record a relocation in this object referencing global symbol SYMNDX.
+  // Used for tracking incremental link information.
+  void
+  count_incremental_reloc(unsigned int symndx)
+  {
+    unsigned int nsyms = this->do_get_global_symbols()->size();
+    gold_assert(symndx < nsyms);
+    gold_assert(this->reloc_counts_ != NULL);
+    ++this->reloc_counts_[symndx];
+  }
+
+  // Finalize the incremental relocation information.
+  void
+  finalize_incremental_relocs(Layout* layout);
+
+  // Return the index of the next relocation to be written for global symbol
+  // SYMNDX.  Only valid after finalize_incremental_relocs() has been called.
+  unsigned int
+  next_incremental_reloc_index(unsigned int symndx)
+  {
+    unsigned int nsyms = this->do_get_global_symbols()->size();
+
+    gold_assert(this->reloc_counts_ != NULL);
+    gold_assert(this->reloc_bases_ != NULL);
+    gold_assert(symndx < nsyms);
+
+    unsigned int counter = this->reloc_counts_[symndx]++;
+    return this->reloc_bases_[symndx] + counter;
+  }
+
  private:
   // Mapping from input sections to output section.
   Output_sections output_sections_;
@@ -957,6 +1043,10 @@ class Relobj : public Object
   // Again used during garbage collection when laying out referenced
   // sections.
   gold::Symbols_data *sd_;
+  // Per-symbol counts of relocations, for incremental links.
+  unsigned int* reloc_counts_;
+  // Per-symbol base indexes of relocations, for incremental links.
+  unsigned int* reloc_bases_;
 };
 
 // This class is used to handle relocations against a section symbol
@@ -1792,7 +1882,8 @@ class Sized_relobj : public Relobj
   // This may be overriden by a child class.
   virtual void
   do_relocate_sections(const Symbol_table* symtab, const Layout* layout,
-                      const unsigned char* pshdrs, Views* pviews);
+                      const unsigned char* pshdrs, Output_file* of,
+                      Views* pviews);
 
   // Allow a child to set output local symbol count.
   void
@@ -1880,8 +1971,9 @@ class Sized_relobj : public Relobj
   // Relocate the sections in the output file.
   void
   relocate_sections(const Symbol_table* symtab, const Layout* layout,
-                   const unsigned char* pshdrs, Views* pviews)
-  { this->do_relocate_sections(symtab, layout, pshdrs, pviews); }
+                   const unsigned char* pshdrs, Output_file* of,
+                   Views* pviews)
+  { this->do_relocate_sections(symtab, layout, pshdrs, of, pviews); }
 
   // Scan the input relocations for --emit-relocs.
   void
@@ -1918,6 +2010,35 @@ class Sized_relobj : public Relobj
                      unsigned char* reloc_view,
                      section_size_type reloc_view_size);
 
+  // Scan the input relocations for --incremental.
+  void
+  incremental_relocs_scan(const Read_relocs_data::Relocs_list::iterator&);
+
+  // Scan the input relocations for --incremental, templatized on the
+  // type of the relocation section.
+  template<int sh_type>
+  void
+  incremental_relocs_scan_reltype(
+      const Read_relocs_data::Relocs_list::iterator&);
+
+  void
+  incremental_relocs_write(const Relocate_info<size, big_endian>*,
+                          unsigned int sh_type,
+                          const unsigned char* prelocs,
+                          size_t reloc_count,
+                          Output_section*,
+                          Address output_offset,
+                          Output_file*);
+
+  template<int sh_type>
+  void
+  incremental_relocs_write_reltype(const Relocate_info<size, big_endian>*,
+                                  const unsigned char* prelocs,
+                                  size_t reloc_count,
+                                  Output_section*,
+                                  Address output_offset,
+                                  Output_file*);
+
   // A type shared by split_stack_adjust_reltype and find_functions.
   typedef std::map<section_offset_type, section_size_type> Function_offsets;
 
index 1c86c03b422415647dec82a80c0b781ae55e24ab..468006701d9bb7a30ee83f64a61c8dfeb28a03ca 100644 (file)
@@ -451,7 +451,7 @@ Plugin_manager::add_input_file(const char *pathname, bool is_lib)
   Input_argument* input_argument = new Input_argument(file);
   Task_token* next_blocker = new Task_token(true);
   next_blocker->add_blocker();
-  if (this->layout_->incremental_inputs())
+  if (parameters->options().incremental())
     gold_error(_("input files added by plug-ins in --incremental mode not "
                 "supported yet"));
   this->workqueue_->queue_soon(new Read_symbols(this->input_objects_,
index d8af99bd39b0f48b6bc810f460409f9feb109424..1cec3b374631e4af91c37eb5c49eeaddff4d5ffc 100644 (file)
@@ -302,12 +302,6 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
                                      this->dirpath_, this);
          arch->setup();
 
-         if (this->layout_->incremental_inputs())
-           {
-             const Input_argument* ia = this->input_argument_;
-             this->layout_->incremental_inputs()->report_archive(ia, arch);
-           }
-
          // Unlock the archive so it can be used in the next task.
          arch->unlock(this);
 
@@ -389,12 +383,6 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
       Read_symbols_data* sd = new Read_symbols_data;
       obj->read_symbols(sd);
 
-      if (this->layout_->incremental_inputs())
-       {
-         const Input_argument* ia = this->input_argument_;
-         this->layout_->incremental_inputs()->report_object(ia, obj);
-       }
-
       // Opening the file locked it, so now we need to unlock it.  We
       // need to unlock it before queuing the Add_symbols task,
       // because the workqueue doesn't know about our lock on the
@@ -599,6 +587,10 @@ Add_symbols::run(Workqueue*)
     }
   else
     {
+      Incremental_inputs* incremental_inputs =
+          this->layout_->incremental_inputs();
+      if (incremental_inputs != NULL)
+       incremental_inputs->report_object(this->object_, NULL);
       this->object_->layout(this->symtab_, this->layout_, this->sd_);
       this->object_->add_symbols(this->symtab_, this->sd_, this->layout_);
       delete this->sd_;
@@ -688,11 +680,20 @@ Finish_group::run(Workqueue*)
        }
     }
 
-  // Delete all the archives now that we no longer need them.
+  // Now that we're done with the archives, record the incremental layout
+  // information, then delete them.
   for (Input_group::const_iterator p = this->input_group_->begin();
        p != this->input_group_->end();
        ++p)
-    delete *p;
+    {
+      // For an incremental link, finish recording the layout information.
+      Incremental_inputs* incremental_inputs =
+          this->layout_->incremental_inputs();
+      if (incremental_inputs != NULL)
+       incremental_inputs->report_archive_end(*p);
+
+      delete *p;
+    }
   delete this->input_group_;
 }
 
index 9f7355e441cd91196fadf24980330b6fe00e9335..89389888c3bdd80ba412134419603c2121c6a6d1 100644 (file)
@@ -25,6 +25,7 @@
 #include <algorithm>
 
 #include "workqueue.h"
+#include "layout.h"
 #include "symtab.h"
 #include "output.h"
 #include "merge.h"
@@ -33,6 +34,7 @@
 #include "reloc.h"
 #include "icf.h"
 #include "compressed_output.h"
+#include "incremental.h"
 
 namespace gold
 {
@@ -300,7 +302,8 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
                                   != 0);
       if (!is_section_allocated
          && !parameters->options().relocatable()
-         && !parameters->options().emit_relocs())
+         && !parameters->options().emit_relocs()
+         && !parameters->options().incremental())
        continue;
 
       if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx_)
@@ -424,6 +427,10 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
   else
     local_symbols = rd->local_symbols->data();
 
+  // For incremental links, allocate the counters for incremental relocations.
+  if (layout->incremental_inputs() != NULL)
+    this->allocate_incremental_reloc_counts();
+
   for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
        p != rd->relocs.end();
        ++p)
@@ -451,6 +458,8 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
                                local_symbols);
          if (parameters->options().emit_relocs())
            this->emit_relocs_scan(symtab, layout, local_symbols, p);
+         if (layout->incremental_inputs() != NULL)
+           this->incremental_relocs_scan(p);
        }
       else
        {
@@ -472,6 +481,10 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
       p->contents = NULL;
     }
 
+  // For incremental links, finalize the allocation of relocations.
+  if (layout->incremental_inputs() != NULL)
+    this->finalize_incremental_relocs(layout);
+
   if (rd->local_symbols != NULL)
     {
       delete rd->local_symbols;
@@ -567,6 +580,54 @@ Sized_relobj<size, big_endian>::emit_relocs_scan_reltype(
     rr);
 }
 
+// Scan the input relocations for --incremental.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_scan(
+    const Read_relocs_data::Relocs_list::iterator& p)
+{
+  if (p->sh_type == elfcpp::SHT_REL)
+    this->incremental_relocs_scan_reltype<elfcpp::SHT_REL>(p);
+  else
+    {
+      gold_assert(p->sh_type == elfcpp::SHT_RELA);
+      this->incremental_relocs_scan_reltype<elfcpp::SHT_RELA>(p);
+    }
+}
+
+// Scan the input relocation for --emit-relocs, templatized on the
+// type of the relocation section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_scan_reltype(
+    const Read_relocs_data::Relocs_list::iterator& p)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+  const unsigned char* prelocs = p->contents->data();
+  size_t reloc_count = p->reloc_count;
+
+  for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+    {
+      Reltype reloc(prelocs);
+
+      if (p->needs_special_offset_handling
+         && !p->output_section->is_input_address_mapped(this, p->data_shndx,
+                                                        reloc.get_r_offset()))
+       continue;
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+         reloc.get_r_info();
+      const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+
+      if (r_sym >= this->local_symbol_count_)
+       this->count_incremental_reloc(r_sym - this->local_symbol_count_);
+    }
+}
+
 // Relocate the input sections and write out the local symbols.
 
 template<int size, bool big_endian>
@@ -597,7 +658,7 @@ Sized_relobj<size, big_endian>::do_relocate(const Symbol_table* symtab,
 
   // Apply relocations.
 
-  this->relocate_sections(symtab, layout, pshdrs, &views);
+  this->relocate_sections(symtab, layout, pshdrs, of, &views);
 
   // After we've done the relocations, we release the hash tables,
   // since we no longer need them.
@@ -827,6 +888,7 @@ Sized_relobj<size, big_endian>::do_relocate_sections(
     const Symbol_table* symtab,
     const Layout* layout,
     const unsigned char* pshdrs,
+    Output_file* of,
     Views* pviews)
 {
   unsigned int shnum = this->shnum();
@@ -938,6 +1000,9 @@ Sized_relobj<size, big_endian>::do_relocate_sections(
            this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
                              os, output_offset, view, address, view_size,
                              (*pviews)[i].view, (*pviews)[i].view_size);
+         if (parameters->options().incremental())
+           this->incremental_relocs_write(&relinfo, sh_type, prelocs,
+                                          reloc_count, os, output_offset, of);
        }
       else
        {
@@ -1020,6 +1085,126 @@ Sized_relobj<size, big_endian>::emit_relocs_reltype(
     reloc_view_size);
 }
 
+// Write the incremental relocs.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_write(
+    const Relocate_info<size, big_endian>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    Address output_offset,
+    Output_file* of)
+{
+  if (sh_type == elfcpp::SHT_REL)
+    this->incremental_relocs_write_reltype<elfcpp::SHT_REL>(
+       relinfo,
+       prelocs,
+       reloc_count,
+       output_section,
+       output_offset,
+       of);
+  else
+    {
+      gold_assert(sh_type == elfcpp::SHT_RELA);
+      this->incremental_relocs_write_reltype<elfcpp::SHT_RELA>(
+         relinfo,
+         prelocs,
+         reloc_count,
+         output_section,
+         output_offset,
+         of);
+    }
+}
+
+// Write the incremental relocs, templatized on the type of the
+// relocation section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj<size, big_endian>::incremental_relocs_write_reltype(
+    const Relocate_info<size, big_endian>* relinfo,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    Address output_offset,
+    Output_file* of)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reloc;
+  const unsigned int reloc_size =
+      Reloc_types<sh_type, size, big_endian>::reloc_size;
+  const unsigned int sizeof_addr = size / 8;
+  const unsigned int incr_reloc_size = 8 + 2 * sizeof_addr;
+
+  unsigned int out_shndx = output_section->out_shndx();
+
+  // Get a view for the .gnu_incremental_relocs section.
+
+  Incremental_inputs* inputs = relinfo->layout->incremental_inputs();
+  gold_assert(inputs != NULL);
+  const off_t relocs_off = inputs->relocs_section()->offset();
+  const off_t relocs_size = inputs->relocs_section()->data_size();
+  unsigned char* const view = of->get_output_view(relocs_off, relocs_size);
+
+  for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+    {
+      Reloc reloc(prelocs);
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+      const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+      if (r_sym < this->local_symbol_count_)
+        continue;
+
+      // Get the new offset--the location in the output section where
+      // this relocation should be applied.
+
+      Address offset = reloc.get_r_offset();
+      if (output_offset != invalid_address)
+       offset += output_offset;
+      else
+       {
+          section_offset_type sot_offset =
+              convert_types<section_offset_type, Address>(offset);
+         section_offset_type new_sot_offset =
+             output_section->output_offset(relinfo->object,
+                                           relinfo->data_shndx,
+                                           sot_offset);
+         gold_assert(new_sot_offset != -1);
+         offset += new_sot_offset;
+       }
+
+      // Get the addend.
+      typename elfcpp::Elf_types<size>::Elf_Swxword addend;
+      if (sh_type == elfcpp::SHT_RELA)
+       addend =
+           Reloc_types<sh_type, size, big_endian>::get_reloc_addend(&reloc);
+      else
+        {
+          // FIXME: Get the addend for SHT_REL.
+          addend = 0;
+        }
+
+      // Get the index of the output relocation.
+
+      unsigned int reloc_index =
+          this->next_incremental_reloc_index(r_sym - this->local_symbol_count_);
+
+      // Write the relocation.
+
+      unsigned char* pov = view + reloc_index * incr_reloc_size;
+      elfcpp::Swap<32, big_endian>::writeval(pov, r_type);
+      elfcpp::Swap<32, big_endian>::writeval(pov + 4, out_shndx);
+      elfcpp::Swap<size, big_endian>::writeval(pov + 8, offset);
+      elfcpp::Swap<size, big_endian>::writeval(pov + 8 + sizeof_addr, addend);
+      of->write_output_view(pov - view, incr_reloc_size, view);
+    }
+}
+
 // Create merge hash tables for the local symbols.  These are used to
 // speed up relocations.
 
@@ -1556,6 +1741,7 @@ Sized_relobj<32, false>::do_relocate_sections(
     const Symbol_table* symtab,
     const Layout* layout,
     const unsigned char* pshdrs,
+    Output_file* of,
     Views* pviews);
 #endif
 
@@ -1566,6 +1752,7 @@ Sized_relobj<32, true>::do_relocate_sections(
     const Symbol_table* symtab,
     const Layout* layout,
     const unsigned char* pshdrs,
+    Output_file* of,
     Views* pviews);
 #endif
 
@@ -1576,6 +1763,7 @@ Sized_relobj<64, false>::do_relocate_sections(
     const Symbol_table* symtab,
     const Layout* layout,
     const unsigned char* pshdrs,
+    Output_file* of,
     Views* pviews);
 #endif
 
@@ -1586,6 +1774,7 @@ Sized_relobj<64, true>::do_relocate_sections(
     const Symbol_table* symtab,
     const Layout* layout,
     const unsigned char* pshdrs,
+    Output_file* of,
     Views* pviews);
 #endif
 
index e0b9359abdc03adabc3757f04bf045c6bfed1a87..d09781a80b13d23d64d69eb467c816f1fa01e21e 100644 (file)
@@ -1462,16 +1462,16 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout,
       this_blocker = nb;
     }
 
-  if (layout->incremental_inputs())
+  if (layout->incremental_inputs() != NULL)
     {
-      // Like new Read_symbols(...) above, we rely on close.inputs()
+      // Like new Read_symbols(...) above, we rely on closure.inputs()
       // getting leaked by closure.
+      const std::string& filename = input_file->filename();
       Script_info* info = new Script_info(closure.inputs());
-      layout->incremental_inputs()->report_script(
-          input_argument,
-          input_file->file().get_mtime(),
-          info);
+      Timespec mtime = input_file->file().get_mtime();
+      layout->incremental_inputs()->report_script(filename, info, mtime);
     }
+
   *used_next_blocker = true;
 
   return true;
index 8178e2c605373f05a882a964a368304c401ef0d4..4e5b7b05ab95db4dc02fe3bb6a1cc811008f7d63 100644 (file)
@@ -1468,6 +1468,16 @@ class Symbol_table
   compute_final_value(const Sized_symbol<size>* sym,
                      Compute_final_value_status* pstatus) const;
 
+  // Return the index of the first global symbol.
+  unsigned int
+  first_global_index() const
+  { return this->first_global_index_; }
+
+  // Return the total number of symbols in the symbol table.
+  unsigned int
+  output_count() const
+  { return this->output_count_; }
+
   // Write out the global symbols.
   void
   write_globals(const Stringpool*, const Stringpool*,