This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gold patch 2/3] Support for incremental linking: write incremental got_plt info


elfcpp/ChangeLog:

	* elfcpp.h (enum SHT): Add SHT_GNU_INCREMENTAL_GOT_PLT.

gold/ChangeLog:

	* arm.cc (Target_arm::got_size): Add const.
	(Target_arm::got_entry_count): New function.
	(Target_arm::plt_entry_count): New function.
	(Target_arm::first_plt_entry_offset): New function.
	(Target_arm::plt_entry_size): New function.
	(Output_data_plt_arm::entry_count): New function.
	(Output_data_plt_arm::first_plt_entry_offset): New function.
	(Output_data_plt_arm::get_plt_entry_size): New function.
	* i386.cc (Target_i386::got_size): Add const.
	(Target_i386::got_entry_count): New function.
	(Target_i386::plt_entry_count): New function.
	(Target_i386::first_plt_entry_offset): New function.
	(Target_i386::plt_entry_size): New function.
	(Output_data_plt_i386::entry_count): New function.
	(Output_data_plt_i386::first_plt_entry_offset): New function.
	(Output_data_plt_i386::get_plt_entry_size): New function.
	* incremental-dump.cc (dump_incremental_inputs): Adjust call to
	find_incremental_inputs_sections.  Dump incremental_got_plt section.
	* incremental.cc: Include target.h.
	(Sized_incremental_binary::do_find_incremental_inputs_sections): Add
	parameter.  Adjust all callers.  Find incremental_got_plt section.
	(Incremental_inputs::create_data_sections): Create incremental_got_plt
	section.
	(Output_section_incremental_inputs::set_final_data_size): Calculate
	size of incremental_got_plt section.
	(Output_section_incremental_inputs::do_write): Write the
	incremental_got_plt section.
	(Got_plt_view_info): New struct.
	(Local_got_offset_visitor): New class.
	(Global_got_offset_visitor): New class.
	(Global_symbol_visitor_got_plt): New class.
	(Output_section_incremental_inputs::write_got_plt): New function.
	* incremental.h (Incremental_binary::find_incremental_inputs_sections):
	Add parameter.  Adjust all callers.
	(Incremental_binary::do_find_incremental_inputs_sections): Likewise.
	(Incremental_inputs::got_plt_section): New function.
	(Incremental_inputs::got_plt_section_): New data member.
	(Incremental_got_plt_reader): New class.
	* layout.cc (Layout::create_incremental_info_sections): Add the
	incremental_got_plt section.
	* object.h (Got_offset_list::get_list): New function.
	(Got offset_list::for_all_got_offsets): New function.
	(Sized_relobj::local_got_offset_list): New function.
	* powerpc.cc (Target_powerpc::got_size): Add const.
	(Target_powerpc::got_entry_count): New function.
	(Target_powerpc::plt_entry_count): New function.
	(Target_powerpc::first_plt_entry_offset): New function.
	(Target_powerpc::plt_entry_size): New function.
	(Output_data_plt_powerpc::entry_count): New function.
	(Output_data_plt_powerpc::first_plt_entry_offset): New function.
	(Output_data_plt_powerpc::get_plt_entry_size): New function.
	* sparc.cc (Target_sparc::got_size): Add const.
	(Target_sparc::got_entry_count): New function.
	(Target_sparc::plt_entry_count): New function.
	(Target_sparc::first_plt_entry_offset): New function.
	(Target_sparc::plt_entry_size): New function.
	(Output_data_plt_sparc::entry_count): New function.
	(Output_data_plt_sparc::first_plt_entry_offset): New function.
	(Output_data_plt_sparc::get_plt_entry_size): New function.
	* symtab.h (Symbol::got_offset_list): New function.
	(Symbol_table::for_all_symbols): New function.
	* target.h (Sized_target::got_entry_count): New function.
	(Sized_target::plt_entry_count): New function.
	(Sized_target::plt_entry_size): New function.
	* x86_64.cc (Target_x86_64::got_size): Add const.
	(Target_x86_64::got_entry_count): New function.
	(Target_x86_64::plt_entry_count): New function.
	(Target_x86_64::first_plt_entry_offset): New function.
	(Target_x86_64::plt_entry_size): New function.
	(Output_data_plt_x86_64::entry_count): New function.
	(Output_data_plt_x86_64::first_plt_entry_offset): New function.
	(Output_data_plt_x86_64::get_plt_entry_size): New function.
