public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [gold patch] Incremental 11/18: update GOT/PLT
@ 2011-04-01 21:36 Cary Coutant
  2011-05-18 18:50 ` Cary Coutant
  2011-05-21 16:52 ` Ian Lance Taylor
  0 siblings, 2 replies; 4+ messages in thread
From: Cary Coutant @ 2011-04-01 21:36 UTC (permalink / raw)
  To: Ian Lance Taylor, Binutils

[-- Attachment #1: Type: text/plain, Size: 4462 bytes --]

This patch adds the support for incremental updates to the GOT and
PLT. In the incremental info for the GOT entries, I changed it to
store an input file index instead of the offset of the input file
entry so that it would be easier to tell whether a local GOT entry was
still in use or available for reuse. For the many similar methods in
class Output_data_got, I refactored the common code into add_got_entry
and add_got_entry_pair. I added two target-specific hooks for managing
the GOT and PLT during an incremental update.

-cary


	* gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
	* incremental-dump.cc (dump_incremental_inputs): Mask high-order
	bit when checking got_type.
	* incremental.cc (Sized_incremental_binary::setup_readers):
	Store symbol table and string table locations; initialize bit vector
	of file status flags.
	(Sized_incremental_binary::do_reserve_layout): Set bit flag for
	unchanged files.
	(Sized_incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::get_symtab_view): Use stored locations.
	(Output_section_incremental_inputs::set_final_data_size): Record
	file index for each input file.
	(Output_section_incremental_inputs::write_got_plt): Store file index
	instead of input entry offset for each GOT entry.
	* incremental.h
	(Incremental_input_entry::Incremental_input_entry): Initialize new
	data member.
	(Incremental_input_entry::set_offset): Store file index.
	(Incremental_input_entry::get_file_index): New function.
	(Incremental_input_entry::file_index_): New data member.
	(Incremental_binary::process_got_plt): New function.
	(Incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::Sized_incremental_binary): Initialize new
	data members.
	(Sized_incremental_binary::~Sized_incremental_binary): New destructor.
	(Sized_incremental_binary::set_file_is_unchanged): New function.
	(Sized_incremental_binary::file_is_unchanged): New function.
	(Sized_incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::file_status_): New data member.
	(Sized_incremental_binary::main_symtab_loc_): New data member.
	(Sized_incremental_binary::main_strtab_loc_): New data member.
	* output.cc (Output_data_got::Got_entry::write): Add case
	RESERVED_CODE.
	(Output_data_got::add_global): Call add_got_entry.
	(Output_data_got::add_global_plt): Likewise.
	(Output_data_got::add_global_with_rel): Likewise.
	(Output_data_got::add_global_with_rela): Likewise.
	(Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair.
	(Output_data_got::add_global_pair_with_rela): Likewise.
	(Output_data_got::add_local): Call add_got_entry.
	(Output_data_got::add_local_plt): Likewise.
	(Output_data_got::add_local_with_rel): Likewise.
	(Output_data_got::add_local_with_rela): Likewise.
	(Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair.
	(Output_data_got::add_local_pair_with_rela): Likewise.
	(Output_data_got::reserve_slot): New function.
	(Output_data_got::reserve_slot_for_global): New function.
	(Output_section::add_output_section_data): Edit FIXME.
	* output.h
	(Output_section_data_build::Output_section_data_build): New
	constructor with size parameter.
	(Output_data_space::Output_data_space): Likewise.
	(Output_data_got::Output_data_got): Initialize new data member; new
	constructor with size parameter.
	(Output_data_got::add_constant): Call add_got_entry.
	(Output_data_got::reserve_slot): New function.
	(Output_data_got::reserve_slot_for_global): New function.
	(class Output_data_got::Got_entry): Add RESERVED_CODE.
	(Output_data_got::add_got_entry): New function.
	(Output_data_got::add_got_entry_pair): New function.
	(Output_data_got::free_list_): New data member.
	* target.h (Sized_target::init_got_plt_for_update): New function.
	(Sized_target::register_global_plt_entry): New function.
	* x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
	Initialize new data member; call init; add constructor with PLT count.
	(Output_data_plt_x86_64::init): New function.
	(Output_data_plt_x86_64::add_relocation): New function.
	(Output_data_plt_x86_64::reserve_slot): New function.
	(Output_data_plt_x86_64::free_list_): New data member.
	(Target_x86_64::init_got_plt_for_update): New function.
	(Target_x86_64::register_global_plt_entry): New function.
	(Output_data_plt_x86_64::add_entry): Allocate from free list for
	incremental updates.
	(Output_data_plt_x86_64::add_relocation): New function.

[-- Attachment #2: incr-patch-11.txt --]
[-- Type: text/plain, Size: 43912 bytes --]

Add incremental update support for GOT/PLT.

2011-04-01 Cary Coutant  <ccoutant@google.com>

	* gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
	* incremental-dump.cc (dump_incremental_inputs): Mask high-order
	bit when checking got_type.
	* incremental.cc (Sized_incremental_binary::setup_readers):
	Store symbol table and string table locations; initialize bit vector
	of file status flags.
	(Sized_incremental_binary::do_reserve_layout): Set bit flag for
	unchanged files.
	(Sized_incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::get_symtab_view): Use stored locations.
	(Output_section_incremental_inputs::set_final_data_size): Record
	file index for each input file.
	(Output_section_incremental_inputs::write_got_plt): Store file index
	instead of input entry offset for each GOT entry.
	* incremental.h
	(Incremental_input_entry::Incremental_input_entry): Initialize new
	data member.
	(Incremental_input_entry::set_offset): Store file index.
	(Incremental_input_entry::get_file_index): New function.
	(Incremental_input_entry::file_index_): New data member.
	(Incremental_binary::process_got_plt): New function.
	(Incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::Sized_incremental_binary): Initialize new
	data members.
	(Sized_incremental_binary::~Sized_incremental_binary): New destructor.
	(Sized_incremental_binary::set_file_is_unchanged): New function.
	(Sized_incremental_binary::file_is_unchanged): New function.
	(Sized_incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::file_status_): New data member.
	(Sized_incremental_binary::main_symtab_loc_): New data member.
	(Sized_incremental_binary::main_strtab_loc_): New data member.
	* output.cc (Output_data_got::Got_entry::write): Add case
	RESERVED_CODE.
	(Output_data_got::add_global): Call add_got_entry.
	(Output_data_got::add_global_plt): Likewise.
	(Output_data_got::add_global_with_rel): Likewise.
	(Output_data_got::add_global_with_rela): Likewise.
	(Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair.
	(Output_data_got::add_global_pair_with_rela): Likewise.
	(Output_data_got::add_local): Call add_got_entry.
	(Output_data_got::add_local_plt): Likewise.
	(Output_data_got::add_local_with_rel): Likewise.
	(Output_data_got::add_local_with_rela): Likewise.
	(Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair.
	(Output_data_got::add_local_pair_with_rela): Likewise.
	(Output_data_got::reserve_slot): New function.
	(Output_data_got::reserve_slot_for_global): New function.
	(Output_section::add_output_section_data): Edit FIXME.
	* output.h
	(Output_section_data_build::Output_section_data_build): New
	constructor with size parameter.
	(Output_data_space::Output_data_space): Likewise.
	(Output_data_got::Output_data_got): Initialize new data member; new
	constructor with size parameter.
	(Output_data_got::add_constant): Call add_got_entry.
	(Output_data_got::reserve_slot): New function.
	(Output_data_got::reserve_slot_for_global): New function.
	(class Output_data_got::Got_entry): Add RESERVED_CODE.
	(Output_data_got::add_got_entry): New function.
	(Output_data_got::add_got_entry_pair): New function.
	(Output_data_got::free_list_): New data member.
	* target.h (Sized_target::init_got_plt_for_update): New function.
	(Sized_target::register_global_plt_entry): New function.
	* x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
	Initialize new data member; call init; add constructor with PLT count.
	(Output_data_plt_x86_64::init): New function.
	(Output_data_plt_x86_64::add_relocation): New function.
	(Output_data_plt_x86_64::reserve_slot): New function.
	(Output_data_plt_x86_64::free_list_): New data member.
	(Target_x86_64::init_got_plt_for_update): New function.
	(Target_x86_64::register_global_plt_entry): New function.
	(Output_data_plt_x86_64::add_entry): Allocate from free list for
	incremental updates.
	(Output_data_plt_x86_64::add_relocation): New function.


diff --git a/gold/gold.cc b/gold/gold.cc
index 7d17d3f..84008ca 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -632,6 +632,13 @@ queue_middle_tasks(const General_options& options,
 	}
     }
 
+  // For incremental updates, record the existing GOT and PLT entries.
+  if (parameters->incremental_update())
+    {
+      Incremental_binary* ibase = layout->incremental_base();
+      ibase->process_got_plt(symtab, layout);
+    }
+
   if (is_debugging_enabled(DEBUG_SCRIPT))
     layout->script_options()->print(stderr);
 
diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc
index 5ac6e6c..eecf8a8 100644
--- a/gold/incremental-dump.cc
+++ b/gold/incremental-dump.cc
@@ -370,7 +370,7 @@ dump_incremental_inputs(const char* argv0, const char* filename,
       unsigned int got_type = igot_plt.get_got_type(i);
       unsigned int got_desc = igot_plt.get_got_desc(i);
       printf("[%d] type %02x, ", i, got_type & 0x7f);
-      if (got_type == 0x7f)
+      if ((got_type & 0x7f) == 0x7f)
 	printf("reserved");
       else if (got_type & 0x80)
 	{
diff --git a/gold/incremental.cc b/gold/incremental.cc
index f5e6bf7..0d335e0 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -258,6 +258,19 @@ Sized_incremental_binary<size, big_endian>::setup_readers()
   this->got_plt_reader_ =
       Incremental_got_plt_reader<big_endian>(got_plt_view.data());
 
+  // Find the main symbol table.
+  unsigned int main_symtab_shndx =
+      this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB);
+  gold_assert(main_symtab_shndx != elfcpp::SHN_UNDEF);
+  this->main_symtab_loc_ = this->elf_file_.section_contents(main_symtab_shndx);
+
+  // Find the main symbol string table.
+  unsigned int main_strtab_shndx =
+      this->elf_file_.section_link(main_symtab_shndx);
+  gold_assert(main_strtab_shndx != elfcpp::SHN_UNDEF
+              && main_strtab_shndx < this->elf_file_.shnum());
+  this->main_strtab_loc_ = this->elf_file_.section_contents(main_strtab_shndx);
+
   // Walk the list of input files (a) to setup an Input_reader for each
   // input file, and (b) to record maps of files added from archive
   // libraries and scripts.
@@ -314,6 +327,10 @@ Sized_incremental_binary<size, big_endian>::setup_readers()
   unsigned int nglobals = this->symtab_reader_.symbol_count();
   this->symbol_map_.resize(nglobals);
 
+  // Initialize the status of each input file.
+  this->file_status_ = new unsigned char[(count + 7) / 8];
+  memset(this->file_status_, 0, (count + 7) / 8);
+
   this->has_incremental_info_ = true;
 }
 
@@ -507,6 +524,8 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout(
   Input_entry_reader input_file =
       this->inputs_reader_.input_file(input_file_index);
 
+  this->set_file_is_unchanged(input_file_index);
+
   if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY)
     return;
 
@@ -523,6 +542,83 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout(
     }
 }
 
+// Process the GOT and PLT entries from the existing output file.
+
+template<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_process_got_plt(
+    Symbol_table* symtab,
+    Layout* layout)
+{
+  Incremental_got_plt_reader<big_endian> got_plt_reader(this->got_plt_reader());
+  Sized_target<size, big_endian>* target =
+      parameters->sized_target<size, big_endian>();
+
+  // Get the number of symbols in the main symbol table and in the
+  // incremental symbol table.  The difference between the two counts
+  // is the index of the first forced-local or global symbol in the
+  // main symbol table.
+  unsigned int symtab_count =
+      this->main_symtab_loc_.data_size / elfcpp::Elf_sizes<size>::sym_size;
+  unsigned int isym_count = this->symtab_reader_.symbol_count();
+  unsigned int first_global = symtab_count - isym_count;
+
+  // Tell the target how big the GOT and PLT sections are.
+  unsigned int got_count = got_plt_reader.get_got_entry_count();
+  unsigned int plt_count = got_plt_reader.get_plt_entry_count();
+  Output_data_got<size, big_endian>* got =
+      target->init_got_plt_for_update(symtab, layout, got_count, plt_count);
+
+  // Read the GOT entries from the base file and build the outgoing GOT.
+  for (unsigned int i = 0; i < got_count; ++i)
+    {
+      unsigned int got_type = got_plt_reader.get_got_type(i);
+      if ((got_type & 0x7f) == 0x7f)
+	{
+	  // This is the second entry of a pair.
+	  got->reserve_slot(i);
+	  continue;
+	}
+      unsigned int got_desc = got_plt_reader.get_got_desc(i);
+      if (got_type & 0x80)
+	{
+	  // This is an entry for a local symbol.  GOT_DESC is the index
+	  // of the object file entry in the list of input files.  Ignore
+	  // this entry if the object file was replaced.
+	  gold_debug(DEBUG_INCREMENTAL,
+		     "GOT entry %d, type %02x: (local symbol)",
+		     i, got_type & 0x7f);
+	  if (this->file_is_unchanged(got_desc))
+	    got->reserve_slot(i);
+	}
+      else
+	{
+	  // This is an entry for a global symbol.  GOT_DESC is the symbol
+	  // table index.
+	  // FIXME: This should really be a fatal error (corrupt input).
+	  gold_assert(got_desc >= first_global && got_desc < symtab_count);
+	  Symbol* sym = this->global_symbol(got_desc - first_global);
+	  gold_debug(DEBUG_INCREMENTAL,
+		     "GOT entry %d, type %02x: %s",
+		     i, got_type, sym->name());
+	  got->reserve_slot_for_global(i, sym, got_type);
+	}
+    }
+
+  // Read the PLT entries from the base file and pass each to the target.
+  for (unsigned int i = 0; i < plt_count; ++i)
+    {
+      unsigned int plt_desc = got_plt_reader.get_plt_desc(i);
+      // FIXME: This should really be a fatal error (corrupt input).
+      gold_assert(plt_desc >= first_global && plt_desc < symtab_count);
+      Symbol* sym = this->global_symbol(plt_desc - first_global);
+      gold_debug(DEBUG_INCREMENTAL,
+		 "PLT entry %d: %s",
+		 i, sym->name());
+      target->register_global_plt_entry(i, sym);
+    }
+}
+
 // Apply incremental relocations for symbols whose values have changed.
 
 template<int size, bool big_endian>
@@ -628,20 +724,12 @@ Sized_incremental_binary<size, big_endian>::get_symtab_view(
     unsigned int* nsyms,
     elfcpp::Elf_strtab* strtab)
 {
-  unsigned int symtab_shndx =
-      this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB);
-  gold_assert(symtab_shndx != elfcpp::SHN_UNDEF);
-  Location symtab_location(this->elf_file_.section_contents(symtab_shndx));
-  *symtab_view = this->view(symtab_location);
-  *nsyms = symtab_location.data_size / elfcpp::Elf_sizes<size>::sym_size;
+  *symtab_view = this->view(this->main_symtab_loc_);
+  *nsyms = this->main_symtab_loc_.data_size / elfcpp::Elf_sizes<size>::sym_size;
 
-  unsigned int strtab_shndx = this->elf_file_.section_link(symtab_shndx);
-  gold_assert(strtab_shndx != elfcpp::SHN_UNDEF
-              && strtab_shndx < this->elf_file_.shnum());
-
-  Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
-  View strtab_view(this->view(strtab_location));
-  *strtab = elfcpp::Elf_strtab(strtab_view.data(), strtab_location.data_size);
+  View strtab_view(this->view(this->main_strtab_loc_));
+  *strtab = elfcpp::Elf_strtab(strtab_view.data(),
+			       this->main_strtab_loc_.data_size);
 }
 
 namespace
@@ -1022,6 +1110,7 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
   unsigned int input_offset = this->header_size;
 
   // Offset of each supplemental info block.
+  unsigned int file_index = 0;
   unsigned int info_offset = this->header_size;
   info_offset += this->input_entry_size * inputs->input_file_count();
 
@@ -1031,8 +1120,9 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
        p != inputs->input_files().end();
        ++p)
     {
-      // Set the offset of the input file entry.
-      (*p)->set_offset(input_offset);
+      // Set the index and offset of the input file entry.
+      (*p)->set_offset(file_index, input_offset);
+      ++file_index;
       input_offset += this->input_entry_size;
 
       // Set the offset of the supplemental info block.
@@ -1655,7 +1745,7 @@ Output_section_incremental_inputs<size, big_endian>::write_got_plt(
       gold_assert(entry != NULL);
       const Object* obj = entry->object();
       gold_assert(obj != NULL);
-      view_info.got_descriptor = (*p)->get_offset();
+      view_info.got_descriptor = (*p)->get_file_index();
       Got_visitor v(view_info);
       obj->for_all_local_got_entries(&v);
     }
diff --git a/gold/incremental.h b/gold/incremental.h
index dabf453..1a8efb9 100644
--- a/gold/incremental.h
+++ b/gold/incremental.h
@@ -79,7 +79,7 @@ class Incremental_input_entry
  public:
   Incremental_input_entry(Stringpool::Key filename_key, unsigned int arg_serial,
 			  Timespec mtime)
-    : filename_key_(filename_key), offset_(0), info_offset_(0),
+    : filename_key_(filename_key), file_index_(0), offset_(0), info_offset_(0),
       arg_serial_(arg_serial), mtime_(mtime), is_in_system_directory_(false)
   { }
 
@@ -92,16 +92,24 @@ class Incremental_input_entry
   type() const
   { return this->do_type(); }
 
-  // Set the section offset of this input file entry.
+  // Set the index and section offset of this input file entry.
   void
-  set_offset(unsigned int offset)
-  { this->offset_ = offset; }
+  set_offset(unsigned int file_index, unsigned int offset)
+  {
+    this->file_index_ = file_index;
+    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 index of this input file entry.
+  unsigned int
+  get_file_index() const
+  { return this->file_index_; }
+
   // Get the section offset of this input file entry.
   unsigned int
   get_offset() const
@@ -182,6 +190,9 @@ class Incremental_input_entry
   // Key of the filename string in the section stringtable.
   Stringpool::Key filename_key_;
 
+  // Index of the entry in the output section.
+  unsigned int file_index_;
+
   // Offset of the entry in the output section.
   unsigned int offset_;
 
@@ -1235,6 +1246,11 @@ class Incremental_binary
   reserve_layout(unsigned int input_file_index)
   { this->do_reserve_layout(input_file_index); }
 
+  // Process the GOT and PLT entries from the existing output file.
+  void
+  process_got_plt(Symbol_table* symtab, Layout* layout)
+  { this->do_process_got_plt(symtab, layout); }
+
   // Apply incremental relocations for symbols whose values have changed.
   void
   apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
@@ -1313,6 +1329,10 @@ class Incremental_binary
   virtual void
   do_reserve_layout(unsigned int input_file_index) = 0;
 
+  // Process the GOT and PLT entries from the existing output file.
+  virtual void
+  do_process_got_plt(Symbol_table* symtab, Layout* layout) = 0;
+
   // Apply incremental relocations for symbols whose values have changed.
   virtual void
   do_apply_incremental_relocs(const Symbol_table*, Layout*, Output_file*) = 0;
@@ -1345,29 +1365,53 @@ class Sized_incremental_binary : public Incremental_binary
                            const elfcpp::Ehdr<size, big_endian>& ehdr,
                            Target* target)
     : Incremental_binary(output, target), elf_file_(this, ehdr),
-      section_map_(), symbol_map_(), has_incremental_info_(false),
-      inputs_reader_(), symtab_reader_(), relocs_reader_(), got_plt_reader_(),
+      file_status_(NULL), section_map_(), symbol_map_(), main_symtab_loc_(),
+      main_strtab_loc_(), has_incremental_info_(false), inputs_reader_(),
+      symtab_reader_(), relocs_reader_(), got_plt_reader_(),
       input_entry_readers_()
   { this->setup_readers(); }
 
+  virtual
+  ~Sized_incremental_binary()
+  {
+    if (this->file_status_ != NULL)
+      delete[] this->file_status_;
+  }
+
   // Returns TRUE if the file contains incremental info.
   bool
   has_incremental_info() const
   { return this->has_incremental_info_; }
 
+  // Set the flag for input file N to indicate that the file is unchanged.
+  void
+  set_file_is_unchanged(unsigned int n)
+  {
+    gold_assert(this->file_status_ != NULL);
+    this->file_status_[n / 8] |= 1U << (n % 8);
+  }
+
+  // Returns TRUE if input file N is unchanged.
+  bool
+  file_is_unchanged(unsigned int n) const
+  {
+    gold_assert(this->file_status_ != NULL);
+    return (this->file_status_[n / 8] & (1U << (n % 8))) != 0;
+  }
+
   // Return the Output_section for section index SHNDX.
   Output_section*
   output_section(unsigned int shndx)
   { return this->section_map_[shndx]; }
 
-  // Map a symbol table entry from the input file to the output symbol table.
+  // Map a symbol table entry from the base file to the output symbol table.
   // SYMNDX is relative to the first forced-local or global symbol in the
   // input file symbol table.
   void
   add_global_symbol(unsigned int symndx, Symbol* gsym)
   { this->symbol_map_[symndx] = gsym; }
 
-  // Map a symbol table entry from the input file to the output symbol table.
+  // Map a symbol table entry from the base file to the output symbol table.
   // SYMNDX is relative to the first forced-local or global symbol in the
   // input file symbol table.
   Symbol*
@@ -1418,6 +1462,10 @@ class Sized_incremental_binary : public Incremental_binary
   virtual void
   do_reserve_layout(unsigned int input_file_index);
 
+  // Process the GOT and PLT entries from the existing output file.
+  virtual void
+  do_process_got_plt(Symbol_table* symtab, Layout* layout);
+
   // Apply incremental relocations for symbols whose values have changed.
   virtual void
   do_apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
@@ -1489,12 +1537,21 @@ class Sized_incremental_binary : public Incremental_binary
   // Output as an ELF file.
   elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file_;
 
+  // Status flags for each input file.  Each bit represents one input file;
+  // 0 indicates that the file was replaced; 1 indicates that the file was
+  // unchanged.
+  unsigned char* file_status_;
+
   // Map section index to an Output_section in the updated layout.
   std::vector<Output_section*> section_map_;
 
   // Map global symbols from the input file to the symbol table.
   std::vector<Symbol*> symbol_map_;
 
+  // Locations of the main symbol table and symbol string table.
+  Location main_symtab_loc_;
+  Location main_strtab_loc_;
+
   // Readers for the incremental info sections.
   bool has_incremental_info_;
   Incremental_inputs_reader<size, big_endian> inputs_reader_;
diff --git a/gold/output.cc b/gold/output.cc
index 5c1fae9..d77325d 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1289,6 +1289,13 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
       val = this->u_.constant;
       break;
 
+    case RESERVED_CODE:
+      // If we're doing an incremental update, don't touch this GOT entry.
+      if (parameters->incremental_update())
+        return;
+      val = this->u_.constant;
+      break;
+
     default:
       {
 	const Sized_relobj<size, big_endian>* object = this->u_.object;
@@ -1324,9 +1331,8 @@ Output_data_got<size, big_endian>::add_global(
   if (gsym->has_got_offset(got_type))
     return false;
 
-  this->entries_.push_back(Got_entry(gsym, false));
-  this->set_got_size();
-  gsym->set_got_offset(got_type, this->last_got_offset());
+  unsigned int got_offset = this->add_got_entry(Got_entry(gsym, false));
+  gsym->set_got_offset(got_type, got_offset);
   return true;
 }
 
@@ -1340,9 +1346,8 @@ Output_data_got<size, big_endian>::add_global_plt(Symbol* gsym,
   if (gsym->has_got_offset(got_type))
     return false;
 
-  this->entries_.push_back(Got_entry(gsym, true));
-  this->set_got_size();
-  gsym->set_got_offset(got_type, this->last_got_offset());
+  unsigned int got_offset = this->add_got_entry(Got_entry(gsym, true));
+  gsym->set_got_offset(got_type, got_offset);
   return true;
 }
 
@@ -1360,9 +1365,7 @@ Output_data_got<size, big_endian>::add_global_with_rel(
   if (gsym->has_got_offset(got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  this->set_got_size();
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset = this->add_got_entry(Got_entry());
   gsym->set_got_offset(got_type, got_offset);
   rel_dyn->add_global(gsym, r_type, this, got_offset);
 }
@@ -1378,9 +1381,7 @@ Output_data_got<size, big_endian>::add_global_with_rela(
   if (gsym->has_got_offset(got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  this->set_got_size();
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset = this->add_got_entry(Got_entry());
   gsym->set_got_offset(got_type, got_offset);
   rela_dyn->add_global(gsym, r_type, this, got_offset, 0);
 }
@@ -1400,19 +1401,12 @@ Output_data_got<size, big_endian>::add_global_pair_with_rel(
   if (gsym->has_got_offset(got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset = this->add_got_entry_pair(Got_entry(), Got_entry());
   gsym->set_got_offset(got_type, got_offset);
   rel_dyn->add_global(gsym, r_type_1, this, got_offset);
 
-  this->entries_.push_back(Got_entry());
   if (r_type_2 != 0)
-    {
-      got_offset = this->last_got_offset();
-      rel_dyn->add_global(gsym, r_type_2, this, got_offset);
-    }
-
-  this->set_got_size();
+    rel_dyn->add_global(gsym, r_type_2, this, got_offset + size / 8);
 }
 
 template<int size, bool big_endian>
@@ -1427,19 +1421,12 @@ Output_data_got<size, big_endian>::add_global_pair_with_rela(
   if (gsym->has_got_offset(got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset = this->add_got_entry_pair(Got_entry(), Got_entry());
   gsym->set_got_offset(got_type, got_offset);
   rela_dyn->add_global(gsym, r_type_1, this, got_offset, 0);
 
-  this->entries_.push_back(Got_entry());
   if (r_type_2 != 0)
-    {
-      got_offset = this->last_got_offset();
-      rela_dyn->add_global(gsym, r_type_2, this, got_offset, 0);
-    }
-
-  this->set_got_size();
+    rela_dyn->add_global(gsym, r_type_2, this, got_offset + size / 8, 0);
 }
 
 // Add an entry for a local symbol to the GOT.  This returns true if
@@ -1456,9 +1443,9 @@ Output_data_got<size, big_endian>::add_local(
   if (object->local_has_got_offset(symndx, got_type))
     return false;
 
-  this->entries_.push_back(Got_entry(object, symndx, false));
-  this->set_got_size();
-  object->set_local_got_offset(symndx, got_type, this->last_got_offset());
+  unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx,
+							  false));
+  object->set_local_got_offset(symndx, got_type, got_offset);
   return true;
 }
 
@@ -1474,9 +1461,9 @@ Output_data_got<size, big_endian>::add_local_plt(
   if (object->local_has_got_offset(symndx, got_type))
     return false;
 
-  this->entries_.push_back(Got_entry(object, symndx, true));
-  this->set_got_size();
-  object->set_local_got_offset(symndx, got_type, this->last_got_offset());
+  unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx,
+							  true));
+  object->set_local_got_offset(symndx, got_type, got_offset);
   return true;
 }
 
@@ -1495,9 +1482,7 @@ Output_data_got<size, big_endian>::add_local_with_rel(
   if (object->local_has_got_offset(symndx, got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  this->set_got_size();
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset = this->add_got_entry(Got_entry());
   object->set_local_got_offset(symndx, got_type, got_offset);
   rel_dyn->add_local(object, symndx, r_type, this, got_offset);
 }
@@ -1514,9 +1499,7 @@ Output_data_got<size, big_endian>::add_local_with_rela(
   if (object->local_has_got_offset(symndx, got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  this->set_got_size();
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset = this->add_got_entry(Got_entry());
   object->set_local_got_offset(symndx, got_type, got_offset);
   rela_dyn->add_local(object, symndx, r_type, this, got_offset, 0);
 }
@@ -1538,20 +1521,15 @@ Output_data_got<size, big_endian>::add_local_pair_with_rel(
   if (object->local_has_got_offset(symndx, got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset =
+      this->add_got_entry_pair(Got_entry(),
+			       Got_entry(object, symndx, false));
   object->set_local_got_offset(symndx, got_type, got_offset);
   Output_section* os = object->output_section(shndx);
   rel_dyn->add_output_section(os, r_type_1, this, got_offset);
 
-  this->entries_.push_back(Got_entry(object, symndx, false));
   if (r_type_2 != 0)
-    {
-      got_offset = this->last_got_offset();
-      rel_dyn->add_output_section(os, r_type_2, this, got_offset);
-    }
-
-  this->set_got_size();
+    rel_dyn->add_output_section(os, r_type_2, this, got_offset + size / 8);
 }
 
 template<int size, bool big_endian>
@@ -1568,20 +1546,37 @@ Output_data_got<size, big_endian>::add_local_pair_with_rela(
   if (object->local_has_got_offset(symndx, got_type))
     return;
 
-  this->entries_.push_back(Got_entry());
-  unsigned int got_offset = this->last_got_offset();
+  unsigned int got_offset =
+      this->add_got_entry_pair(Got_entry(),
+			       Got_entry(object, symndx, false));
   object->set_local_got_offset(symndx, got_type, got_offset);
   Output_section* os = object->output_section(shndx);
   rela_dyn->add_output_section(os, r_type_1, this, got_offset, 0);
 
-  this->entries_.push_back(Got_entry(object, symndx, false));
   if (r_type_2 != 0)
-    {
-      got_offset = this->last_got_offset();
-      rela_dyn->add_output_section(os, r_type_2, this, got_offset, 0);
-    }
+    rela_dyn->add_output_section(os, r_type_2, this, got_offset + size / 8, 0);
+}
+
+// Reserve a slot in the GOT for a local symbol or the second slot of a pair.
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::reserve_slot(unsigned int i)
+{
+  this->free_list_.remove(i * size / 8, (i + 1) * size / 8);
+}
 
-  this->set_got_size();
+// Reserve a slot in the GOT for a global symbol.
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::reserve_slot_for_global(
+    unsigned int i,
+    Symbol* gsym,
+    unsigned int got_type)
+{
+  this->free_list_.remove(i * size / 8, (i + 1) * size / 8);
+  gsym->set_got_offset(got_type, this->got_offset(i));
 }
 
 // Write out the GOT.
@@ -2266,7 +2261,8 @@ Output_section::add_output_section_data(Output_section_data* posd)
       uint64_t addr = this->address();
       posd->set_address(addr);
       posd->set_file_offset(0);
-      // FIXME: Mark *POSD as part of a fixed-layout section.
+      // FIXME: This should eventually be unreachable.
+      // gold_unreachable();
     }
 }
 
diff --git a/gold/output.h b/gold/output.h
index d62ae73..3fc6d89 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -764,6 +764,10 @@ class Output_section_data_build : public Output_section_data
     : Output_section_data(addralign)
   { }
 
+  Output_section_data_build(off_t data_size, uint64_t addralign)
+    : Output_section_data(data_size, addralign, false)
+  { }
+
   // Set the current data size.
   void
   set_current_data_size(off_t data_size)
@@ -890,6 +894,12 @@ class Output_data_space : public Output_section_data_build
       map_name_(map_name)
   { }
 
+  explicit Output_data_space(off_t data_size, uint64_t addralign,
+			     const char* map_name)
+    : Output_section_data_build(data_size, addralign),
+      map_name_(map_name)
+  { }
+
   // Set the alignment.
   void
   set_space_alignment(uint64_t align)
@@ -1942,9 +1952,20 @@ class Output_data_got : public Output_section_data_build
 
   Output_data_got()
     : Output_section_data_build(Output_data::default_alignment_for_size(size)),
-      entries_()
+      entries_(), free_list_()
   { }
 
+  Output_data_got(off_t data_size)
+    : Output_section_data_build(data_size,
+				Output_data::default_alignment_for_size(size)),
+      entries_(), free_list_()
+  {
+    // For an incremental update, we have an existing GOT section.
+    // Initialize the list of entries and the free list.
+    this->entries_.resize(data_size / (size / 8));
+    this->free_list_.init(data_size, false);
+  }
+
   // Add an entry for a global symbol to the GOT.  Return true if this
   // is a new GOT entry, false if the symbol was already in the GOT.
   bool
@@ -2021,11 +2042,18 @@ class Output_data_got : public Output_section_data_build
   unsigned int
   add_constant(Valtype constant)
   {
-    this->entries_.push_back(Got_entry(constant));
-    this->set_got_size();
-    return this->last_got_offset();
+    unsigned int got_offset = this->add_got_entry(Got_entry(constant));
+    return got_offset;
   }
 
+  // Reserve a slot in the GOT for a local symbol or the second slot of a pair.
+  void
+  reserve_slot(unsigned int i);
+
+  // Reserve a slot in the GOT for a global symbol.
+  void
+  reserve_slot_for_global(unsigned int i, Symbol* gsym, unsigned int got_type);
+
  protected:
   // Write out the GOT table.
   void
@@ -2043,7 +2071,7 @@ class Output_data_got : public Output_section_data_build
    public:
     // Create a zero entry.
     Got_entry()
-      : local_sym_index_(CONSTANT_CODE), use_plt_offset_(false)
+      : local_sym_index_(RESERVED_CODE), use_plt_offset_(false)
     { this->u_.constant = 0; }
 
     // Create a global symbol entry.
@@ -2058,6 +2086,7 @@ class Output_data_got : public Output_section_data_build
     {
       gold_assert(local_sym_index != GSYM_CODE
 		  && local_sym_index != CONSTANT_CODE
+		  && local_sym_index != RESERVED_CODE
 		  && local_sym_index == this->local_sym_index_);
       this->u_.object = object;
     }
@@ -2076,7 +2105,8 @@ class Output_data_got : public Output_section_data_build
     enum
     {
       GSYM_CODE = 0x7fffffff,
-      CONSTANT_CODE = 0x7ffffffe
+      CONSTANT_CODE = 0x7ffffffe,
+      RESERVED_CODE = 0x7ffffffd
     };
 
     union
@@ -2097,6 +2127,58 @@ class Output_data_got : public Output_section_data_build
 
   typedef std::vector<Got_entry> Got_entries;
 
+  // Create a new GOT entry and return its offset.
+  unsigned int
+  add_got_entry(Got_entry got_entry)
+  {
+    if (!this->is_data_size_valid())
+      {
+	this->entries_.push_back(got_entry);
+	this->set_got_size();
+	return this->last_got_offset();
+      }
+    else
+      {
+	// For an incremental update, find an available slot.
+	off_t got_offset = this->free_list_.allocate(size / 8, size / 8, 0);
+	if (got_offset == -1)
+	  gold_fatal(_("out of patch space (GOT);"
+		       " relink with --incremental-full"));
+	unsigned int got_index = got_offset / (size / 8);
+	gold_assert(got_index < this->entries_.size());
+	this->entries_[got_index] = got_entry;
+	return static_cast<unsigned int>(got_offset);
+      }
+  }
+
+  // Create a pair of new GOT entries and return the offset of the first.
+  unsigned int
+  add_got_entry_pair(Got_entry got_entry_1, Got_entry got_entry_2)
+  {
+    if (!this->is_data_size_valid())
+      {
+	unsigned int got_offset;
+	this->entries_.push_back(got_entry_1);
+	got_offset = this->last_got_offset();
+	this->entries_.push_back(got_entry_2);
+	this->set_got_size();
+	return got_offset;
+      }
+    else
+      {
+	// For an incremental update, find an available pair of slots.
+	off_t got_offset = this->free_list_.allocate(2 * size / 8, size / 8, 0);
+	if (got_offset == -1)
+	  gold_fatal(_("out of patch space (GOT);"
+		       " relink with --incremental-full"));
+	unsigned int got_index = got_offset / (size / 8);
+	gold_assert(got_index < this->entries_.size());
+	this->entries_[got_index] = got_entry_1;
+	this->entries_[got_index + 1] = got_entry_2;
+	return static_cast<unsigned int>(got_offset);
+      }
+  }
+
   // Return the offset into the GOT of GOT entry I.
   unsigned int
   got_offset(unsigned int i) const
@@ -2114,6 +2196,10 @@ class Output_data_got : public Output_section_data_build
 
   // The list of GOT entries.
   Got_entries entries_;
+
+  // List of available regions within the section, for incremental
+  // update links.
+  Free_list free_list_;
 };
 
 // Output_data_dynamic is used to hold the data in SHT_DYNAMIC
diff --git a/gold/target.h b/gold/target.h
index b86efc4..6b25d5f 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -54,6 +54,8 @@ template<int size>
 class Sized_symbol;
 class Symbol_table;
 class Output_data;
+template<int size, bool big_endian>
+class Output_data_got;
 class Output_section;
 class Input_objects;
 class Task;
@@ -795,6 +797,24 @@ class Sized_target : public Target
   plt_entry_size() const
   { gold_unreachable(); }
 
+  // Create the GOT and PLT sections for an incremental update.
+  // A target needs to implement this to support incremental linking.
+
+  virtual Output_data_got<size, big_endian>*
+  init_got_plt_for_update(Symbol_table*,
+			  Layout*,
+			  unsigned int /* got_count */,
+			  unsigned int /* plt_count */)
+  { gold_unreachable(); }
+
+  // Register an existing PLT entry for a global symbol.
+  // A target needs to implement this to support incremental linking.
+
+  virtual void
+  register_global_plt_entry(unsigned int /* plt_index */,
+			    Symbol*)
+  { gold_unreachable(); }
+
   // Apply an incremental relocation.
 
   virtual void
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 7915e32..c85f65c 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -53,8 +53,31 @@ class Output_data_plt_x86_64 : public Output_section_data
  public:
   typedef Output_data_reloc<elfcpp::SHT_RELA, true, 64, false> Reloc_section;
 
-  Output_data_plt_x86_64(Symbol_table*, Layout*, Output_data_got<64, false>*,
-                         Output_data_space*);
+  Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
+			 Output_data_got<64, false>* got,
+			 Output_data_space* got_plt)
+    : Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
+      count_(0), tlsdesc_got_offset_(-1U), free_list_()
+  { this->init(symtab, layout); }
+
+  Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
+			 Output_data_got<64, false>* got,
+			 Output_data_space* got_plt,
+			 unsigned int plt_count)
+    : Output_section_data((plt_count + 1) * plt_entry_size, 8, false),
+      tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
+      count_(plt_count), tlsdesc_got_offset_(-1U), free_list_()
+  {
+    this->init(symtab, layout);
+
+    // Initialize the free list and reserve the first entry.
+    this->free_list_.init((plt_count + 1) * plt_entry_size, false);
+    this->free_list_.remove(0, plt_entry_size);
+  }
+
+  // Initialize the PLT section.
+  void
+  init(Symbol_table* symtab, Layout* layout);
 
   // Add an entry to the PLT.
   void
@@ -65,6 +88,10 @@ class Output_data_plt_x86_64 : public Output_section_data
   add_local_ifunc_entry(Sized_relobj<64, false>* relobj,
 			unsigned int local_sym_index);
 
+  // Add the relocation for a PLT entry.
+  void
+  add_relocation(Symbol* gsym, unsigned int got_offset);
+
   // Add the reserved TLSDESC_PLT entry to the PLT.
   void
   reserve_tlsdesc_entry(unsigned int got_offset)
@@ -109,6 +136,14 @@ class Output_data_plt_x86_64 : public Output_section_data
   get_plt_entry_size()
   { return plt_entry_size; }
 
+  // Reserve a slot in the PLT for an existing symbol in an incremental update.
+  void
+  reserve_slot(unsigned int plt_index)
+  {
+    this->free_list_.remove((plt_index + 1) * plt_entry_size,
+			    (plt_index + 2) * plt_entry_size);
+  }
+
  protected:
   void
   do_adjust_output_section(Output_section* os);
@@ -154,6 +189,9 @@ class Output_data_plt_x86_64 : public Output_section_data
   unsigned int count_;
   // Offset of the reserved TLSDESC_GOT entry when needed.
   unsigned int tlsdesc_got_offset_;
+  // List of available regions within the section, for incremental
+  // update links.
+  Free_list free_list_;
 };
 
 // The x86_64 target class.
@@ -345,6 +383,18 @@ class Target_x86_64 : public Target_freebsd<64, false>
   unsigned int
   plt_entry_size() const;
 
+  // Create the GOT section for an incremental update.
+  Output_data_got<64, false>*
+  init_got_plt_for_update(Symbol_table* symtab,
+			  Layout* layout,
+			  unsigned int got_count,
+			  unsigned int plt_count);
+
+  // Register an existing PLT entry for a global symbol.
+  // A target needs to implement this to support incremental linking.
+  void
+  register_global_plt_entry(unsigned int plt_index, Symbol* gsym);
+
   // Apply an incremental relocation.
   void
   apply_relocation(const Relocate_info<64, false>* relinfo,
@@ -779,16 +829,10 @@ Target_x86_64::rela_dyn_section(Layout* layout)
   return this->rela_dyn_;
 }
 
-// Create the PLT section.  The ordinary .got section is an argument,
-// since we need to refer to the start.  We also create our own .got
-// section just for PLT entries.
+// Initialize the PLT section.
 
-Output_data_plt_x86_64::Output_data_plt_x86_64(Symbol_table* symtab,
-					       Layout* layout,
-                                               Output_data_got<64, false>* got,
-                                               Output_data_space* got_plt)
-  : Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
-    count_(0), tlsdesc_got_offset_(-1U)
+void
+Output_data_plt_x86_64::init(Symbol_table* symtab, Layout* layout)
 {
   this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
@@ -827,31 +871,47 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym)
 {
   gold_assert(!gsym->has_plt_offset());
 
-  // Note that when setting the PLT offset we skip the initial
-  // reserved PLT entry.
-  gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
+  unsigned int plt_index;
+  off_t plt_offset;
+  section_offset_type got_offset;
 
-  ++this->count_;
+  if (!this->is_data_size_valid())
+    {
+      // Note that when setting the PLT offset we skip the initial
+      // reserved PLT entry.
+      plt_index = this->count_ + 1;
+      plt_offset = plt_index * plt_entry_size;
 
-  section_offset_type got_offset = this->got_plt_->current_data_size();
+      ++this->count_;
 
-  // Every PLT entry needs a GOT entry which points back to the PLT
-  // entry (this will be changed by the dynamic linker, normally
-  // lazily when the function is called).
-  this->got_plt_->set_current_data_size(got_offset + 8);
+      got_offset = (plt_index - 1 + 3) * 8;
+      gold_assert(got_offset == this->got_plt_->current_data_size());
 
-  // Every PLT entry needs a reloc.
-  if (gsym->type() == elfcpp::STT_GNU_IFUNC
-      && gsym->can_use_relative_reloc(false))
-    this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
-					     this->got_plt_, got_offset, 0);
+      // Every PLT entry needs a GOT entry which points back to the PLT
+      // entry (this will be changed by the dynamic linker, normally
+      // lazily when the function is called).
+      this->got_plt_->set_current_data_size(got_offset + 8);
+    }
   else
     {
-      gsym->set_needs_dynsym_entry();
-      this->rel_->add_global(gsym, elfcpp::R_X86_64_JUMP_SLOT, this->got_plt_,
-			     got_offset, 0);
+      // For incremental updates, find an available slot.
+      plt_offset = this->free_list_.allocate(plt_entry_size, plt_entry_size, 0);
+      if (plt_offset == -1)
+	gold_fatal(_("out of patch space (PLT);"
+		     " relink with --incremental-full"));
+
+      // The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
+      // can be calculated from the PLT index, adjusting for the three
+      // reserved entries at the beginning of the GOT.
+      plt_index = plt_offset / plt_entry_size - 1;
+      got_offset = (plt_index - 1 + 3) * 8;
     }
 
+  gsym->set_plt_offset(plt_offset);
+
+  // Every PLT entry needs a reloc.
+  this->add_relocation(gsym, got_offset);
+
   // Note that we don't need to save the symbol.  The contents of the
   // PLT are independent of which symbols are used.  The symbols only
   // appear in the relocations.
@@ -881,6 +941,23 @@ Output_data_plt_x86_64::add_local_ifunc_entry(Sized_relobj<64, false>* relobj,
   return plt_offset;
 }
 
+// Add the relocation for a PLT entry.
+
+void
+Output_data_plt_x86_64::add_relocation(Symbol* gsym, unsigned int got_offset)
+{
+  if (gsym->type() == elfcpp::STT_GNU_IFUNC
+      && gsym->can_use_relative_reloc(false))
+    this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
+					     this->got_plt_, got_offset, 0);
+  else
+    {
+      gsym->set_needs_dynsym_entry();
+      this->rel_->add_global(gsym, elfcpp::R_X86_64_JUMP_SLOT, this->got_plt_,
+			     got_offset, 0);
+    }
+}
+
 // Return where the TLSDESC relocations should go, creating it if
 // necessary.  These follow the JUMP_SLOT relocations.
 
@@ -1129,6 +1206,81 @@ Target_x86_64::plt_entry_size() const
   return Output_data_plt_x86_64::get_plt_entry_size();
 }
 
+// Create the GOT and PLT sections for an incremental update.
+
+Output_data_got<64, false>*
+Target_x86_64::init_got_plt_for_update(Symbol_table* symtab,
+				       Layout* layout,
+				       unsigned int got_count,
+				       unsigned int plt_count)
+{
+  gold_assert(this->got_ == NULL);
+
+  this->got_ = new Output_data_got<64, false>(got_count * 8);
+  layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+				  (elfcpp::SHF_ALLOC
+				   | elfcpp::SHF_WRITE),
+				  this->got_, ORDER_RELRO_LAST,
+				  true);
+
+  // Add the three reserved entries.
+  this->got_plt_ = new Output_data_space((plt_count + 3) * 8, 8, "** GOT PLT");
+  layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+				  (elfcpp::SHF_ALLOC
+				   | elfcpp::SHF_WRITE),
+				  this->got_plt_, ORDER_NON_RELRO_FIRST,
+				  false);
+
+  // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
+  this->global_offset_table_ =
+    symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+				  Symbol_table::PREDEFINED,
+				  this->got_plt_,
+				  0, 0, elfcpp::STT_OBJECT,
+				  elfcpp::STB_LOCAL,
+				  elfcpp::STV_HIDDEN, 0,
+				  false, false);
+
+  // If there are any TLSDESC relocations, they get GOT entries in
+  // .got.plt after the jump slot entries.
+  // FIXME: Get the count for TLSDESC entries.
+  this->got_tlsdesc_ = new Output_data_got<64, false>(0);
+  layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+				  elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+				  this->got_tlsdesc_,
+				  ORDER_NON_RELRO_FIRST, false);
+
+  // Create the PLT section.
+  this->plt_ = new Output_data_plt_x86_64(symtab, layout, this->got_,
+					  this->got_plt_, plt_count);
+  layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+				  elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
+				  this->plt_, ORDER_PLT, false);
+
+  // Make the sh_info field of .rela.plt point to .plt.
+  Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
+  rela_plt_os->set_info_section(this->plt_->output_section());
+
+  return this->got_;
+}
+
+// Register an existing PLT entry for a global symbol.
+
+void
+Target_x86_64::register_global_plt_entry(unsigned int plt_index,
+					 Symbol* gsym)
+{
+  gold_assert(this->plt_ != NULL);
+  gold_assert(!gsym->has_plt_offset());
+
+  this->plt_->reserve_slot(plt_index);
+
+  gsym->set_plt_offset((plt_index + 1) * this->plt_entry_size());
+
+  unsigned int got_offset = (plt_index + 3) * 8;
+  this->plt_->add_relocation(gsym, got_offset);
+}
+
 // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
 
 void

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gold patch] Incremental 11/18: update GOT/PLT
  2011-04-01 21:36 [gold patch] Incremental 11/18: update GOT/PLT Cary Coutant
