summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2011-07-06 21:19:32 +0000
committerCary Coutant <ccoutant@google.com>2011-07-06 21:19:32 +0000
commit9fbd3822ad34dced1ec88410f3f1b447d30e6435 (patch)
tree095ca61510e2bbeca8a22eb82909691b0d945da1
parent438640d1120a37fb0309164e84c82e01fe98c5a9 (diff)
downloadbinutils-gdb-9fbd3822ad34dced1ec88410f3f1b447d30e6435.tar.gz
* 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.
-rw-r--r--gold/ChangeLog34
-rw-r--r--gold/incremental.cc2
-rw-r--r--gold/layout.cc26
-rw-r--r--gold/options.cc11
-rw-r--r--gold/options.h13
-rw-r--r--gold/output.cc92
-rw-r--r--gold/output.h10
-rw-r--r--gold/parameters.cc8
-rw-r--r--gold/parameters.h4
-rw-r--r--gold/testsuite/Makefile.am2
-rw-r--r--gold/testsuite/Makefile.in2
-rw-r--r--gold/testsuite/two_file_test_1_v1.cc15
12 files changed, 176 insertions, 43 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index ec8e8f162b9..f975788fe91 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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
diff --git a/gold/incremental.cc b/gold/incremental.cc
index c92bb07aa55..f0be7f04daa 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -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
diff --git a/gold/layout.cc b/gold/layout.cc
index e6fd7e51149..3c3b5b35ab4 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -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.
diff --git a/gold/options.cc b/gold/options.cc
index f1dc1cb9184..05d6f88dd64 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -235,6 +235,17 @@ parse_double(const char* option_name, const char* arg, double* retval)
}
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)
{
if (*arg == '\0')
diff --git a/gold/options.h b/gold/options.h
index 57d58108b8f..c73bd45444f 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -98,6 +98,9 @@ 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);
extern void
@@ -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"));
diff --git a/gold/output.cc b/gold/output.cc
index 8a781c5e87d..b9cfafd9cd2 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -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)
diff --git a/gold/output.h b/gold/output.h
index 72d1dbaf5e0..7fb87de8097 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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
diff --git a/gold/parameters.cc b/gold/parameters.cc
index 1b371d8e5bb..0384dd68081 100644
--- a/gold/parameters.cc
+++ b/gold/parameters.cc
@@ -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
diff --git a/gold/parameters.h b/gold/parameters.h
index 78675030071..09b0516b782 100644
--- a/gold/parameters.h
+++ b/gold/parameters.h
@@ -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;
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 97924001dcc..33ae7c88824 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -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
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index 5295c52998a..a25b0124e3c 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -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
diff --git a/gold/testsuite/two_file_test_1_v1.cc b/gold/testsuite/two_file_test_1_v1.cc
index 6a43d9ba824..2a2365404e3 100644
--- a/gold/testsuite/two_file_test_1_v1.cc
+++ b/gold/testsuite/two_file_test_1_v1.cc
@@ -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;
}