* incremental.cc (Sized_incremental_binary::setup_readers): Allocate
authorCary Coutant <ccoutant@google.com>
Fri, 22 Apr 2011 22:39:55 +0000 (22:39 +0000)
committerCary Coutant <ccoutant@google.com>
Fri, 22 Apr 2011 22:39:55 +0000 (22:39 +0000)
global symbol map.
(Sized_incremental_binary::do_apply_incremental_relocs): New function.
(Sized_incr_relobj::do_add_symbols): Add symbols to global symbol map.
(Sized_incr_relobj::do_relocate): Remap section indices in incremental
relocations.
(Sized_incr_dynobj::do_add_symbols): Add symbols to global symbol map.
(Sized_incr_dynobj::do_for_all_global_symbols): Remove FIXME.
(Sized_incr_dynobj::do_for_all_local_got_entries): Likewise.
* incremental.h
(Incremental_inputs_reader::global_symbol_reader_at_offset): New
function.
(Incremental_binary::apply_incremental_relocs): New function.
(Incremental_binary::do_apply_incremental_relocs): New function.
(Sized_incremental_binary::Sized_incremental_binary): Initialize new
data member.
(Sized_incremental_binary::add_global_symbol): New function.
(Sized_incremental_binary::global_symbol): New function.
(Sized_incremental_binary::do_apply_incremental_relocs): New function.
(Sized_incremental_binary::symbol_map_): New data member.
* layout.cc (Layout_task_runner::run): Apply incremental relocations.
* target.h (Sized_target::apply_relocation): New function.
* target-reloc.h (apply_relocation): New function.
* x86_64.cc (Target_x86_64::apply_relocation): New function.

gold/ChangeLog
gold/incremental.cc
gold/incremental.h
gold/layout.cc
gold/target-reloc.h
gold/target.h
gold/x86_64.cc

index 865573e72948ac4dc3dd2417a3210bf927886943..c4c02f66702c94bb4bcdf3200c4e4d20990dbb8a 100644 (file)
@@ -1,3 +1,30 @@
+2011-04-22 Cary Coutant  <ccoutant@google.com>
+
+       * incremental.cc (Sized_incremental_binary::setup_readers): Allocate
+       global symbol map.
+       (Sized_incremental_binary::do_apply_incremental_relocs): New function.
+       (Sized_incr_relobj::do_add_symbols): Add symbols to global symbol map.
+       (Sized_incr_relobj::do_relocate): Remap section indices in incremental
+       relocations.
+       (Sized_incr_dynobj::do_add_symbols): Add symbols to global symbol map.
+       (Sized_incr_dynobj::do_for_all_global_symbols): Remove FIXME.
+       (Sized_incr_dynobj::do_for_all_local_got_entries): Likewise.
+       * incremental.h
+       (Incremental_inputs_reader::global_symbol_reader_at_offset): New
+       function.
+       (Incremental_binary::apply_incremental_relocs): New function.
+       (Incremental_binary::do_apply_incremental_relocs): New function.
+       (Sized_incremental_binary::Sized_incremental_binary): Initialize new
+       data member.
+       (Sized_incremental_binary::add_global_symbol): New function.
+       (Sized_incremental_binary::global_symbol): New function.
+       (Sized_incremental_binary::do_apply_incremental_relocs): New function.
+       (Sized_incremental_binary::symbol_map_): New data member.
+       * layout.cc (Layout_task_runner::run): Apply incremental relocations.
+       * target.h (Sized_target::apply_relocation): New function.
+       * target-reloc.h (apply_relocation): New function.
+       * x86_64.cc (Target_x86_64::apply_relocation): New function.
+
 2011-04-22  Doug Kwan  <dougkwan@google.com>
 
        * arm.cc (Arm_output_section::Arm_output_section): Set SHF_LINK_ORDER
index ba89e0569e37a9a27c247b6e8da43a070c44601b..3de22f197f12a05f47f65dfd3c53877b0fcc82dc 100644 (file)
@@ -310,6 +310,10 @@ Sized_incremental_binary<size, big_endian>::setup_readers()
        }
     }
 
+  // Initialize the map of global symbols.
+  unsigned int nglobals = this->symtab_reader_.symbol_count();
+  this->symbol_map_.resize(nglobals);
+
   this->has_incremental_info_ = true;
 }
 
@@ -519,6 +523,102 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout(
     }
 }
 
