* incremental.cc (Incremental_inputs::report_command_line): Ignore
authorCary Coutant <ccoutant@google.com>
Wed, 6 Jul 2011 21:19:32 +0000 (21:19 +0000)
committerCary Coutant <ccoutant@google.com>
Wed, 6 Jul 2011 21:19:32 +0000 (21:19 +0000)
--incremental-patch option.
* layout.cc (Free_list::allocate): Extend allocation beyond original
end if enabled.
(Layout::make_output_section): Mark sections that should get
patch space.
* options.cc (parse_percent): New function.
* options.h (parse_percent): New function.
(DEFINE_percent): New macro.
(General_options): Add --incremental-patch option.
* output.cc (Output_section::Output_section): Initialize new data
members.
(Output_section::add_input_section): Print section name when out
of patch space.
(Output_section::add_output_section_data): Likewise.
(Output_section::set_final_data_size): Add patch space when
doing --incremental-full.
(Output_section::do_reset_address_and_file_offset): Remove patch
space.
(Output_segment::set_section_list_addresses): Print debug output
only if --incremental-update.
* output.h (Output_section::set_is_patch_space_allowed): New function.
(Output_section::is_patch_space_allowed_): New data member.
(Output_section::patch_space_): New data member.
* parameters.cc (Parameters::incremental_full): New function.
* parameters.h (Parameters::incremental_full): New function
* testsuite/Makefile.am (incremental_test_2): Add test for
--incremental-patch option.
* testsuite/Makefile.in: Regenerate.
* testsuite/two_file_test_1_v1.cc (t1, t2, t3): Add comments.
(t18): Remove function body.

12 files changed:
gold/ChangeLog
gold/incremental.cc
gold/layout.cc
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h
gold/parameters.cc
gold/parameters.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/two_file_test_1_v1.cc

index ec8e8f162b995c5f1b0d595dc0be81ce6bd71148..f975788fe9176eb32d8ca0775c9a8670653a99ad 100644 (file)
@@ -1,3 +1,37 @@
+2011-07-06  Cary Coutant  <ccoutant@google.com>
+
+       * incremental.cc (Incremental_inputs::report_command_line): Ignore
+       --incremental-patch option.
+       * layout.cc (Free_list::allocate): Extend allocation beyond original
+       end if enabled.
+       (Layout::make_output_section): Mark sections that should get
+       patch space.
+       * options.cc (parse_percent): New function.
+       * options.h (parse_percent): New function.
+       (DEFINE_percent): New macro.
+       (General_options): Add --incremental-patch option.
+       * output.cc (Output_section::Output_section): Initialize new data
+       members.
+       (Output_section::add_input_section): Print section name when out
+       of patch space.
+       (Output_section::add_output_section_data): Likewise.
+       (Output_section::set_final_data_size): Add patch space when
+       doing --incremental-full.
+       (Output_section::do_reset_address_and_file_offset): Remove patch
+       space.
+       (Output_segment::set_section_list_addresses): Print debug output
+       only if --incremental-update.
+       * output.h (Output_section::set_is_patch_space_allowed): New function.
+       (Output_section::is_patch_space_allowed_): New data member.
+       (Output_section::patch_space_): New data member.
+       * parameters.cc (Parameters::incremental_full): New function.
+       * parameters.h (Parameters::incremental_full): New function
+       * testsuite/Makefile.am (incremental_test_2): Add test for
+       --incremental-patch option.
+       * testsuite/Makefile.in: Regenerate.
+       * testsuite/two_file_test_1_v1.cc (t1, t2, t3): Add comments.
+       (t18): Remove function body.
+
 2011-07-05  Doug Kwan  <dougkwan@google.com>
 
        PR gold/12771