---
 elfcpp/elfcpp.h          |    1 +
 gold/arm.cc              |   67 +++++++++++++-
 gold/i386.cc             |   64 +++++++++++++-
 gold/incremental-dump.cc |   64 +++++++++++---
 gold/incremental.cc      |  227 +++++++++++++++++++++++++++++++++++++++++++++-
 gold/incremental.h       |   83 ++++++++++++++++-
 gold/layout.cc           |   11 ++
 gold/object.h            |   31 ++++++
 gold/powerpc.cc          |   67 +++++++++++++-
 gold/sparc.cc            |   67 +++++++++++++-
 gold/symtab.h            |   19 ++++
 gold/target.h            |   32 +++++++
 gold/x86_64.cc           |   64 +++++++++++++-
 13 files changed, 773 insertions(+), 24 deletions(-)

diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index c46fbf5..b3eff64 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -367,6 +367,7 @@ enum SHT
   SHT_GNU_INCREMENTAL_INPUTS = 0x6fff4700,
   SHT_GNU_INCREMENTAL_SYMTAB = 0x6fff4701,
   SHT_GNU_INCREMENTAL_RELOCS = 0x6fff4702,
+  SHT_GNU_INCREMENTAL_GOT_PLT = 0x6fff4703,
   // Object attributes.
   SHT_GNU_ATTRIBUTES = 0x6ffffff5,
   // GNU style dynamic hash table.
diff --git a/gold/arm.cc b/gold/arm.cc
index 5d25533..3bcf10f 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -2342,12 +2342,33 @@ class Target_arm : public Sized_target<32, big_endian>
 
   // Return the size of the GOT section.
   section_size_type
-  got_size()
+  got_size() const
   {
     gold_assert(this->got_ != NULL);
     return this->got_->data_size();
   }
 
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (!this->has_got_section())
+      return 0;
+    return this->got_size() / 4;
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
   // Map platform-specific reloc types
   static unsigned int
   get_real_reloc_type (unsigned int r_type);
@@ -7111,6 +7132,21 @@ class Output_data_plt_arm : public Output_section_data
   rel_plt() const
   { return this->rel_; }
 
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return sizeof(first_plt_entry); }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return sizeof(plt_entry); }
+
  protected:
   void
   do_adjust_output_section(Output_section* os);
@@ -7326,6 +7362,35 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
   this->plt_->add_entry(gsym);
 }
 
+// Return the number of entries in the PLT.
+
+template<bool big_endian>
+unsigned int
+Target_arm<big_endian>::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+template<bool big_endian>
+unsigned int
+Target_arm<big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_arm<big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<bool big_endian>
+unsigned int
+Target_arm<big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_arm<big_endian>::get_plt_entry_size();
+}
+
 // Get the section to use for TLS_DESC relocations.
 
 template<bool big_endian>
diff --git a/gold/i386.cc b/gold/i386.cc
index b4040c1..629f480 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -185,12 +185,33 @@ class Target_i386 : public Target_freebsd<32, false>
 
   // Return the size of the GOT section.
   section_size_type
-  got_size()
+  got_size() const
   {
     gold_assert(this->got_ != NULL);
     return this->got_->data_size();
   }
 
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_size() / 4;
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
  private:
   // The class which scans relocations.
   struct Scan
@@ -584,6 +605,21 @@ class Output_data_plt_i386 : public Output_section_data
   Reloc_section*
   rel_tls_desc(Layout*);
 
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return plt_entry_size; }
+
  protected:
   void
   do_adjust_output_section(Output_section* os);
@@ -849,6 +885,32 @@ Target_i386::make_plt_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym)
   this->plt_->add_entry(gsym);
 }
 