+// Apply incremental relocations for symbols whose values have changed.
+
+template<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_apply_incremental_relocs(
+    const Symbol_table* symtab,
+    Layout* layout,
+    Output_file* of)
+{
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+  typedef typename elfcpp::Elf_types<size>::Elf_Swxword Addend;
+  Incremental_symtab_reader<big_endian> isymtab(this->symtab_reader());
+  Incremental_relocs_reader<size, big_endian> irelocs(this->relocs_reader());
+  unsigned int nglobals = isymtab.symbol_count();
+  const unsigned int incr_reloc_size = irelocs.reloc_size;
+
+  Relocate_info<size, big_endian> relinfo;
+  relinfo.symtab = symtab;
+  relinfo.layout = layout;
+  relinfo.object = NULL;
+  relinfo.reloc_shndx = 0;
+  relinfo.reloc_shdr = NULL;
+  relinfo.data_shndx = 0;
+  relinfo.data_shdr = NULL;
+
+  Sized_target<size, big_endian>* target =
+      parameters->sized_target<size, big_endian>();
+
+  for (unsigned int i = 0; i < nglobals; i++)
+    {
+      const Symbol* gsym = this->global_symbol(i);
+
+      // If the symbol is not referenced from any unchanged input files,
+      // we do not need to reapply any of its relocations.
+      if (gsym == NULL)
+       continue;
+
+      // If the symbol is defined in an unchanged file, we do not need to
+      // reapply any of its relocations.
+      if (gsym->source() == Symbol::FROM_OBJECT
+         && gsym->object()->is_incremental())
+       continue;
+
+      gold_debug(DEBUG_INCREMENTAL,
+                "Applying incremental relocations for global symbol %s [%d]",
+                gsym->name(), i);
+
+      // Follow the linked list of input symbol table entries for this symbol.
+      // We don't bother to figure out whether the symbol table entry belongs
+      // to a changed or unchanged file because it's easier just to apply all
+      // the relocations -- although we might scribble over an area that has
+      // been reallocated, we do this before copying any new data into the
+      // output file.
+      unsigned int offset = isymtab.get_list_head(i);
+      while (offset > 0)
+        {
+         Incremental_global_symbol_reader<big_endian> sym_info =
+             this->inputs_reader().global_symbol_reader_at_offset(offset);
+         unsigned int r_base = sym_info.reloc_offset();
+         unsigned int r_count = sym_info.reloc_count();
+
+         // Apply each relocation for this symbol table entry.
+         for (unsigned int j = 0; j < r_count;
+              ++j, r_base += incr_reloc_size)
+           {
+             unsigned int r_type = irelocs.get_r_type(r_base);
+             unsigned int r_shndx = irelocs.get_r_shndx(r_base);
+             Address r_offset = irelocs.get_r_offset(r_base);
+             Addend r_addend = irelocs.get_r_addend(r_base);
+             Output_section* os = this->output_section(r_shndx);
+             Address address = os->address();
+             off_t section_offset = os->offset();
+             size_t view_size = os->data_size();
+             unsigned char* const view = of->get_output_view(section_offset,
+                                                             view_size);
+
+             gold_debug(DEBUG_INCREMENTAL,
+                        "  %08lx: %s + %d: type %d addend %ld",
+                        (long)(section_offset + r_offset),
+                        os->name(),
+                        (int)r_offset,
+                        r_type,
+                        (long)r_addend);
+
+             target->apply_relocation(&relinfo, r_offset, r_type, r_addend,
+                                      gsym, view, address, view_size);
+
+             // FIXME: Do something more efficient if write_output_view
+             // ever becomes more than a no-op.
+             of->write_output_view(section_offset, view_size, view);
+           }
+         offset = sym_info.next_offset();
+        }
+    }
+}
+
 // Get a view of the main symbol table and the symbol string table.
 
 template<int size, bool big_endian>
@@ -1652,17 +1752,17 @@ Sized_incr_relobj<size, big_endian>::do_add_symbols(
   elfcpp::Elf_strtab strtab(NULL, 0);
   this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab);
 
