[gold patch] Add incremental link support for debug sections

Cary Coutant ccoutant@google.com
Mon Aug 15 22:49:00 GMT 2011


Debug sections are a problem for incremental linking because the
debugger and other consumers expect the .debug_info, .debug_types, and
.debug_line sections to contain a sequence of compile units, one after
the other. When adding patch space or leaving unused space in the
middle of a section during an incremental update, the resulting hole
makes the debug info unreadable. This patch fixes this by synthesizing
dummy compile unit headers in each hole. In order to guarantee that
any particular hole is large enough to hold a dummy header, I changed
the allocation method so that any chunk of free space left from an
allocation had to be a minimum size. (That, in turn, necessitated
adding some extra patch space to most of the incremental test cases.)

The dummy compile units for .debug_info and .debug_types work for
readelf/objdump, but not for gdb -- gdb insists on a
DW_TAG_compile_unit (or type_unit) DIE after each header, and I'm
generating a completely empty DIE tree. I'll submit a patch for gdb to
deal with that. (I prefer the empty DIE tree so that I don't have to
synthesize a fake debug abbrev table, too.) The dummy compile units
for .debug_line are filled with DW_LNS_set_basic_block opcodes --
basically no-ops as long as no row-creating opcodes are used.
(Technically, no consumer is supposed to read a .debug_line section
serially, but many do anyway -- they should instead follow the
DW_AT_stmt_list attribute from a compile_unit DIE.)

OK?

-cary

	* gold/layout.cc (Free_list::allocate): Provide guarantee of minimum
	remaining hole size when allocating.
	(Layout::make_output_section): Set fill methods for debug sections.
	* gold/layout.h (Free_list::Free_list_node): Move from private to
	public.
	(Free_list::set_min_hole_size): New function.
	(Free_list::begin, Free_list::end): New functions.
	(Free_list::min_hole_): New data member.
	* gold/output.cc: Include dwarf.h.
	(Output_fill_debug_info::do_minimum_hole_size): New function.
	(Output_fill_debug_info::do_write): New function.
	(Output_fill_debug_line::do_minimum_hole_size): New function.
	(Output_fill_debug_line::do_write): New function.
	(Output_section::Output_section): Initialize new data member.
	(Output_section::set_final_data_size): Ensure patch space is larger
	than minimum hole size.
	(Output_section::do_write): Fill holes in debug sections.
	* gold/output.h (Output_fill): New class.
	(Output_fill_debug_info): New class.
	(Output_fill_debug_line): New class.
	(Output_section::set_free_space_fill): New function.
	(Output_section::free_space_fill_): New data member.
	* gold/testsuite/Makefile.am (incremental_test_3): Add
	--incremental-patch option.
	(incremental_test_4): Likewise.
	(incremental_test_5): Likewise.
	(incremental_test_6): Likewise.
	(incremental_copy_test): Likewise.
	(incremental_common_test_1): Likewise.
	* gold/testsuite/Makefile.in: Regenerate.
-------------- next part --------------
2011-08-15  Cary Coutant  <ccoutant@google.com>

	* gold/layout.cc (Free_list::allocate): Provide guarantee of minimum
	remaining hole size when allocating.
	(Layout::make_output_section): Set fill methods for debug sections.
	* gold/layout.h (Free_list::Free_list_node): Move from private to
	public.
	(Free_list::set_min_hole_size): New function.
	(Free_list::begin, Free_list::end): New functions.
	(Free_list::min_hole_): New data member.
	* gold/output.cc: Include dwarf.h.
	(Output_fill_debug_info::do_minimum_hole_size): New function.
	(Output_fill_debug_info::do_write): New function.
	(Output_fill_debug_line::do_minimum_hole_size): New function.
	(Output_fill_debug_line::do_write): New function.
	(Output_section::Output_section): Initialize new data member.
	(Output_section::set_final_data_size): Ensure patch space is larger
	than minimum hole size.
	(Output_section::do_write): Fill holes in debug sections.
	* gold/output.h (Output_fill): New class.
	(Output_fill_debug_info): New class.
	(Output_fill_debug_line): New class.
	(Output_section::set_free_space_fill): New function.
	(Output_section::free_space_fill_): New data member.
	* gold/testsuite/Makefile.am (incremental_test_3): Add
	--incremental-patch option.
	(incremental_test_4): Likewise.
	(incremental_test_5): Likewise.
	(incremental_test_6): Likewise.
	(incremental_copy_test): Likewise.
	(incremental_common_test_1): Likewise.
	* gold/testsuite/Makefile.in: Regenerate.