+// Return the number of entries in the PLT.
+
+unsigned int
+Target_i386::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+unsigned int
+Target_i386::first_plt_entry_offset() const
+{
+  return Output_data_plt_i386::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+unsigned int
+Target_i386::plt_entry_size() const
+{
+  return Output_data_plt_i386::get_plt_entry_size();
+}
+
 // Get the section to use for TLS_DESC relocations.
 
 Target_i386::Reloc_section*
diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc
index e8ad272..43529d2 100644
--- a/gold/incremental-dump.cc
+++ b/gold/incremental-dump.cc
@@ -79,6 +79,7 @@ dump_incremental_inputs(const char* argv0, const char* filename,
   unsigned int inputs_shndx;
   unsigned int isymtab_shndx;
   unsigned int irelocs_shndx;
+  unsigned int igot_plt_shndx;
   unsigned int istrtab_shndx;
   typedef Incremental_binary::Location Location;
   typedef Incremental_binary::View View;
@@ -88,7 +89,8 @@ dump_incremental_inputs(const char* argv0, const char* filename,
   // Find the .gnu_incremental_inputs, _symtab, _relocs, and _strtab sections.
 
   t = inc->find_incremental_inputs_sections(&inputs_shndx, &isymtab_shndx,
-					    &irelocs_shndx, &istrtab_shndx);
+					    &irelocs_shndx, &igot_plt_shndx,
+					    &istrtab_shndx);
   if (!t)
     {
       fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0,
@@ -134,9 +136,7 @@ dump_incremental_inputs(const char* argv0, const char* filename,
   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);
+      Entry_reader input_file = incremental_inputs.input_file(i);
 
       const char* objname = input_file.filename();
       if (objname == NULL)
@@ -203,10 +203,6 @@ dump_incremental_inputs(const char* argv0, const char* filename,
   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
@@ -241,10 +237,6 @@ dump_incremental_inputs(const char* argv0, const char* filename,
   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
@@ -374,6 +366,54 @@ dump_incremental_inputs(const char* argv0, const char* filename,
       isym_p += 4;
     }
 
+  // Get a view of the .gnu_incremental_got_plt section.
+
+  Location igot_plt_location(elf_file.section_contents(igot_plt_shndx));
+  View igot_plt_view(inc->view(igot_plt_location));
+
+  Incremental_got_plt_reader<big_endian> igot_plt(igot_plt_view.data());
+  unsigned int ngot = igot_plt.get_got_entry_count();
+  unsigned int nplt = igot_plt.get_plt_entry_count();
+  
+  printf("\nGOT entries:\n");
+  for (unsigned int i = 0; i < ngot; ++i)
+    {
+      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)
+	printf("reserved");
+      else if (got_type & 0x80)
+	{
+	  Entry_reader input_file = incremental_inputs.input_file(got_desc);
+	  const char* objname = input_file.filename();
+	  printf("local: %s (%d)", objname, got_desc);
+	}
+      else
+	{
+	  sym_p = symtab_view.data() + got_desc * sym_size;
+	  elfcpp::Sym<size, big_endian> sym(sym_p);
+	  const char* symname;
+	  if (!strtab.get_c_string(sym.get_st_name(), &symname))
+	    symname = "<unknown>";
+	  printf("global %s (%d)", symname, got_desc);
+	}
+      printf("\n");
+    }
+
+  printf("\nPLT entries:\n");
+  for (unsigned int i = 0; i < nplt; ++i)
+    {
+      unsigned int plt_desc = igot_plt.get_plt_desc(i);
+      printf("[%d] ", i);
+      sym_p = symtab_view.data() + plt_desc * sym_size;
+      elfcpp::Sym<size, big_endian> sym(sym_p);
+      const char* symname;
+      if (!strtab.get_c_string(sym.get_st_name(), &symname))
+	symname = "<unknown>";
+      printf("%s (%d)\n", symname, plt_desc);
+    }
+
   printf("\nUnused archive symbols:\n");
   for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
     {
diff --git a/gold/incremental.cc b/gold/incremental.cc
index 50b7482..6ba4234 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -32,6 +32,7 @@
 #include "archive.h"
 #include "output.h"
 #include "target-select.h"
+#include "target.h"
 
 namespace gold {
 
@@ -88,6 +89,10 @@ class Output_section_incremental_inputs : public Output_section_data
   write_symtab(unsigned char* pov, unsigned int* global_syms,
 	       unsigned int global_sym_count);
 
+  // Write the contents of the .gnu_incremental_got_plt section.
+  void
+  write_got_plt(unsigned char* pov, off_t view_size);
+
   // Typedefs for writing the data to the output sections.
   typedef elfcpp::Swap<size, big_endian> Swap;
   typedef elfcpp::Swap<16, big_endian> Swap16;
@@ -153,6 +158,7 @@ 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_got_plt_shndx,
     unsigned int* p_strtab_shndx)
 {
   unsigned int inputs_shndx =
@@ -174,6 +180,13 @@ Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_sections(
   if (this->elf_file_.section_link(relocs_shndx) != inputs_shndx)
     return false;
 
+  unsigned int got_plt_shndx =
+      this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_GOT_PLT);
+  if (got_plt_shndx == elfcpp::SHN_UNDEF)  // Not found.
+    return false;
+  if (this->elf_file_.section_link(got_plt_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()
@@ -186,6 +199,8 @@ Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_sections(
     *p_symtab_shndx = symtab_shndx;
   if (p_relocs_shndx != NULL)
     *p_relocs_shndx = relocs_shndx;
+  if (p_got_plt_shndx != NULL)
+    *p_got_plt_shndx = got_plt_shndx;
   if (p_strtab_shndx != NULL)
     *p_strtab_shndx = strtab_shndx;
   return true;
@@ -202,10 +217,12 @@ Sized_incremental_binary<size, big_endian>::do_check_inputs(
   unsigned int inputs_shndx;
   unsigned int symtab_shndx;
   unsigned int relocs_shndx;
+  unsigned int plt_got_shndx;
   unsigned int strtab_shndx;
 
   if (!do_find_incremental_inputs_sections(&inputs_shndx, &symtab_shndx,
-					   &relocs_shndx, &strtab_shndx))
+					   &relocs_shndx, &plt_got_shndx,
+					   &strtab_shndx))
     {
       explain_no_incremental(_("no incremental data from previous build"));
       return false;
@@ -555,6 +572,7 @@ Incremental_inputs::create_data_sections(Symbol_table* symtab)
     }
   this->symtab_section_ = new Output_data_space(4, "** incremental_symtab");
   this->relocs_section_ = new Output_data_space(4, "** incremental_relocs");
+  this->got_plt_section_ = new Output_data_space(4, "** incremental_got_plt");
 }
 
 // Return the sh_entsize value for the .gnu_incremental_relocs section.
@@ -657,6 +675,16 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
   // Set the size of the .gnu_incremental_relocs section.
   inputs->relocs_section()->set_current_data_size(inputs->get_reloc_count()
 						  * rel_size);
+
+  // Set the size of the .gnu_incremental_got_plt section.
+  Sized_target<size, big_endian>* target =
+    parameters->sized_target<size, big_endian>();
+  unsigned int got_count = target->got_entry_count();
+  unsigned int plt_count = target->plt_entry_count();
+  unsigned int got_plt_size = 8;  // GOT entry count, PLT entry count.
+  got_plt_size = (got_plt_size + got_count + 3) & ~3;  // GOT type array.
+  got_plt_size += got_count * 4 + plt_count * 4;  // GOT array, PLT array.
+  inputs->got_plt_section()->set_current_data_size(got_plt_size);
 }
 
 // Write the contents of the .gnu_incremental_inputs and
@@ -711,8 +739,16 @@ Output_section_incremental_inputs<size, big_endian>::do_write(Output_file* of)
 
   delete[] global_syms;
 
+  // Write the .gnu_incremental_got_plt section.
+  const off_t got_plt_off = inputs->got_plt_section()->offset();
+  const off_t got_plt_size = inputs->got_plt_section()->data_size();
+  unsigned char* const got_plt_view = of->get_output_view(got_plt_off,
+							  got_plt_size);
+  this->write_got_plt(got_plt_view, got_plt_size);
+
   of->write_output_view(off, oview_size, oview);
   of->write_output_view(symtab_off, symtab_size, symtab_view);
+  of->write_output_view(got_plt_off, got_plt_size, got_plt_view);
 }
 
 // Write the section header: version, input file count, offset of command line
@@ -936,6 +972,195 @@ Output_section_incremental_inputs<size, big_endian>::write_symtab(
     }
 }
 
+// This struct holds the view information needed to write the
+// .gnu_incremental_got_plt section.
+
+struct Got_plt_view_info
+{
+  // Start of the GOT type array in the output view.
+  unsigned char* got_type_p;
+  // Start of the GOT descriptor array in the output view.
+  unsigned char* got_desc_p;
+  // Start of the PLT descriptor array in the output view.
+  unsigned char* plt_desc_p;
+  // Number of GOT entries.
+  unsigned int got_count;
+  // Number of PLT entries.
+  unsigned int plt_count;
+  // Offset of the first non-reserved PLT entry (this is a target-dependent value).
+  unsigned int first_plt_entry_offset;
+  // Size of a PLT entry (this is a target-dependent value).
+  unsigned int plt_entry_size;
+  // Value to write in the GOT descriptor array.  For global symbols,
+  // this is the global symbol table index; for local symbols, it is
+  // the offset of the input file entry in the .gnu_incremental_inputs
+  // section.
+  unsigned int got_descriptor;
+};
+
+// Functor class for processing a GOT offset list for local symbols.
+// Writes the GOT type and symbol index into the GOT type and descriptor
+// arrays in the output section.
+
+template<int size, bool big_endian>
+class Local_got_offset_visitor
+{
+ public:
+  Local_got_offset_visitor(struct Got_plt_view_info& info)
+    : info_(info)
+  { }
+
+  void
+  operator()(unsigned int got_type, unsigned int got_offset)
+  {
+    unsigned int got_index = got_offset / this->got_entry_size_;
+    gold_assert(got_index < this->info_.got_count);
+    // We can only handle GOT entry types in the range 0..0x7e
+    // because we use a byte array to store them, and we use the
+    // high bit to flag a local symbol.
+    gold_assert(got_type < 0x7f);
+    this->info_.got_type_p[got_index] = got_type | 0x80;
+    unsigned char* pov = this->info_.got_desc_p + got_index * 4;
+    elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.got_descriptor);
+  }
+
+ private:
+  static const unsigned int got_entry_size_ = size / 8;
+  struct Got_plt_view_info& info_;
+};
+
+// Functor class for processing a GOT offset list.  Writes the GOT type
+// and symbol index into the GOT type and descriptor arrays in the output
+// section.
+
+template<int size, bool big_endian>
+class Global_got_offset_visitor
+{
+ public:
+  Global_got_offset_visitor(struct Got_plt_view_info& info)
+    : info_(info)
+  { }
+
+  void
+  operator()(unsigned int got_type, unsigned int got_offset)
+  {
+    unsigned int got_index = got_offset / this->got_entry_size_;
+    gold_assert(got_index < this->info_.got_count);
+    // We can only handle GOT entry types in the range 0..0x7e
+    // because we use a byte array to store them, and we use the
+    // high bit to flag a local symbol.
+    gold_assert(got_type < 0x7f);
+    this->info_.got_type_p[got_index] = got_type;
+    unsigned char* pov = this->info_.got_desc_p + got_index * 4;
+    elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.got_descriptor);
+  }
+
+ private:
+  static const unsigned int got_entry_size_ = size / 8;
+  struct Got_plt_view_info& info_;
+};
+
+// Functor class for processing the global symbol table.  Processes the
+// GOT offset list for the symbol, and writes the symbol table index
+// into the PLT descriptor array in the output section.
+
+template<int size, bool big_endian>
+class Global_symbol_visitor_got_plt
+{
+ public:
+  Global_symbol_visitor_got_plt(struct Got_plt_view_info& info)
+    : info_(info)
+  { }
+
+  void
+  operator()(const Sized_symbol<size>* sym)
+  {
+    typedef Global_got_offset_visitor<size, big_endian> Got_visitor;
+    const Got_offset_list* got_offsets = sym->got_offset_list();
+    if (got_offsets != NULL)
+      {
+        info_.got_descriptor = sym->symtab_index();
+	got_offsets->for_all_got_offsets(Got_visitor(info_));
+      }
+    if (sym->has_plt_offset())
+      {
+	unsigned int plt_index =
+	    ((sym->plt_offset() - this->info_.first_plt_entry_offset)
+	     / this->info_.plt_entry_size);
+	gold_assert(plt_index < this->info_.plt_count);
+	unsigned char* pov = this->info_.plt_desc_p + plt_index * 4;
+	elfcpp::Swap<32, big_endian>::writeval(pov, sym->symtab_index());
+      }
+  }
+
+ private:
+  struct Got_plt_view_info& info_;
+};
+
+// Write the contents of the .gnu_incremental_got_plt section.
+
+template<int size, bool big_endian>
+void
+Output_section_incremental_inputs<size, big_endian>::write_got_plt(
+    unsigned char* pov,
+    off_t view_size)
+{
+  Sized_target<size, big_endian>* target =
+    parameters->sized_target<size, big_endian>();
+
+  // Set up the view information for the functors.
+  struct Got_plt_view_info view_info;
+  view_info.got_count = target->got_entry_count();
+  view_info.plt_count = target->plt_entry_count();
+  view_info.first_plt_entry_offset = target->first_plt_entry_offset();
+  view_info.plt_entry_size = target->plt_entry_size();
+  view_info.got_type_p = pov + 8;
+  view_info.got_desc_p = (view_info.got_type_p
+			  + ((view_info.got_count + 3) & ~3));
+  view_info.plt_desc_p = view_info.got_desc_p + view_info.got_count * 4;
+
+  gold_assert(pov + view_size ==
+	      view_info.plt_desc_p + view_info.plt_count * 4);
+
+  // Write the section header.
+  Swap32::writeval(pov, view_info.got_count);
+  Swap32::writeval(pov + 4, view_info.plt_count);
+
+  // Initialize the GOT type array to 0xff (reserved).
+  memset(view_info.got_type_p, 0xff, view_info.got_count);
+
+  // Write the incremental GOT descriptors for local symbols.
+  for (Incremental_inputs::Input_list::const_iterator p =
+	   this->inputs_->input_files().begin();
+       p != this->inputs_->input_files().end();
+       ++p)
+    {
+      if ((*p)->type() != INCREMENTAL_INPUT_OBJECT
+	  && (*p)->type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
+	continue;
+      Incremental_object_entry* entry = (*p)->object_entry();
+      gold_assert(entry != NULL);
+      const Sized_relobj<size, big_endian>* obj =
+          static_cast<Sized_relobj<size, big_endian>*>(entry->object());
+      gold_assert(obj != NULL);
+      unsigned int nsyms = obj->local_symbol_count();
+      for (unsigned int i = 0; i < nsyms; i++)
+        {
+          const Got_offset_list* got_offsets = obj->local_got_offset_list(i);
+          if (got_offsets != NULL)
+            {
+	      typedef Local_got_offset_visitor<size, big_endian> Got_visitor;
+	      view_info.got_descriptor = (*p)->get_offset();
+	      got_offsets->for_all_got_offsets(Got_visitor(view_info));
+	    }
+	}
+    }
+
+  // Write the incremental GOT and PLT descriptors for global symbols.
+  typedef Global_symbol_visitor_got_plt<size, big_endian> Symbol_visitor;
+  symtab_->for_all_symbols<size, Symbol_visitor>(Symbol_visitor(view_info));
+}
+
 // Instantiate the templates we need.
 
 #ifdef HAVE_TARGET_32_LITTLE
diff --git a/gold/incremental.h b/gold/incremental.h
index 979a94d..cd03217 100644
--- a/gold/incremental.h
+++ b/gold/incremental.h
@@ -131,10 +131,12 @@ class Incremental_binary
   find_incremental_inputs_sections(unsigned int* p_inputs_shndx,
 				   unsigned int* p_symtab_shndx,
 				   unsigned int* p_relocs_shndx,
+				   unsigned int* p_got_plt_shndx,
 				   unsigned int* p_strtab_shndx)
   {
     return do_find_incremental_inputs_sections(p_inputs_shndx, p_symtab_shndx,
-					       p_relocs_shndx, p_strtab_shndx);
+					       p_relocs_shndx, p_got_plt_shndx,
+  					       p_strtab_shndx);
   }
 
   // Check the .gnu_incremental_inputs section to see whether an incremental
@@ -153,6 +155,7 @@ class Incremental_binary
   do_find_incremental_inputs_sections(unsigned int* p_inputs_shndx,
 				      unsigned int* p_symtab_shndx,
 				      unsigned int* p_relocs_shndx,
+				      unsigned int* p_got_plt_shndx,
 				      unsigned int* p_strtab_shndx) = 0;
 
   // Check the .gnu_incremental_inputs section to see whether an incremental
@@ -182,6 +185,7 @@ class Sized_incremental_binary : public Incremental_binary
   do_find_incremental_inputs_sections(unsigned int* p_inputs_shndx,
 				      unsigned int* p_symtab_shndx,
 				      unsigned int* p_relocs_shndx,
+				      unsigned int* p_got_plt_shndx,
 				      unsigned int* p_strtab_shndx);
 
   virtual bool
@@ -577,6 +581,11 @@ class Incremental_inputs
   relocs_section() const
   { return this->relocs_section_; }
 
+  // Return the .gnu_incremental_got_plt section.
+  Output_data_space*
+  got_plt_section() const
+  { return this->got_plt_section_; }
+
   // Return the .gnu_incremental_strtab stringpool.
   Stringpool*
   get_stringpool() const
@@ -635,6 +644,9 @@ class Incremental_inputs
   // The .gnu_incremental_relocs section.
   Output_data_space* relocs_section_;
 
+  // The .gnu_incremental_got_plt section.
+  Output_data_space* got_plt_section_;
+
   // Total count of incremental relocations.  Updated during Scan_relocs
   // phase at the completion of each object file.
   unsigned int reloc_count_;
@@ -889,7 +901,7 @@ class Incremental_symtab_reader
   { }
 
   // Return the list head for symbol table entry N.
-  unsigned int get_list_head(unsigned int n)
+  unsigned int get_list_head(unsigned int n) const
   { return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4 * n); }
 
  private:
@@ -918,28 +930,28 @@ class Incremental_relocs_reader
 
   // Return the relocation type for relocation entry at offset OFF.
   unsigned int
-  get_r_type(unsigned int off)
+  get_r_type(unsigned int off) const
   {
     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)
+  get_r_shndx(unsigned int off) const
   {
     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)
+  get_r_offset(unsigned int off) const
   {
     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)
+  get_r_addend(unsigned int off) const
   {
     return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8
 						   + this->field_size);
@@ -950,6 +962,65 @@ class Incremental_relocs_reader
   const unsigned char* p_;
 };
 