-  // Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
-  // Incremental_relocs_reader<size, big_endian> irelocs(this->ibase_->relocs_reader());
-  // unsigned int isym_count = isymtab.symbol_count();
-  // unsigned int first_global = symtab_count - isym_count;
+  Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
+  unsigned int isym_count = isymtab.symbol_count();
+  unsigned int first_global = symtab_count - isym_count;
 
   unsigned const char* sym_p;
   for (unsigned int i = 0; i < nsyms; ++i)
     {
       Incremental_global_symbol_reader<big_endian> info =
          this->input_reader_.get_global_symbol_reader(i);
-      sym_p = symtab_view.data() + info.output_symndx() * sym_size;
+      unsigned int output_symndx = info.output_symndx();
+      sym_p = symtab_view.data() + output_symndx * sym_size;
       elfcpp::Sym<size, big_endian> gsym(sym_p);
       const char* name;
       if (!strtab.get_c_string(gsym.get_st_name(), &name))
@@ -1708,6 +1808,8 @@ Sized_incr_relobj<size, big_endian>::do_add_symbols(
 
       this->symbols_[i] =
        symtab->add_from_incrobj(this, name, NULL, &sym);
+      this->ibase_->add_global_symbol(output_symndx - first_global,
+                                     this->symbols_[i]);
     }
 }
 
@@ -1993,6 +2095,19 @@ Sized_incr_relobj<size, big_endian>::do_relocate(const Symbol_table*,
   off_t off = this->incr_reloc_output_index_ * incr_reloc_size;
   unsigned int len = this->incr_reloc_count_ * incr_reloc_size;
   memcpy(view + off, this->incr_relocs_, len);
+
+  // The output section table may have changed, so we need to map
+  // the old section index to the new section index for each relocation.
+  for (unsigned int i = 0; i < this->incr_reloc_count_; ++i)
+    {
+      unsigned char* pov = view + off + i * incr_reloc_size;
+      unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(pov + 4);
+      Output_section* os = this->ibase_->output_section(shndx);
+      gold_assert(os != NULL);
+      shndx = os->out_shndx();
+      elfcpp::Swap<32, big_endian>::writeval(pov + 4, shndx);
+    }
+
   of->write_output_view(off, len, view);
 }
 
@@ -2068,10 +2183,9 @@ Sized_incr_dynobj<size, big_endian>::do_add_symbols(
   elfcpp::Elf_strtab strtab(NULL, 0);
   this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab);
 
-  // Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
-  // Incremental_relocs_reader<size, big_endian> irelocs(this->ibase_->relocs_reader());
-  // unsigned int isym_count = isymtab.symbol_count();
-  // unsigned int first_global = symtab_count - isym_count;
+  Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
+  unsigned int isym_count = isymtab.symbol_count();
+  unsigned int first_global = symtab_count - isym_count;
 
   unsigned const char* sym_p;
   for (unsigned int i = 0; i < nsyms; ++i)
@@ -2117,6 +2231,8 @@ Sized_incr_dynobj<size, big_endian>::do_add_symbols(
 
       this->symbols_[i] =
        symtab->add_from_incrobj<size, big_endian>(this, name, NULL, &sym);
+      this->ibase_->add_global_symbol(output_symndx - first_global,
+                                     this->symbols_[i]);
     }
 }
 
@@ -2152,7 +2268,6 @@ void
 Sized_incr_dynobj<size, big_endian>::do_for_all_local_got_entries(
     Got_offset_list::Visitor*) const
 {
-  // FIXME: Implement Sized_incr_dynobj::do_for_all_local_got_entries.
 }
 
 // Get the size of a section.
index 2b3f0e76bc896ef6d76855b1038bb5b9141bff90..dad5d665aac11a1521ef591200e84067edd4dcbd 100644 (file)
@@ -898,6 +898,14 @@ class Incremental_inputs_reader
     return Incremental_input_entry_reader(this, offset);
   }
 
+  // Return a reader for the global symbol info at OFFSET.
+  Incremental_global_symbol_reader<big_endian>
+  global_symbol_reader_at_offset(unsigned int offset) const
+  {
+    const unsigned char* p = this->p_ + offset;
+    return Incremental_global_symbol_reader<big_endian>(p);
+  }
+
  private:
   // Lookup a string in the ELF string table.
   const char* get_string(unsigned int offset) const
@@ -1207,6 +1215,12 @@ class Incremental_binary
   reserve_layout(unsigned int input_file_index)
   { this->do_reserve_layout(input_file_index); }
 
+  // Apply incremental relocations for symbols whose values have changed.
+  void
+  apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
+                          Output_file* of)
+  { this->do_apply_incremental_relocs(symtab, layout, of); }
+
   // Functions and types for the elfcpp::Elf_file interface.  This
   // permit us to use Incremental_binary as the File template parameter for
   // elfcpp::Elf_file.
@@ -1279,6 +1293,10 @@ class Incremental_binary
   virtual void
   do_reserve_layout(unsigned int input_file_index) = 0;
 