index c92bb07aa5577ab0af536b3819a7898eec478d97..f0be7f04daac23fdd199dd460927b11bd4b1f474 100644 (file)
@@ -925,9 +925,11 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
          || strcmp(argv[i], "--incremental-unchanged") == 0
          || strcmp(argv[i], "--incremental-unknown") == 0
          || is_prefix_of("--incremental-base=", argv[i])
+         || is_prefix_of("--incremental-patch=", argv[i])
          || is_prefix_of("--debug=", argv[i]))
         continue;
       if (strcmp(argv[i], "--incremental-base") == 0
+         || strcmp(argv[i], "--incremental-patch") == 0
          || strcmp(argv[i], "--debug") == 0)
        {
          // When these options are used without the '=', skip the
index e6fd7e51149f529909390d123586f5037e964abc..3c3b5b35ab4256697fe253bfece2ca41170b80d1 100644 (file)
@@ -168,6 +168,11 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
       off_t start = p->start_ > minoff ? p->start_ : minoff;
       start = align_address(start, align);
       off_t end = start + len;
+      if (end > p->end_ && p->end_ == this->length_ && this->extend_)
+       {
+         this->length_ = end;
+         p->end_ = end;
+       }
       if (end <= p->end_)
        {
          if (p->start_ + 3 >= start && p->end_ <= end + 3)
@@ -186,6 +191,12 @@ Free_list::allocate(off_t len, uint64_t align, off_t minoff)
          return start;
        }
     }
+  if (this->extend_)
+    {
+      off_t start = align_address(this->length_, align);
+      this->length_ = start + len;
+      return start;
+    }
   return -1;
 }
 
@@ -1413,6 +1424,21 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
       && strcmp(name + strlen(name) - 3, "str") == 0)
     this->have_stabstr_section_ = true;
 
+  // During a full incremental link, we add patch space to most
+  // PROGBITS and NOBITS sections.  Flag those that may be
+  // arbitrarily padded.
+  if ((type == elfcpp::SHT_PROGBITS || type == elfcpp::SHT_NOBITS)
+      && order != ORDER_INTERP
+      && order != ORDER_INIT
+      && order != ORDER_PLT
+      && order != ORDER_FINI
+      && order != ORDER_RELRO_LAST
+      && order != ORDER_NON_RELRO_FIRST
+      && strcmp(name, ".ctors") != 0
+      && strcmp(name, ".dtors") != 0
+      && strcmp(name, ".jcr") != 0)
+    os->set_is_patch_space_allowed();
+
   // If we have already attached the sections to segments, then we
   // need to attach this one now.  This happens for sections created
   // directly by the linker.
index f1dc1cb91845843c80b405096b0e9e2157e16d83..05d6f88dd645d01a5242c31231c69a24cfbaf55b 100644 (file)
@@ -234,6 +234,17 @@ parse_double(const char* option_name, const char* arg, double* retval)
               option_name, arg);
 }
 
+void
+parse_percent(const char* option_name, const char* arg, double* retval)
+{
+  char* endptr;
+  *retval = strtod(arg, &endptr) / 100.0;
+  if (*endptr != '\0')
+    gold_fatal(_("%s: invalid option value "
+                "(expected a floating point number): %s"),
+              option_name, arg);
+}
+
 void
 parse_string(const char* option_name, const char* arg, const char** retval)
 {
index 57d58108b8fff3bc44cee693ba0154e1ac86156a..c73bd45444f4ea2cb4b076fd6772353bc2d44c54 100644 (file)
@@ -97,6 +97,9 @@ parse_uint64(const char* option_name, const char* arg, uint64_t* retval);
 extern void
 parse_double(const char* option_name, const char* arg, double* retval);
 
+extern void
+parse_percent(const char* option_name, const char* arg, double* retval);
+
 extern void
 parse_string(const char* option_name, const char* arg, const char** retval);
 
@@ -372,6 +375,12 @@ struct Struct_special : public Struct_var
             #default_value__, helpstring__, helparg__, false,           \
             double, double, options::parse_double)
 