+// Reader class for the .gnu_incremental_got_plt section.
+
+template<bool big_endian>
+class Incremental_got_plt_reader
+{
+ public:
+  Incremental_got_plt_reader(const unsigned char* p) : p_(p)
+  {
+    this->got_count_ = elfcpp::Swap<32, big_endian>::readval(p);
+    this->got_desc_p_ = p + 8 + ((this->got_count_ + 3) & ~3);
+    this->plt_desc_p_ = this->got_desc_p_ + this->got_count_ * 4;
+  }
+
+  // Return the GOT entry count.
+  unsigned int
+  get_got_entry_count() const
+  {
+    return this->got_count_;
+  }
+
+  // Return the PLT entry count.
+  unsigned int
+  get_plt_entry_count() const
+  {
+    return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4);
+  }
+
+  // Return the GOT type for GOT entry N.
+  unsigned int
+  get_got_type(unsigned int n)
+  {
+    return this->p_[8 + n];
+  }
+
+  // Return the GOT descriptor for GOT entry N.
+  unsigned int
+  get_got_desc(unsigned int n)
+  {
+    return elfcpp::Swap<32, big_endian>::readval(this->got_desc_p_ + n * 4);
+  }
+
+  // Return the PLT descriptor for PLT entry N.
+  unsigned int
+  get_plt_desc(unsigned int n)
+  {
+    return elfcpp::Swap<32, big_endian>::readval(this->plt_desc_p_ + n * 4);
+  }
+
+ private:
+  // Base address of the .gnu_incremental_got_plt section.
+  const unsigned char* p_;
+  // GOT entry count.
+  unsigned int got_count_;
+  // Base address of the GOT descriptor array.
+  const unsigned char* got_desc_p_;
+  // Base address of the PLT descriptor array.
+  const unsigned char* plt_desc_p_;
+};
+
 } // End namespace gold.
 
 #endif // !defined(GOLD_INCREMENTAL_H)