+  // Apply incremental relocations for symbols whose values have changed.
+  virtual void
+  do_apply_incremental_relocs(const Symbol_table*, Layout*, Output_file*) = 0;
+
   virtual unsigned int
   do_input_file_count() const = 0;
 
@@ -1307,8 +1325,8 @@ 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_(), has_incremental_info_(false), inputs_reader_(),
-      symtab_reader_(), relocs_reader_(), got_plt_reader_(),
+      section_map_(), symbol_map_(), has_incremental_info_(false),
+      inputs_reader_(), symtab_reader_(), relocs_reader_(), got_plt_reader_(),
       input_entry_readers_()
   { this->setup_readers(); }
 
@@ -1322,6 +1340,20 @@ class Sized_incremental_binary : public Incremental_binary
   output_section(unsigned int shndx)
   { return this->section_map_[shndx]; }
 
+  // Map a symbol table entry from the input 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.
+  // SYMNDX is relative to the first forced-local or global symbol in the
+  // input file symbol table.
+  Symbol*
+  global_symbol(unsigned int symndx) const
+  { return this->symbol_map_[symndx]; }
+
   // Readers for the incremental info sections.
 
   const Incremental_inputs_reader<size, big_endian>&
@@ -1366,6 +1398,11 @@ class Sized_incremental_binary : public Incremental_binary
   virtual void
   do_reserve_layout(unsigned int input_file_index);
 
+  // Apply incremental relocations for symbols whose values have changed.
+  virtual void
+  do_apply_incremental_relocs(const Symbol_table* symtab, Layout* layout,
+                             Output_file* of);
+
   // Proxy class for a sized Incremental_input_entry_reader.
 
   class Sized_input_reader : public Input_reader
@@ -1435,6 +1472,9 @@ class Sized_incremental_binary : public Incremental_binary
   // 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_;
+
   // Readers for the incremental info sections.
   bool has_incremental_info_;
   Incremental_inputs_reader<size, big_endian> inputs_reader_;
index 7afb21f2c4d5c2f3d5db82b25a96da36135bf5ac..e3972040b6c413ae4af6016a2f4deeca1edd70c6 100644 (file)
@@ -298,10 +298,11 @@ Layout::Relaxation_debug_check::verify_sections(
 void
 Layout_task_runner::run(Workqueue* workqueue, const Task* task)
 {
-  off_t file_size = this->layout_->finalize(this->input_objects_,
-                                           this->symtab_,
-                                            this->target_,
-                                           task);
+  Layout* layout = this->layout_;
+  off_t file_size = layout->finalize(this->input_objects_,
+                                    this->symtab_,
+                                     this->target_,
+                                    task);
 
   // Now we know the final size of the output file and we know where
   // each piece of information goes.
@@ -309,11 +310,11 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
   if (this->mapfile_ != NULL)
     {
       this->mapfile_->print_discarded_sections(this->input_objects_);
-      this->layout_->print_to_mapfile(this->mapfile_);
+      layout->print_to_mapfile(this->mapfile_);
     }
 
   Output_file* of;
-  if (this->layout_->incremental_base() == NULL)
+  if (layout->incremental_base() == NULL)
     {
       of = new Output_file(parameters->options().output_file_name());
       if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF)
@@ -322,13 +323,24 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
     }
   else
     {
-      of = this->layout_->incremental_base()->output_file();
+      of = layout->incremental_base()->output_file();
+
+      // Apply the incremental relocations for symbols whose values
+      // have changed.  We do this before we resize the file and start
+      // writing anything else to it, so that we can read the old
+      // incremental information from the file before (possibly)
+      // overwriting it.
+      if (parameters->incremental_update())
+        layout->incremental_base()->apply_incremental_relocs(this->symtab_,
+                                                            this->layout_,
+                                                            of);
+
       of->resize(file_size);
     }
 
   // Queue up the final set of tasks.
   gold::queue_final_tasks(this->options_, this->input_objects_,
-                         this->symtab_, this->layout_, workqueue, of);
+                         this->symtab_, layout, workqueue, of);
 }
 
 // Layout methods.
index 2d12fa21e0fa5d454ff2e87c049cca8db39fab09..17c9c99fb2380a8cdd55da4b2095a40543a82579 100644 (file)
@@ -362,6 +362,46 @@ relocate_section(
     }
 }
 