+#define DEFINE_percent(varname__, dashes__, shortname__, default_value__, \
+                      helpstring__, helparg__)                           \
+  DEFINE_var(varname__, dashes__, shortname__, default_value__ / 100.0,          \
+            #default_value__, helpstring__, helparg__, false,            \
+            double, double, options::parse_percent)
+
 #define DEFINE_string(varname__, dashes__, shortname__, default_value__, \
                       helpstring__, helparg__)                           \
   DEFINE_var(varname__, dashes__, shortname__, default_value__,          \
@@ -813,6 +822,10 @@ class General_options
   DEFINE_special(incremental_unknown, options::TWO_DASHES, '\0',
                  N_("Use timestamps to check files (default)"), NULL);
 
+  DEFINE_percent(incremental_patch, options::TWO_DASHES, '\0', 10,
+                N_("Amount of extra space to allocate for patches"),
+                N_("PERCENT"));
+
   DEFINE_string(init, options::ONE_DASH, '\0', "_init",
                 N_("Call SYMBOL at load-time"), N_("SYMBOL"));
 
index 8a781c5e87d9d1fc4a306a75acd62c3644662be9..b9cfafd9cd2b18f4d405c788a15e776c4f9a16dd 100644 (file)
@@ -2153,10 +2153,12 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     is_noload_(false),
     always_keeps_input_sections_(false),
     has_fixed_layout_(false),
+    is_patch_space_allowed_(false),
     tls_offset_(0),
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
-    free_list_()
+    free_list_(),
+    patch_space_(0)
 {
   // An unallocated section has no address.  Forcing this means that
   // we don't need special treatment for symbols defined in debug
@@ -2271,7 +2273,9 @@ Output_section::add_input_section(Layout* layout,
       offset_in_section = this->free_list_.allocate(input_section_size,
                                                    addralign, 0);
       if (offset_in_section == -1)
-        gold_fallback(_("out of patch space; relink with --incremental-full"));
+        gold_fallback(_("out of patch space in section %s; "
+                       "relink with --incremental-full"),
+                     this->name());
       aligned_offset_in_section = offset_in_section;
     }
   else
@@ -2375,8 +2379,9 @@ Output_section::add_output_section_data(Output_section_data* posd)
          offset_in_section = this->free_list_.allocate(posd->data_size(),
                                                        posd->addralign(), 0);
          if (offset_in_section == -1)
-           gold_fallback(_("out of patch space; "
-                           "relink with --incremental-full"));
+           gold_fallback(_("out of patch space in section %s; "
+                           "relink with --incremental-full"),
+                         this->name());
          // Finalize the address and offset now.
          uint64_t addr = this->address();
          off_t offset = this->offset();
@@ -2946,30 +2951,48 @@ Output_section::update_data_size()
 void
 Output_section::set_final_data_size()
 {
+  off_t data_size;
+
   if (this->input_sections_.empty())
+    data_size = this->current_data_size_for_child();
+  else
     {
-      this->set_data_size(this->current_data_size_for_child());
-      return;
-    }
+      if (this->must_sort_attached_input_sections()
+         || this->input_section_order_specified())
+       this->sort_attached_input_sections();
 
-  if (this->must_sort_attached_input_sections()
-      || this->input_section_order_specified())
-    this->sort_attached_input_sections();
+      uint64_t address = this->address();
+      off_t startoff = this->offset();
+      off_t off = startoff + this->first_input_offset_;
+      for (Input_section_list::iterator p = this->input_sections_.begin();
+          p != this->input_sections_.end();
+          ++p)
+       {
+         off = align_address(off, p->addralign());
+         p->set_address_and_file_offset(address + (off - startoff), off,
+                                        startoff);
+         off += p->data_size();
+       }
+      data_size = off - startoff;
+    }
 
-  uint64_t address = this->address();
-  off_t startoff = this->offset();
-  off_t off = startoff + this->first_input_offset_;
-  for (Input_section_list::iterator p = this->input_sections_.begin();
-       p != this->input_sections_.end();
-       ++p)
+  // For full incremental links, we want to allocate some patch space
+  // in most sections for subsequent incremental updates.
+  if (this->is_patch_space_allowed_ && parameters->incremental_full())
     {
-      off = align_address(off, p->addralign());
-      p->set_address_and_file_offset(address + (off - startoff), off,
-                                    startoff);
-      off += p->data_size();
+      double pct = parameters->options().incremental_patch();
+      off_t extra = static_cast<off_t>(data_size * pct);
+      off_t new_size = align_address(data_size + extra, this->addralign());
+      this->patch_space_ = new_size - data_size;
+      gold_debug(DEBUG_INCREMENTAL,
+                "set_final_data_size: %08lx + %08lx: section %s",
+                static_cast<long>(data_size),
+                static_cast<long>(this->patch_space_),
+                this->name());
+      data_size = new_size;
     }
 
-  this->set_data_size(off - startoff);
+  this->set_data_size(data_size);
 }
 
 // Reset the address and file offset.
@@ -2988,8 +3011,16 @@ Output_section::do_reset_address_and_file_offset()
        p != this->input_sections_.end();
        ++p)
     p->reset_address_and_file_offset();