diff --git a/gold/layout.cc b/gold/layout.cc
index eb1322a..1dd41f3 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -2342,6 +2342,15 @@ Layout::create_incremental_info_sections(Symbol_table* symtab)
   incremental_relocs_os->add_output_section_data(incr->relocs_section());
   incremental_relocs_os->set_entsize(incr->relocs_entsize());
 
+  // Add the .gnu_incremental_got_plt section.
+  const char *incremental_got_plt_name =
+    this->namepool_.add(".gnu_incremental_got_plt", false, NULL);
+  Output_section* incremental_got_plt_os =
+    this->make_output_section(incremental_got_plt_name,
+			      elfcpp::SHT_GNU_INCREMENTAL_GOT_PLT, 0,
+			      ORDER_INVALID, false);
+  incremental_got_plt_os->add_output_section_data(incr->got_plt_section());
+
   // Add the .gnu_incremental_strtab section.
   const char *incremental_strtab_name =
     this->namepool_.add(".gnu_incremental_strtab", false, NULL);
@@ -2355,10 +2364,12 @@ Layout::create_incremental_info_sections(Symbol_table* symtab)
   incremental_inputs_os->set_after_input_sections();
   incremental_symtab_os->set_after_input_sections();
   incremental_relocs_os->set_after_input_sections();