+// Apply an incremental relocation.
+
+template<int size, bool big_endian, typename Target_type,
+        typename Relocate>
+void
+apply_relocation(const Relocate_info<size, big_endian>* relinfo,
+                Target_type* target,
+                typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+                unsigned int r_type,
+                typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
+                const Symbol* gsym,
+                unsigned char* view,
+                typename elfcpp::Elf_types<size>::Elf_Addr address,
+                section_size_type view_size)
+{
+  // Construct the ELF relocation in a temporary buffer.
+  const int reloc_size = elfcpp::Elf_sizes<64>::rela_size;
+  unsigned char relbuf[reloc_size];
+  elfcpp::Rela<64, false> rel(relbuf);
+  elfcpp::Rela_write<64, false> orel(relbuf);
+  orel.put_r_offset(r_offset);
+  orel.put_r_info(elfcpp::elf_r_info<64>(0, r_type));
+  orel.put_r_addend(r_addend);
+
+  // Setup a Symbol_value for the global symbol.
+  const Sized_symbol<64>* sym = static_cast<const Sized_symbol<64>*>(gsym);
+  Symbol_value<64> symval;
+  gold_assert(sym->has_symtab_index() && sym->symtab_index() != -1U);
+  symval.set_output_symtab_index(sym->symtab_index());
+  symval.set_output_value(sym->value());
+  if (gsym->type() == elfcpp::STT_TLS)
+    symval.set_is_tls_symbol();
+  else if (gsym->type() == elfcpp::STT_GNU_IFUNC)
+    symval.set_is_ifunc_symbol();
+
+  Relocate relocate;
+  relocate.relocate(relinfo, target, NULL, -1U, rel, r_type, sym, &symval,
+                   view + r_offset, address + r_offset, view_size);
+}
+
 // This class may be used as a typical class for the
 // Scan_relocatable_reloc parameter to scan_relocatable_relocs.  The
 // template parameter Classify_reloc must be a class type which
index 85af8d37c6706201f8a557cc5ac5ba3d57a2f3a9..b86efc46a61fd0be1db7ed9cb0d9a8d4ee3dc2e1 100644 (file)
@@ -795,6 +795,19 @@ class Sized_target : public Target
   plt_entry_size() const
   { gold_unreachable(); }
 
+  // Apply an incremental relocation.
+
+  virtual void
+  apply_relocation(const Relocate_info<size, big_endian>* /* relinfo */,
+                  typename elfcpp::Elf_types<size>::Elf_Addr /* r_offset */,
+                  unsigned int /* r_type */,
+                  typename elfcpp::Elf_types<size>::Elf_Swxword /* r_addend */,
+                  const Symbol* /* gsym */,
+                  unsigned char* /* view */,
+                  typename elfcpp::Elf_types<size>::Elf_Addr /* address */,
+                  section_size_type /* view_size */)
+  { gold_unreachable(); }
+
  protected:
   Sized_target(const Target::Target_info* pti)
     : Target(pti)
index 5ba15c45d0e2512e37674fd565321bce04c81842..e4a70433e572f110dcfe123098e95265d9c13553 100644 (file)
@@ -345,6 +345,17 @@ class Target_x86_64 : public Target_freebsd<64, false>
   unsigned int
   plt_entry_size() const;
 
+  // Apply an incremental relocation.
+  void
+  apply_relocation(const Relocate_info<64, false>* relinfo,
+                  elfcpp::Elf_types<64>::Elf_Addr r_offset,
+                  unsigned int r_type,
+                  elfcpp::Elf_types<64>::Elf_Swxword r_addend,
+                  const Symbol* gsym,
+                  unsigned char* view,
+                  elfcpp::Elf_types<64>::Elf_Addr address,
+                  section_size_type view_size);
+
   // 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)
@@ -3014,6 +3025,32 @@ Target_x86_64::relocate_section(
     reloc_symbol_changes);
 }
 
+// Apply an incremental relocation.  Incremental relocations always refer
+// to global symbols.
+
+void
+Target_x86_64::apply_relocation(
+    const Relocate_info<64, false>* relinfo,
+    elfcpp::Elf_types<64>::Elf_Addr r_offset,
+    unsigned int r_type,
+    elfcpp::Elf_types<64>::Elf_Swxword r_addend,
+    const Symbol* gsym,
+    unsigned char* view,
+    elfcpp::Elf_types<64>::Elf_Addr address,
+    section_size_type view_size)
+{
+  gold::apply_relocation<64, false, Target_x86_64, Target_x86_64::Relocate>(
+    relinfo,
+    this,
+    r_offset,
+    r_type,
+    r_addend,
+    gsym,
+    view,
+    address,
+    view_size);
+}
+
 // Return the size of a relocation while scanning during a relocatable
 // link.