+
+  // Remove any patch space that was added in set_final_data_size.
+  if (this->patch_space_ > 0)
+    {
+      this->set_current_data_size_for_child(this->current_data_size_for_child()
+                                           - this->patch_space_);
+      this->patch_space_ = 0;
+    }
 }
-  
+
 // Return true if address and file offset have the values after reset.
 
 bool
@@ -4265,14 +4296,15 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
          (*p)->finalize_data_size();
        }
 
-      gold_debug(DEBUG_INCREMENTAL,
-                "set_section_list_addresses: %08lx %08lx %s",
-                static_cast<long>(off),
-                static_cast<long>((*p)->data_size()),
-                ((*p)->output_section() != NULL
-                 ? (*p)->output_section()->name() : "(special)"));
-
-      // We want to ignore the size of a SHF_TLS or SHT_NOBITS
+      if (parameters->incremental_update())
+       gold_debug(DEBUG_INCREMENTAL,
+                  "set_section_list_addresses: %08lx %08lx %s",
+                  static_cast<long>(off),
+                  static_cast<long>((*p)->data_size()),
+                  ((*p)->output_section() != NULL
+                   ? (*p)->output_section()->name() : "(special)"));
+
+      // We want to ignore the size of a SHF_TLS SHT_NOBITS
       // section.  Such a section does not affect the size of a
       // PT_LOAD segment.
       if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS)
index 72d1dbaf5e0b87bd5e37fbf8679a907cea8e3fbc..7fb87de8097000d73d2050a97a9c87afb8b5f3ea 100644 (file)
@@ -3427,6 +3427,12 @@ class Output_section : public Output_data
   has_fixed_layout() const
   { return this->has_fixed_layout_; }
 
+  // Set flag to allow patch space for this section.  Used for full
+  // incremental links.
+  void
+  set_is_patch_space_allowed()
+  { this->is_patch_space_allowed_ = true; }
+
   // Reserve space within the fixed layout for the section.  Used for
   // incremental update links.
   void
@@ -3890,6 +3896,8 @@ class Output_section : public Output_data
   bool always_keeps_input_sections_ : 1;
   // Whether this section has a fixed layout, for incremental update links.
   bool has_fixed_layout_ : 1;
+  // True if we can add patch space to this section.
+  bool is_patch_space_allowed_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
@@ -3900,6 +3908,8 @@ class Output_section : public Output_data
   // List of available regions within the section, for incremental
   // update links.
   Free_list free_list_;
+  // Amount added as patch space for incremental linking.
+  off_t patch_space_;
 };
 
 // An output segment.  PT_LOAD segments are built from collections of