+  incremental_got_plt_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);
+  incremental_got_plt_os->set_link_section(incremental_inputs_os);
 }
 
 // Return whether SEG1 should be before SEG2 in the output file.  This
diff --git a/gold/object.h b/gold/object.h
index 99ceabf..94ad643 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -1479,6 +1479,26 @@ class Got_offset_list
     return -1U;
   }
 
+  // Return a pointer to the list, or NULL if the list is empty.
+  const Got_offset_list*
+  get_list() const
+  {
+    if (this->got_type_ == -1U)
+      return NULL;
+    return this;
+  }
+
+  // Loop over all GOT offset entries, applying the function F to each.
+  template<typename F>
+  void
+  for_all_got_offsets(F f) const
+  {
+    if (this->got_type_ == -1U)
+      return;
+    for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
+      f(g->got_type_, g->got_offset_);
+  }
+
  private:
   unsigned int got_type_;
   unsigned int got_offset_;
@@ -1661,6 +1681,17 @@ class Sized_relobj : public Relobj
       }
   }
 
+  // Return the GOT offset list for the local symbol SYMNDX.
+  const Got_offset_list*
+  local_got_offset_list(unsigned int symndx) const
+  {
+    Local_got_offsets::const_iterator p =
+        this->local_got_offsets_.find(symndx);
+    if (p == this->local_got_offsets_.end())
+      return NULL;
+    return p->second;
+  }
+
   // Get the offset of input section SHNDX within its output section.
   // This is -1 if the input section requires a special mapping, such
   // as a merge section.  The output section can be found in the
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 88bc378..6e9570d 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -151,12 +151,33 @@ class Target_powerpc : public Sized_target<size, big_endian>
 
   // Return the size of the GOT section.
   section_size_type