diff --git a/gold/layout.cc b/gold/layout.cc
index 44c2e18..afb5b6a 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -162,6 +162,11 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
 
   ++Free_list::num_allocates;
 
+  // We usually want to drop free chunks smaller than 4 bytes.
+  // If we need to guarantee a minimum hole size, though, we need
+  // to keep track of all free chunks.
+  const int fuzz = this->min_hole_ > 0 ? 0 : 3;
+
   for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p)
     {
       ++Free_list::num_allocate_visits;
@@ -173,13 +178,13 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
 	  this->length_ = end;
 	  p->end_ = end;
 	}
-      if (end <= p->end_)
+      if (end == p->end_ || (end <= p->end_ - this->min_hole_))
 	{
-	  if (p->start_ + 3 >= start && p->end_ <= end + 3)
+	  if (p->start_ + fuzz >= start && p->end_ <= end + fuzz)
 	    this->list_.erase(p);
-	  else if (p->start_ + 3 >= start)
+	  else if (p->start_ + fuzz >= start)
 	    p->start_ = end;
-	  else if (p->end_ <= end + 3)
+	  else if (p->end_ <= end + fuzz)
 	    p->end_ = start;
 	  else
 	    {
@@ -1440,7 +1445,20 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
       && strcmp(name, ".ctors") != 0
       && strcmp(name, ".dtors") != 0
       && strcmp(name, ".jcr") != 0)
-    os->set_is_patch_space_allowed();
+    {
+      os->set_is_patch_space_allowed();
+
+      // Certain sections require "holes" to be filled with
+      // specific fill patterns.  These fill patterns may have
+      // a minimum size, so we must prevent allocations from the
+      // free list that leave a hole smaller than the minimum.
+      if (strcmp(name, ".debug_info") == 0)
+        os->set_free_space_fill(new Output_fill_debug_info(false));
+      else if (strcmp(name, ".debug_types") == 0)
+        os->set_free_space_fill(new Output_fill_debug_info(true));
+      else if (strcmp(name, ".debug_line") == 0)
+        os->set_free_space_fill(new Output_fill_debug_line());
+    }
 
   // If we have already attached the sections to segments, then we
   // need to attach this one now.  This happens for sections created
diff --git a/gold/layout.h b/gold/layout.h
index 1497f12..05cb50f 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -71,34 +71,60 @@ is_compressed_debug_section(const char* secname);
 class Free_list
 {
  public:
+  struct Free_list_node
+  {
+    Free_list_node(off_t start, off_t end)
+      : start_(start), end_(end)
+    { }
+    off_t start_;
+    off_t end_;
+  };
+  typedef std::list<Free_list_node>::const_iterator Const_iterator;
+
   Free_list()
-    : list_(), last_remove_(list_.begin()), extend_(false), length_(0)
+    : list_(), last_remove_(list_.begin()), extend_(false), length_(0),
+      min_hole_(0)
   { }
 
+  // Initialize the free list for a section of length LEN.
+  // If EXTEND is true, free space may be allocated past the end.
   void
   init(off_t len, bool extend);
 
+  // Set the minimum hole size that is allowed when allocating
+  // from the free list.
+  void
+  set_min_hole_size(off_t min_hole)
+  { this->min_hole_ = min_hole; }
+
+  // Remove a chunk from the free list.
   void
   remove(off_t start, off_t end);
 
+  // Allocate a chunk of space from the free list of length LEN,
+  // with alignment ALIGN, and minimum offset MINOFF.
   off_t
   allocate(off_t len, uint64_t align, off_t minoff);
 
+  // Return an iterator for the beginning of the free list.
+  Const_iterator
+  begin() const
+  { return this->list_.begin(); }
+
+  // Return an iterator for the end of the free list.
+  Const_iterator
+  end() const
+  { return this->list_.end(); }
+
+  // Dump the free list (for debugging).
   void
   dump();
 
+  // Print usage statistics.
   static void
   print_stats();
 
  private:
-  struct Free_list_node
-  {
-    Free_list_node(off_t start, off_t end)
-      : start_(start), end_(end)
-    { }
-    off_t start_;
-    off_t end_;
-  };
   typedef std::list<Free_list_node>::iterator Iterator;
 
   // The free list.
@@ -113,6 +139,10 @@ class Free_list
   // The total length of the section, segment, or file.
   off_t length_;
 
+  // The minimum hole size allowed.  When allocating from the free list,
+  // we must not leave a hole smaller than this.
+  off_t min_hole_;
+
   // Statistics:
   // The total number of free lists used.
   static unsigned int num_lists;
diff --git a/gold/output.cc b/gold/output.cc
index affc6f7..470290c 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -36,6 +36,7 @@
 
 #include "libiberty.h"
 
+#include "dwarf.h"
 #include "parameters.h"
 #include "object.h"
 #include "symtab.h"
@@ -1926,6 +1927,124 @@ Output_symtab_xindex::endian_do_write(unsigned char* const oview)
     }
 }
 