@ 2011-05-18 18:50 ` Cary Coutant
  2011-05-21 16:52 ` Ian Lance Taylor
  1 sibling, 0 replies; 4+ messages in thread
From: Cary Coutant @ 2011-05-18 18:50 UTC (permalink / raw)
  To: Ian Lance Taylor, Binutils

Ping?

-cary

On Fri, Apr 1, 2011 at 2:35 PM, Cary Coutant <ccoutant@google.com> wrote:
> This patch adds the support for incremental updates to the GOT and
> PLT. In the incremental info for the GOT entries, I changed it to
> store an input file index instead of the offset of the input file
> entry so that it would be easier to tell whether a local GOT entry was
> still in use or available for reuse. For the many similar methods in
> class Output_data_got, I refactored the common code into add_got_entry
> and add_got_entry_pair. I added two target-specific hooks for managing
> the GOT and PLT during an incremental update.
>
> -cary
>
>
>        * gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
>        * incremental-dump.cc (dump_incremental_inputs): Mask high-order
>        bit when checking got_type.
>        * incremental.cc (Sized_incremental_binary::setup_readers):
>        Store symbol table and string table locations; initialize bit vector
>        of file status flags.
>        (Sized_incremental_binary::do_reserve_layout): Set bit flag for
>        unchanged files.
>        (Sized_incremental_binary::do_process_got_plt): New function.
>        (Sized_incremental_binary::get_symtab_view): Use stored locations.
>        (Output_section_incremental_inputs::set_final_data_size): Record
>        file index for each input file.
>        (Output_section_incremental_inputs::write_got_plt): Store file index
>        instead of input entry offset for each GOT entry.
>        * incremental.h
>        (Incremental_input_entry::Incremental_input_entry): Initialize new
>        data member.
>        (Incremental_input_entry::set_offset): Store file index.
>        (Incremental_input_entry::get_file_index): New function.
>        (Incremental_input_entry::file_index_): New data member.
>        (Incremental_binary::process_got_plt): New function.
>        (Incremental_binary::do_process_got_plt): New function.
>        (Sized_incremental_binary::Sized_incremental_binary): Initialize new
>        data members.
>        (Sized_incremental_binary::~Sized_incremental_binary): New destructor.
>        (Sized_incremental_binary::set_file_is_unchanged): New function.
>        (Sized_incremental_binary::file_is_unchanged): New function.
>        (Sized_incremental_binary::do_process_got_plt): New function.
>        (Sized_incremental_binary::file_status_): New data member.
>        (Sized_incremental_binary::main_symtab_loc_): New data member.
>        (Sized_incremental_binary::main_strtab_loc_): New data member.
>        * output.cc (Output_data_got::Got_entry::write): Add case
>        RESERVED_CODE.
>        (Output_data_got::add_global): Call add_got_entry.
>        (Output_data_got::add_global_plt): Likewise.
>        (Output_data_got::add_global_with_rel): Likewise.
>        (Output_data_got::add_global_with_rela): Likewise.
>        (Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair.
>        (Output_data_got::add_global_pair_with_rela): Likewise.
>        (Output_data_got::add_local): Call add_got_entry.
>        (Output_data_got::add_local_plt): Likewise.
>        (Output_data_got::add_local_with_rel): Likewise.
>        (Output_data_got::add_local_with_rela): Likewise.
>        (Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair.
>        (Output_data_got::add_local_pair_with_rela): Likewise.
>        (Output_data_got::reserve_slot): New function.
>        (Output_data_got::reserve_slot_for_global): New function.
>        (Output_section::add_output_section_data): Edit FIXME.
>        * output.h
>        (Output_section_data_build::Output_section_data_build): New
>        constructor with size parameter.
>        (Output_data_space::Output_data_space): Likewise.
>        (Output_data_got::Output_data_got): Initialize new data member; new
>        constructor with size parameter.
>        (Output_data_got::add_constant): Call add_got_entry.
>        (Output_data_got::reserve_slot): New function.
>        (Output_data_got::reserve_slot_for_global): New function.
>        (class Output_data_got::Got_entry): Add RESERVED_CODE.
>        (Output_data_got::add_got_entry): New function.
>        (Output_data_got::add_got_entry_pair): New function.
>        (Output_data_got::free_list_): New data member.
>        * target.h (Sized_target::init_got_plt_for_update): New function.
>        (Sized_target::register_global_plt_entry): New function.
>        * x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
>        Initialize new data member; call init; add constructor with PLT count.
>        (Output_data_plt_x86_64::init): New function.
>        (Output_data_plt_x86_64::add_relocation): New function.
>        (Output_data_plt_x86_64::reserve_slot): New function.
>        (Output_data_plt_x86_64::free_list_): New data member.
>        (Target_x86_64::init_got_plt_for_update): New function.
>        (Target_x86_64::register_global_plt_entry): New function.
>        (Output_data_plt_x86_64::add_entry): Allocate from free list for
>        incremental updates.
>        (Output_data_plt_x86_64::add_relocation): New function.
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gold patch] Incremental 11/18: update GOT/PLT
  2011-04-01 21:36 [gold patch] Incremental 11/18: update GOT/PLT Cary Coutant
  2011-05-18 18:50 ` Cary Coutant
@ 2011-05-21 16:52 ` Ian Lance Taylor
  2011-05-23 23:36   ` Cary Coutant
  1 sibling, 1 reply; 4+ messages in thread
From: Ian Lance Taylor @ 2011-05-21 16:52 UTC (permalink / raw)
  To: Cary Coutant; +Cc: Binutils

Cary Coutant <ccoutant@google.com> writes:

> 	* gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
> 	* incremental-dump.cc (dump_incremental_inputs): Mask high-order
> 	bit when checking got_type.
> 	* incremental.cc (Sized_incremental_binary::setup_readers):
> 	Store symbol table and string table locations; initialize bit vector
> 	of file status flags.
> 	(Sized_incremental_binary::do_reserve_layout): Set bit flag for
> 	unchanged files.
> 	(Sized_incremental_binary::do_process_got_plt): New function.
> 	(Sized_incremental_binary::get_symtab_view): Use stored locations.
> 	(Output_section_incremental_inputs::set_final_data_size): Record
> 	file index for each input file.
> 	(Output_section_incremental_inputs::write_got_plt): Store file index
> 	instead of input entry offset for each GOT entry.
> 	* incremental.h
> 	(Incremental_input_entry::Incremental_input_entry): Initialize new
> 	data member.
> 	(Incremental_input_entry::set_offset): Store file index.
> 	(Incremental_input_entry::get_file_index): New function.
> 	(Incremental_input_entry::file_index_): New data member.
> 	(Incremental_binary::process_got_plt): New function.
> 	(Incremental_binary::do_process_got_plt): New function.
> 	(Sized_incremental_binary::Sized_incremental_binary): Initialize new
> 	data members.
> 	(Sized_incremental_binary::~Sized_incremental_binary): New destructor.
> 	(Sized_incremental_binary::set_file_is_unchanged): New function.
> 	(Sized_incremental_binary::file_is_unchanged): New function.
> 	(Sized_incremental_binary::do_process_got_plt): New function.
> 	(Sized_incremental_binary::file_status_): New data member.
> 	(Sized_incremental_binary::main_symtab_loc_): New data member.
> 	(Sized_incremental_binary::main_strtab_loc_): New data member.
> 	* output.cc (Output_data_got::Got_entry::write): Add case
> 	RESERVED_CODE.
> 	(Output_data_got::add_global): Call add_got_entry.
> 	(Output_data_got::add_global_plt): Likewise.
> 	(Output_data_got::add_global_with_rel): Likewise.
> 	(Output_data_got::add_global_with_rela): Likewise.
> 	(Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair.
> 	(Output_data_got::add_global_pair_with_rela): Likewise.
> 	(Output_data_got::add_local): Call add_got_entry.
> 	(Output_data_got::add_local_plt): Likewise.
> 	(Output_data_got::add_local_with_rel): Likewise.
> 	(Output_data_got::add_local_with_rela): Likewise.
> 	(Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair.
> 	(Output_data_got::add_local_pair_with_rela): Likewise.
> 	(Output_data_got::reserve_slot): New function.
> 	(Output_data_got::reserve_slot_for_global): New function.
> 	(Output_section::add_output_section_data): Edit FIXME.
> 	* output.h
> 	(Output_section_data_build::Output_section_data_build): New
> 	constructor with size parameter.
> 	(Output_data_space::Output_data_space): Likewise.
> 	(Output_data_got::Output_data_got): Initialize new data member; new
> 	constructor with size parameter.
> 	(Output_data_got::add_constant): Call add_got_entry.
> 	(Output_data_got::reserve_slot): New function.
> 	(Output_data_got::reserve_slot_for_global): New function.
> 	(class Output_data_got::Got_entry): Add RESERVED_CODE.
> 	(Output_data_got::add_got_entry): New function.
> 	(Output_data_got::add_got_entry_pair): New function.
> 	(Output_data_got::free_list_): New data member.
> 	* target.h (Sized_target::init_got_plt_for_update): New function.
> 	(Sized_target::register_global_plt_entry): New function.
> 	* x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
> 	Initialize new data member; call init; add constructor with PLT count.
> 	(Output_data_plt_x86_64::init): New function.
> 	(Output_data_plt_x86_64::add_relocation): New function.
> 	(Output_data_plt_x86_64::reserve_slot): New function.
> 	(Output_data_plt_x86_64::free_list_): New data member.
> 	(Target_x86_64::init_got_plt_for_update): New function.
> 	(Target_x86_64::register_global_plt_entry): New function.
> 	(Output_data_plt_x86_64::add_entry): Allocate from free list for
> 	incremental updates.
> 	(Output_data_plt_x86_64::add_relocation): New function.


> +  // Set the flag for input file N to indicate that the file is unchanged.
> +  void
> +  set_file_is_unchanged(unsigned int n)
> +  {
> +    gold_assert(this->file_status_ != NULL);
> +    this->file_status_[n / 8] |= 1U << (n % 8);
> +  }

You don't have to do this, but consider using std::vector<bool> for
file_status_.  That will give the tight memory layout without requiring
that we get the bit operations right.

> +  // Create a new GOT entry and return its offset.
> +  unsigned int
> +  add_got_entry(Got_entry got_entry)
> +  {
> +    if (!this->is_data_size_valid())
> +      {
> +	this->entries_.push_back(got_entry);
> +	this->set_got_size();
> +	return this->last_got_offset();
> +      }
> +    else
> +      {
> +	// For an incremental update, find an available slot.
> +	off_t got_offset = this->free_list_.allocate(size / 8, size / 8, 0);
> +	if (got_offset == -1)
> +	  gold_fatal(_("out of patch space (GOT);"
> +		       " relink with --incremental-full"));
> +	unsigned int got_index = got_offset / (size / 8);
> +	gold_assert(got_index < this->entries_.size());
> +	this->entries_[got_index] = got_entry;
> +	return static_cast<unsigned int>(got_offset);
> +      }
> +  }
> +
> +  // Create a pair of new GOT entries and return the offset of the first.
> +  unsigned int
> +  add_got_entry_pair(Got_entry got_entry_1, Got_entry got_entry_2)
> +  {
> +    if (!this->is_data_size_valid())
> +      {
> +	unsigned int got_offset;
> +	this->entries_.push_back(got_entry_1);
> +	got_offset = this->last_got_offset();
> +	this->entries_.push_back(got_entry_2);
> +	this->set_got_size();
> +	return got_offset;
> +      }
> +    else
> +      {
> +	// For an incremental update, find an available pair of slots.
> +	off_t got_offset = this->free_list_.allocate(2 * size / 8, size / 8, 0);
> +	if (got_offset == -1)
> +	  gold_fatal(_("out of patch space (GOT);"
> +		       " relink with --incremental-full"));
> +	unsigned int got_index = got_offset / (size / 8);
> +	gold_assert(got_index < this->entries_.size());
> +	this->entries_[got_index] = got_entry_1;
> +	this->entries_[got_index + 1] = got_entry_2;
> +	return static_cast<unsigned int>(got_offset);
> +      }
> +  }

I think these functions are complex enough that they should move from
output.h to output.cc.


This is OK with those changes.

Sorry for the long delay.  Thanks.

Ian

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gold patch] Incremental 11/18: update GOT/PLT
  2011-05-21 16:52 ` Ian Lance Taylor
@ 2011-05-23 23:36   ` Cary Coutant
  0 siblings, 0 replies; 4+ messages in thread
From: Cary Coutant @ 2011-05-23 23:36 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Binutils

> I think these functions are complex enough that they should move from
> output.h to output.cc.

Done.

> This is OK with those changes.

Thanks, committed with one tiny additional change to
testsuite/object_unittest.cc to fix a test failure. This was a piece
of Patch 14 (I didn't quite get the order right when doing the git
rebase -i).

	* testsuite/object_unittest.cc (Object_test): Set default options.

New changelog entry and the missing piece diff chunk below.

-cary


	* gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
	* incremental-dump.cc (dump_incremental_inputs): Mask high-order
	bit when checking got_type.
	* incremental.cc (Sized_incremental_binary::setup_readers):
	Store symbol table and string table locations; initialize bit vector
	of file status flags.
	(Sized_incremental_binary::do_reserve_layout): Set bit flag for
	unchanged files.
	(Sized_incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::get_symtab_view): Use stored locations.
	(Output_section_incremental_inputs::set_final_data_size): Record
	file index for each input file.
	(Output_section_incremental_inputs::write_got_plt): Store file index
	instead of input entry offset for each GOT entry.
	* incremental.h
	(Incremental_input_entry::Incremental_input_entry): Initialize new
	data member.
	(Incremental_input_entry::set_offset): Store file index.
	(Incremental_input_entry::get_file_index): New function.
	(Incremental_input_entry::file_index_): New data member.
	(Incremental_binary::process_got_plt): New function.
	(Incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::Sized_incremental_binary): Initialize new
	data members.
	(Sized_incremental_binary::~Sized_incremental_binary): New destructor.
	(Sized_incremental_binary::set_file_is_unchanged): New function.
	(Sized_incremental_binary::file_is_unchanged): New function.
	(Sized_incremental_binary::do_process_got_plt): New function.
	(Sized_incremental_binary::file_status_): New data member.
	(Sized_incremental_binary::main_symtab_loc_): New data member.
	(Sized_incremental_binary::main_strtab_loc_): New data member.
	* output.cc (Output_data_got::Got_entry::write): Add case
	RESERVED_CODE.
	(Output_data_got::add_global): Call add_got_entry.
	(Output_data_got::add_global_plt): Likewise.
	(Output_data_got::add_global_with_rel): Likewise.
	(Output_data_got::add_global_with_rela): Likewise.
	(Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair.
	(Output_data_got::add_global_pair_with_rela): Likewise.
	(Output_data_got::add_local): Call add_got_entry.
	(Output_data_got::add_local_plt): Likewise.
	(Output_data_got::add_local_with_rel): Likewise.
	(Output_data_got::add_local_with_rela): Likewise.
	(Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair.
	(Output_data_got::add_local_pair_with_rela): Likewise.
	(Output_data_got::reserve_slot): New function.
	(Output_data_got::reserve_slot_for_global): New function.
	(Output_data_got::add_got_entry): New function.
	(Output_data_got::add_got_entry_pair): New function.
	(Output_section::add_output_section_data): Edit FIXME.
	* output.h
	(Output_section_data_build::Output_section_data_build): New
	constructor with size parameter.
	(Output_data_space::Output_data_space): Likewise.
	(Output_data_got::Output_data_got): Initialize new data member; new
	constructor with size parameter.
	(Output_data_got::add_constant): Call add_got_entry.
	(Output_data_got::reserve_slot): New function.
	(Output_data_got::reserve_slot_for_global): New function.
	(class Output_data_got::Got_entry): Add RESERVED_CODE.
	(Output_data_got::add_got_entry): New function.
	(Output_data_got::add_got_entry_pair): New function.
	(Output_data_got::free_list_): New data member.
	* target.h (Sized_target::init_got_plt_for_update): New function.
	(Sized_target::register_global_plt_entry): New function.
	* x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
	Initialize new data member; call init; add constructor with PLT count.
	(Output_data_plt_x86_64::init): New function.
	(Output_data_plt_x86_64::add_relocation): New function.
	(Output_data_plt_x86_64::reserve_slot): New function.
	(Output_data_plt_x86_64::free_list_): New data member.
	(Target_x86_64::init_got_plt_for_update): New function.
	(Target_x86_64::register_global_plt_entry): New function.
	(Output_data_plt_x86_64::add_entry): Allocate from free list for
	incremental updates.
	(Output_data_plt_x86_64::add_relocation): New function.
	* testsuite/object_unittest.cc (Object_test): Set default options.


diff --git a/gold/testsuite/object_unittest.cc
b/gold/testsuite/object_unittest.cc
index 0451add..7dedeae 100644
--- a/gold/testsuite/object_unittest.cc
+++ b/gold/testsuite/object_unittest.cc
@@ -23,6 +23,8 @@
 #include "gold.h"

 #include "object.h"
+#include "options.h"
+#include "parameters.h"

 #include "test.h"
 #include "testfile.h"
@@ -62,8 +64,11 @@ Sized_object_test(const unsigned char* test_file,
unsigned int test_file_size)
 bool
 Object_test(Test_report*)
 {
+  General_options options;
   int fail = 0;

+  set_parameters_options(&options);
+
 #ifdef HAVE_TARGET_32_LITTLE
   if (!Sized_object_test<32, false>(test_file_1_32_little,
 				    test_file_1_size_32_little))

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-05-23 23:36 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-01 21:36 [gold patch] Incremental 11/18: update GOT/PLT Cary Coutant
2011-05-18 18:50 ` Cary Coutant
2011-05-21 16:52 ` Ian Lance Taylor
2011-05-23 23:36   ` Cary Coutant

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).