-  got_size()
+  got_size() const
   {
     gold_assert(this->got_ != NULL);
     return this->got_->data_size();
   }
 
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_size() / (size / 8);
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
  private:
 
   // The class which scans relocations.
@@ -808,6 +829,21 @@ class Output_data_plt_powerpc : public Output_section_data
     return this->rel_;
   }
 
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return 4 * base_plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return base_plt_entry_size; }
+
  protected:
   void do_adjust_output_section(Output_section* os);
 
@@ -993,6 +1029,35 @@ Target_powerpc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
   this->plt_->add_entry(gsym);
 }
 
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_powerpc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_powerpc<size, big_endian>::get_plt_entry_size();
+}
+
 // Create a GOT entry for the TLS module index.
 
 template<int size, bool big_endian>
diff --git a/gold/sparc.cc b/gold/sparc.cc
index 1635f33..f9f25f9 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -161,12 +161,33 @@ class Target_sparc : public Sized_target<size, big_endian>
 
   // Return the size of the GOT section.
   section_size_type
-  got_size()
+  got_size() const
   {
     gold_assert(this->got_ != NULL);
     return this->got_->data_size();
   }
 
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_size() / (size / 8);
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
  private:
 
   // The class which scans relocations.
@@ -1100,6 +1121,21 @@ class Output_data_plt_sparc : public Output_section_data
     return this->rel_;
   }
 
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return 4 * base_plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return base_plt_entry_size; }
+
  protected:
   void do_adjust_output_section(Output_section* os);
 