+// Output_fill_debug_info methods.
+
+size_t
+Output_fill_debug_info::do_minimum_hole_size() const
+{
+  // Compile unit header fields: unit_length, version, debug_abbrev_offset,
+  // address_size.
+  const size_t len = 4 + 2 + 4 + 1;
+  // For type units, add type_signature, type_offset.
+  if (this->is_debug_types_)
+    return len + 8 + 4;
+  return len;
+}
+
+void
+Output_fill_debug_info::do_write(Output_file* of, off_t off, size_t len) const
+{
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_info(%08lx, %08lx)", off, len);
+
+  gold_assert(len >= this->do_minimum_hole_size());
+
+  unsigned char* const oview = of->get_output_view(off, len);
+  unsigned char* pov = oview;
+
+  // Write header fields: unit_length, version, debug_abbrev_offset,
+  // address_size.
+  if (this->is_big_endian())
+    {
+      elfcpp::Swap<32, true>::writeval(pov, len - 4);
+      elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, true>::writeval(pov + 6, 0);
+    }
+  else
+    {
+      elfcpp::Swap<32, false>::writeval(pov, len - 4);
+      elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, false>::writeval(pov + 6, 0);
+    }
+  pov += 4 + 2 + 4;
+  *pov++ = 4;
+
+  // For type units, the additional header fields -- type_signature,
+  // type_offset -- can be filled with zeroes.
+
+  // Fill the remainder of the free space with zeroes.
+  if (pov < oview + len)
+    memset(pov, 0, oview + len - pov);
+
+  of->write_output_view(off, len, oview);
+}
+
+// Output_fill_debug_line methods.
+
+size_t
+Output_fill_debug_line::do_minimum_hole_size() const
+{
+  // Line number program header fields: unit_length, version, header_length,
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  const size_t len = 4 + 2 + 4 + this->header_length;
+  return len;
+}
+
+void
+Output_fill_debug_line::do_write(Output_file* of, off_t off, size_t len) const
+{
+  gold_debug(DEBUG_INCREMENTAL, "fill_debug_line(%08lx, %08lx)", off, len);
+
+  gold_assert(len >= this->do_minimum_hole_size());
+
+  unsigned char* const oview = of->get_output_view(off, len);
+  unsigned char* pov = oview;
+
+  // Write header fields: unit_length, version, header_length,
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  if (this->is_big_endian())
+    {
+      elfcpp::Swap<32, true>::writeval(pov, len - 4);
+      elfcpp::Swap<16, true>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, true>::writeval(pov + 6, this->header_length);
+    }
+  else
+    {
+      elfcpp::Swap<32, false>::writeval(pov, len - 4);
+      elfcpp::Swap<16, false>::writeval(pov + 4, this->version);
+      elfcpp::Swap<32, false>::writeval(pov + 6, this->header_length);
+    }
+  pov += 4 + 2 + 4;
+  *pov++ = 1;	// minimum_instruction_length
+  *pov++ = 0;	// default_is_stmt
+  *pov++ = 0;	// line_base
+  *pov++ = 5;	// line_range
+  *pov++ = 13;	// opcode_base
+  *pov++ = 0;	// standard_opcode_lengths[1]
+  *pov++ = 1;	// standard_opcode_lengths[2]
+  *pov++ = 1;	// standard_opcode_lengths[3]
+  *pov++ = 1;	// standard_opcode_lengths[4]
+  *pov++ = 1;	// standard_opcode_lengths[5]
+  *pov++ = 0;	// standard_opcode_lengths[6]
+  *pov++ = 0;	// standard_opcode_lengths[7]
+  *pov++ = 0;	// standard_opcode_lengths[8]
+  *pov++ = 1;	// standard_opcode_lengths[9]
+  *pov++ = 0;	// standard_opcode_lengths[10]
+  *pov++ = 0;	// standard_opcode_lengths[11]
+  *pov++ = 1;	// standard_opcode_lengths[12]
+  *pov++ = 0;	// include_directories (empty)
+  *pov++ = 0;	// filenames (empty)
+
+  // Fill the remainder of the free space with DW_LNS_set_basic_block
+  // opcodes.  These are effectively no-ops: the resulting line table
+  // program will not create any rows.
+  if (pov < oview + len)
+    memset(pov, elfcpp::DW_LNS_set_basic_block, oview + len - pov);
+
+  of->write_output_view(off, len, oview);
+}
+
 // Output_section::Input_section methods.
 
 // Return the current data size.  For an input section we store the size here.