index 1b371d8e5bbcb08d5f1e1a701d67a13f0f15662f..0384dd68081664870cc67d438277da5ec5e5dcc8 100644 (file)
@@ -248,6 +248,14 @@ Parameters::incremental() const
   return this->incremental_mode_ != General_options::INCREMENTAL_OFF;
 }
 
+// Return true if we are doing a full incremental link.
+
+bool
+Parameters::incremental_full() const
+{
+  return this->incremental_mode_ == General_options::INCREMENTAL_FULL;
+}
+
 // Return true if we are doing an incremental update.
 
 bool
index 786750300712a4cdb148604b9652a452da3ca052..09b0516b782576edc745773a6a2c91ac1784da49 100644 (file)
@@ -159,6 +159,10 @@ class Parameters
   bool
   incremental() const;
 
+  // Return true if we are doing a full incremental link.
+  bool
+  incremental_full() const;
+
   // Return true if we are doing an incremental update.
   bool
   incremental_update() const;
index 97924001dccbbbdd253e3dd827ac84bec7970d98..33ae7c8882427a658ffcc39ec731ae40137b2994 100644 (file)
@@ -1903,7 +1903,7 @@ MOSTLYCLEANFILES += two_file_test_tmp_2.o
 incremental_test_2: two_file_test_1_v1.o two_file_test_1.o two_file_test_1b.o \
                    two_file_test_2.o two_file_test_main.o gcctestdir/ld
        cp -f two_file_test_1_v1.o two_file_test_tmp_2.o
-       $(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b.o two_file_test_2.o two_file_test_main.o
+       $(CXXLINK) -Wl,--incremental-full,--incremental-patch=100 -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b.o two_file_test_2.o two_file_test_main.o
        @sleep 1
        cp -f two_file_test_1.o two_file_test_tmp_2.o
        $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b.o two_file_test_2.o two_file_test_main.o
index 5295c52998ade347ca9769454b681d7b5bed9567..a25b0124e3c75dd009cb301efdc81418831dec33 100644 (file)
@@ -4783,7 +4783,7 @@ uninstall-am:
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@incremental_test_2: two_file_test_1_v1.o two_file_test_1.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_1_v1.o two_file_test_tmp_2.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     $(CXXLINK) -Wl,--incremental-full -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b.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_tmp_2.o two_file_test_1b.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_1.o two_file_test_tmp_2.o
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@     $(CXXLINK) -Wl,--incremental-update -Bgcctestdir/ two_file_test_tmp_2.o two_file_test_1b.o two_file_test_2.o two_file_test_main.o
index 6a43d9ba824bfb58ef72cddebb1b3f365e13fea7..2a2365404e3b98e1b7bd57e835182355e0cc16e4 100644 (file)
@@ -62,7 +62,7 @@
 bool
 t1()
 {
-  return t1_2() == 0;
+  return t1_2() == 0;  // Intentionally wrong.
 }
 
 // 2  Code in file 1 refers to global data in file 2.
@@ -70,7 +70,7 @@ t1()
 bool
 t2()
 {
-  return v2 == 0;
+  return v2 == 0;  // Intentionally wrong.
 }
 
 // 3  Code in file 1 referes to common symbol in file 2.
@@ -78,7 +78,7 @@ t2()
 bool
 t3()
 {
-  return v3 == 0;
+  return v3 == 0;  // Intentionally wrong.
 }
 
 // 4  Code in file 1 refers to offset within global data in file 2.
@@ -231,13 +231,6 @@ t17()
 bool
 t18()
 {
-  char c = 'a';
-  for (int i = 0; i < T17_COUNT; ++i)
-    {
-      const char* s = f18(i);
-      if (s[0] != c || s[1] != '\0')
-        return false;
-      ++c;
-    }
+  // Stubbed out; full implementation in two_file_test_1.cc.
   return true;
 }