@@ -1415,6 +1451,35 @@ Target_sparc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
   this->plt_->add_entry(gsym);
 }
 
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_sparc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_sparc<size, big_endian>::get_plt_entry_size();
+}
+
 // Create a GOT entry for the TLS module index.
 
 template<int size, bool big_endian>
diff --git a/gold/symtab.h b/gold/symtab.h
index 4e5b7b0..8ccbca9 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -409,6 +409,11 @@ class Symbol
   set_got_offset(unsigned int got_type, unsigned int got_offset)
   { this->got_offsets_.set_offset(got_type, got_offset); }
 
+  // Return the GOT offset list.
+  const Got_offset_list*
+  got_offset_list() const
+  { return this->got_offsets_.get_list(); }
+
   // Return whether this symbol has an entry in the PLT section.
   bool
   has_plt_offset() const
@@ -1489,6 +1494,20 @@ class Symbol_table
   write_section_symbol(const Output_section*, Output_symtab_xindex*,
 		       Output_file*, off_t) const;
 
+  // Loop over all symbols, applying the function F to each.
+  template<int size, typename F>
+  void
+  for_all_symbols(F f) const
+  {
+    for (Symbol_table_type::const_iterator p = this->table_.begin();
+         p != this->table_.end();
+         ++p)
+      {
+	Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+	f(sym);
+      }
+  }
+
   // Dump statistical information to stderr.
   void
   print_stats() const;
diff --git a/gold/target.h b/gold/target.h
index 9f9c4f9..0af83f6 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -732,6 +732,38 @@ class Sized_target : public Target
 			       unsigned char* /* preloc_out*/)
   { gold_unreachable(); }
  
+  // Return the number of entries in the GOT.  This is only used for
+  // laying out the incremental link info sections.  A target needs
+  // to implement this to support incremental linking.
+
+  virtual unsigned int
+  got_entry_count() const
+  { gold_unreachable(); }
+
+  // Return the number of entries in the PLT.  This is only used for
+  // laying out the incremental link info sections.  A target needs
+  // to implement this to support incremental linking.
+
+  virtual unsigned int
+  plt_entry_count() const
+  { gold_unreachable(); }
+
+  // Return the offset of the first non-reserved PLT entry.  This is
+  // only used for laying out the incremental link info sections.
+  // A target needs to implement this to support incremental linking.
+
+  virtual unsigned int
+  first_plt_entry_offset() const
+  { gold_unreachable(); }
+
+  // Return the size of each PLT entry.  This is only used for
+  // laying out the incremental link info sections.  A target needs
+  // to implement this to support incremental linking.
+
+  virtual unsigned int
+  plt_entry_size() const
+  { gold_unreachable(); }
+
  protected:
   Sized_target(const Target::Target_info* pti)
     : Target(pti)
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index abeff04..75a2cc6 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -197,12 +197,33 @@ class Target_x86_64 : public Target_freebsd<64, false>
 
   // Return the size of the GOT section.
   section_size_type
-  got_size()
+  got_size() const
   {
     gold_assert(this->got_ != NULL);
     return this->got_->data_size();
   }
 
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_size() / 8;
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
   // Add a new reloc argument, returning the index in the vector.
   size_t
   add_tlsdesc_info(Sized_relobj<64, false>* object, unsigned int r_sym)
@@ -659,6 +680,21 @@ class Output_data_plt_x86_64 : public Output_section_data
   Reloc_section*
   rela_tlsdesc(Layout*);
 
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return plt_entry_size; }
+
  protected:
   void
   do_adjust_output_section(Output_section* os);
@@ -960,6 +996,32 @@ Target_x86_64::make_plt_entry(Symbol_table* symtab, Layout* layout,
   this->plt_->add_entry(gsym);
 }
 
+// Return the number of entries in the PLT.
+
+unsigned int
+Target_x86_64::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+unsigned int
+Target_x86_64::first_plt_entry_offset() const
+{
+  return Output_data_plt_x86_64::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+unsigned int
+Target_x86_64::plt_entry_size() const
+{
+  return Output_data_plt_x86_64::get_plt_entry_size();
+}
+
 // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
 
 void

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]