@@ -2158,6 +2277,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
     free_list_(),
+    free_space_fill_(NULL),
     patch_space_(0)
 {
   // An unallocated section has no address.  Forcing this means that
@@ -2981,7 +3101,10 @@ Output_section::set_final_data_size()
   if (this->is_patch_space_allowed_ && parameters->incremental_full())
     {
       double pct = parameters->options().incremental_patch();
-      off_t extra = static_cast<off_t>(data_size * pct);
+      size_t extra = static_cast<size_t>(data_size * pct);
+      if (this->free_space_fill_ != NULL
+          && this->free_space_fill_->minimum_hole_size() > extra)
+	extra = this->free_space_fill_->minimum_hole_size();
       off_t new_size = align_address(data_size + extra, this->addralign());
       this->patch_space_ = new_size - data_size;
       gold_debug(DEBUG_INCREMENTAL,
@@ -3515,6 +3638,26 @@ Output_section::do_write(Output_file* of)
       p->write(of);
       off = aligned_off + p->data_size();
     }
+
+  // For incremental links, fill in unused chunks in debug sections
+  // with dummy compilation unit headers.
+  if (this->free_space_fill_ != NULL)
+    {
+      for (Free_list::Const_iterator p = this->free_list_.begin();
+	   p != this->free_list_.end();
+	   ++p)
+	{
+	  off_t off = p->start_;
+	  size_t len = p->end_ - off;
+	  this->free_space_fill_->write(of, this->offset() + off, len);
+	}
+      if (this->patch_space_ > 0)
+	{
+	  off_t off = this->current_data_size_for_child() - this->patch_space_;
+	  this->free_space_fill_->write(of, this->offset() + off,
+					this->patch_space_);
+	}
+    }
 }
 
 // If a section requires postprocessing, create the buffer to use.
diff --git a/gold/output.h b/gold/output.h
index 20869e6..5c0eb69 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -2615,6 +2615,98 @@ class Output_section_lookup_maps
   Relaxed_input_sections_by_id relaxed_input_sections_by_id_;
 };
 
+// This abstract base class defines the interface for the
+// types of methods used to fill free space left in an output
+// section during an incremental link.  These methods are used
+// to insert dummy compilation units into debug info so that
+// debug info consumers can scan the debug info serially.
+
+class Output_fill
+{
+ public:
+  Output_fill()
+  { this->is_big_endian_ = parameters->target().is_big_endian(); }
+
+  // Return the smallest size chunk of free space that can be
+  // filled with a dummy compilation unit.
+  size_t
+  minimum_hole_size() const
+  { return this->do_minimum_hole_size(); }
+
+  // Write a fill pattern of length LEN at offset OFF in the file.
+  void
+  write(Output_file* of, off_t off, size_t len) const
+  { this->do_write(of, off, len); }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const = 0;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const = 0;
+
+  bool
+  is_big_endian() const
+  { return this->is_big_endian_; }
+
+ private:
+  bool is_big_endian_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_info or .debug_types section.
+
+class Output_fill_debug_info : public Output_fill
+{
+ public:
+  Output_fill_debug_info(bool is_debug_types)
+    : is_debug_types_(is_debug_types)
+  { }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+  // Version of the header.
+  static const int version = 4;
+  // True if this is a .debug_types section.
+  bool is_debug_types_;
+};
+
+// Fill method that introduces a dummy compilation unit in
+// a .debug_line section.
+
+class Output_fill_debug_line : public Output_fill
+{
+ public:
+  Output_fill_debug_line()
+  { }
+
+ protected:
+  virtual size_t
+  do_minimum_hole_size() const;
+
+  virtual void
+  do_write(Output_file* of, off_t off, size_t len) const;
+
+ private:
+  // Version of the header.  We write a DWARF-3 header because it's smaller
+  // and many tools have not yet been updated to understand the DWARF-4 header.
+  static const int version = 3;
+  // Length of the portion of the header that follows the header_length
+  // field.  This includes the following fields:
+  // minimum_instruction_length, default_is_stmt, line_base, line_range,
+  // opcode_base, standard_opcode_lengths[], include_directories, filenames.
+  // The standard_opcode_lengths array is 12 bytes long, and the
+  // include_directories and filenames fields each contain only a single
+  // null byte.
+  static const size_t header_length = 19;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -3438,6 +3530,15 @@ class Output_section : public Output_data
   set_is_patch_space_allowed()
   { this->is_patch_space_allowed_ = true; }
 
+  // Set a fill method to use for free space left in the output section
+  // during incremental links.
+  void
+  set_free_space_fill(Output_fill* free_space_fill)
+  {
+    this->free_space_fill_ = free_space_fill;
+    this->free_list_.set_min_hole_size(free_space_fill->minimum_hole_size());
+  }
+
   // Reserve space within the fixed layout for the section.  Used for
   // incremental update links.
   void
@@ -3913,6 +4014,8 @@ class Output_section : public Output_data
   // List of available regions within the section, for incremental
   // update links.
   Free_list free_list_;
+  // Method for filling chunks of free space.
+  Output_fill* free_space_fill_;
   // Amount added as patch space for incremental linking.
   off_t patch_space_;
 };
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 755c055..ca07f87 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -1966,7 +1966,7 @@ MOSTLYCLEANFILES += two_file_test_tmp_3.o
 incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 	@sleep 1
 	cp -f two_file_test_1b.o two_file_test_tmp_3.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
@@ -1976,7 +1976,7 @@ MOSTLYCLEANFILES += incremental_test_4.base two_file_test_tmp_4.o
 incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
 	mv -f incremental_test_4 incremental_test_4.base
 	@sleep 1
 	cp -f two_file_test_2.o two_file_test_tmp_4.o
@@ -1988,7 +1988,7 @@ incremental_test_5: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
 	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
 	@sleep 1
 	cp -f two_file_test_1b.o two_file_test_tmp_5.o
 	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
@@ -2002,7 +2002,7 @@ incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 	cp -f two_file_test_1b.o two_file_test_tmp_6.o
 	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
 	@sleep 1
 	cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
 	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
@@ -2011,7 +2011,7 @@ incremental_test_6: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 check_PROGRAMS += incremental_copy_test
 incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 	cp -f copy_test_v1.o copy_test_tmp.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 	@sleep 1
 	cp -f copy_test.o copy_test_tmp.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
@@ -2019,7 +2019,7 @@ incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 check_PROGRAMS += incremental_common_test_1
 incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
 	cp -f common_test_1_v1.o common_test_1_tmp.o
-	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ common_test_1_tmp.o
+	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
 	@sleep 1
 	cp -f common_test_1_v2.o common_test_1_tmp.o
 	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index d937b7d..f0339fd 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -4942,14 +4942,14 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_3: two_file_test_1.o two_file_test_1b_v1.o two_file_test_1b.o \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_3.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_3.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_1.o two_file_test_tmp_3.o two_file_test_2.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_4: two_file_test_1.o two_file_test_1b.o two_file_test_2_v1.o \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_2_v1.o two_file_test_tmp_4.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_1.o two_file_test_1b.o two_file_test_tmp_4.o two_file_test_main.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	mv -f incremental_test_4 incremental_test_4.base
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_2.o two_file_test_tmp_4.o
@@ -4958,7 +4958,7 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_5.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_5.a
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_5.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_5.a two_file_test_1.o two_file_test_tmp_5.o two_file_test_2.o
@@ -4967,20 +4967,20 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@		    two_file_test_2.o two_file_test_main.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b.o two_file_test_tmp_6.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_main.o two_file_test_6.a
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f two_file_test_1b_v1.o two_file_test_tmp_6.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(TEST_AR) rc two_file_test_6.a two_file_test_1.o two_file_test_tmp_6.o two_file_test_2.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_main.o -Wl,--incremental-unchanged two_file_test_6.a -Wl,--incremental-unknown
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_copy_test: copy_test_v1.o copy_test.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f copy_test_v1.o copy_test_tmp.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f copy_test.o copy_test_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ -Wl,-R,. copy_test_tmp.o copy_test_1.so copy_test_2.so
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_common_test_1: common_test_1_v1.o common_test_1_v2.o gcctestdir/ld
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f common_test_1_v1.o common_test_1_tmp.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ common_test_1_tmp.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ common_test_1_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	@sleep 1
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	cp -f common_test_1_v2.o common_test_1_tmp.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@	$(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ common_test_1_tmp.o


More information about the Binutils mailing list