* 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.
This commit is contained in:
Cary Coutant 2011-07-06 21:19:32 +00:00
parent 438640d112
commit 9fbd3822ad
12 changed files with 175 additions and 42 deletions

View 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> 2011-07-05 Doug Kwan <dougkwan@google.com>
PR gold/12771 PR gold/12771

View 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-unchanged") == 0
|| strcmp(argv[i], "--incremental-unknown") == 0 || strcmp(argv[i], "--incremental-unknown") == 0
|| is_prefix_of("--incremental-base=", argv[i]) || is_prefix_of("--incremental-base=", argv[i])
|| is_prefix_of("--incremental-patch=", argv[i])
|| is_prefix_of("--debug=", argv[i])) || is_prefix_of("--debug=", argv[i]))
continue; continue;
if (strcmp(argv[i], "--incremental-base") == 0 if (strcmp(argv[i], "--incremental-base") == 0
|| strcmp(argv[i], "--incremental-patch") == 0
|| strcmp(argv[i], "--debug") == 0) || strcmp(argv[i], "--debug") == 0)
{ {
// When these options are used without the '=', skip the // When these options are used without the '=', skip the

View 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; off_t start = p->start_ > minoff ? p->start_ : minoff;
start = align_address(start, align); start = align_address(start, align);
off_t end = start + len; 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 (end <= p->end_)
{ {
if (p->start_ + 3 >= start && p->end_ <= end + 3) 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; return start;
} }
} }
if (this->extend_)
{
off_t start = align_address(this->length_, align);
this->length_ = start + len;
return start;
}
return -1; return -1;
} }
@ -1413,6 +1424,21 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
&& strcmp(name + strlen(name) - 3, "str") == 0) && strcmp(name + strlen(name) - 3, "str") == 0)
this->have_stabstr_section_ = true; 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 // If we have already attached the sections to segments, then we
// need to attach this one now. This happens for sections created // need to attach this one now. This happens for sections created
// directly by the linker. // directly by the linker.

View file

@ -234,6 +234,17 @@ parse_double(const char* option_name, const char* arg, double* retval)
option_name, arg); 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 void
parse_string(const char* option_name, const char* arg, const char** retval) parse_string(const char* option_name, const char* arg, const char** retval)
{ {

View file

@ -97,6 +97,9 @@ parse_uint64(const char* option_name, const char* arg, uint64_t* retval);
extern void extern void
parse_double(const char* option_name, const char* arg, double* retval); 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 extern void
parse_string(const char* option_name, const char* arg, const char** retval); 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, \ #default_value__, helpstring__, helparg__, false, \
double, double, options::parse_double) 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__, \ #define DEFINE_string(varname__, dashes__, shortname__, default_value__, \
helpstring__, helparg__) \ helpstring__, helparg__) \
DEFINE_var(varname__, dashes__, shortname__, default_value__, \ DEFINE_var(varname__, dashes__, shortname__, default_value__, \
@ -813,6 +822,10 @@ class General_options
DEFINE_special(incremental_unknown, options::TWO_DASHES, '\0', DEFINE_special(incremental_unknown, options::TWO_DASHES, '\0',
N_("Use timestamps to check files (default)"), NULL); 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", DEFINE_string(init, options::ONE_DASH, '\0', "_init",
N_("Call SYMBOL at load-time"), N_("SYMBOL")); N_("Call SYMBOL at load-time"), N_("SYMBOL"));

View file

@ -2153,10 +2153,12 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
is_noload_(false), is_noload_(false),
always_keeps_input_sections_(false), always_keeps_input_sections_(false),
has_fixed_layout_(false), has_fixed_layout_(false),
is_patch_space_allowed_(false),
tls_offset_(0), tls_offset_(0),
checkpoint_(NULL), checkpoint_(NULL),
lookup_maps_(new Output_section_lookup_maps), lookup_maps_(new Output_section_lookup_maps),
free_list_() free_list_(),
patch_space_(0)
{ {
// An unallocated section has no address. Forcing this means that // An unallocated section has no address. Forcing this means that
// we don't need special treatment for symbols defined in debug // 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, offset_in_section = this->free_list_.allocate(input_section_size,
addralign, 0); addralign, 0);
if (offset_in_section == -1) 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; aligned_offset_in_section = offset_in_section;
} }
else 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(), offset_in_section = this->free_list_.allocate(posd->data_size(),
posd->addralign(), 0); posd->addralign(), 0);
if (offset_in_section == -1) if (offset_in_section == -1)
gold_fallback(_("out of patch space; " gold_fallback(_("out of patch space in section %s; "
"relink with --incremental-full")); "relink with --incremental-full"),
this->name());
// Finalize the address and offset now. // Finalize the address and offset now.
uint64_t addr = this->address(); uint64_t addr = this->address();
off_t offset = this->offset(); off_t offset = this->offset();
@ -2946,30 +2951,48 @@ Output_section::update_data_size()
void void
Output_section::set_final_data_size() Output_section::set_final_data_size()
{ {
off_t data_size;
if (this->input_sections_.empty()) if (this->input_sections_.empty())
data_size = this->current_data_size_for_child();
else
{ {
this->set_data_size(this->current_data_size_for_child()); if (this->must_sort_attached_input_sections()
return; || 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;
} }
if (this->must_sort_attached_input_sections() // For full incremental links, we want to allocate some patch space
|| this->input_section_order_specified()) // in most sections for subsequent incremental updates.
this->sort_attached_input_sections(); if (this->is_patch_space_allowed_ && parameters->incremental_full())
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()); double pct = parameters->options().incremental_patch();
p->set_address_and_file_offset(address + (off - startoff), off, off_t extra = static_cast<off_t>(data_size * pct);
startoff); off_t new_size = align_address(data_size + extra, this->addralign());
off += p->data_size(); 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. // Reset the address and file offset.
@ -2988,8 +3011,16 @@ Output_section::do_reset_address_and_file_offset()
p != this->input_sections_.end(); p != this->input_sections_.end();
++p) ++p)
p->reset_address_and_file_offset(); 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. // Return true if address and file offset have the values after reset.
bool bool
@ -4265,14 +4296,15 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
(*p)->finalize_data_size(); (*p)->finalize_data_size();
} }
gold_debug(DEBUG_INCREMENTAL, if (parameters->incremental_update())
"set_section_list_addresses: %08lx %08lx %s", gold_debug(DEBUG_INCREMENTAL,
static_cast<long>(off), "set_section_list_addresses: %08lx %08lx %s",
static_cast<long>((*p)->data_size()), static_cast<long>(off),
((*p)->output_section() != NULL static_cast<long>((*p)->data_size()),
? (*p)->output_section()->name() : "(special)")); ((*p)->output_section() != NULL
? (*p)->output_section()->name() : "(special)"));
// We want to ignore the size of a SHF_TLS or SHT_NOBITS // We want to ignore the size of a SHF_TLS SHT_NOBITS
// section. Such a section does not affect the size of a // section. Such a section does not affect the size of a
// PT_LOAD segment. // PT_LOAD segment.
if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS) if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS)

View file

@ -3427,6 +3427,12 @@ class Output_section : public Output_data
has_fixed_layout() const has_fixed_layout() const
{ return this->has_fixed_layout_; } { 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 // Reserve space within the fixed layout for the section. Used for
// incremental update links. // incremental update links.
void void
@ -3890,6 +3896,8 @@ class Output_section : public Output_data
bool always_keeps_input_sections_ : 1; bool always_keeps_input_sections_ : 1;
// Whether this section has a fixed layout, for incremental update links. // Whether this section has a fixed layout, for incremental update links.
bool has_fixed_layout_ : 1; 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 // For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment. // of the TLS segment.
uint64_t tls_offset_; uint64_t tls_offset_;
@ -3900,6 +3908,8 @@ class Output_section : public Output_data
// List of available regions within the section, for incremental // List of available regions within the section, for incremental
// update links. // update links.
Free_list free_list_; 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 // An output segment. PT_LOAD segments are built from collections of

View file

@ -248,6 +248,14 @@ Parameters::incremental() const
return this->incremental_mode_ != General_options::INCREMENTAL_OFF; 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. // Return true if we are doing an incremental update.
bool bool

View file

@ -159,6 +159,10 @@ class Parameters
bool bool
incremental() const; 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. // Return true if we are doing an incremental update.
bool bool
incremental_update() const; incremental_update() const;

View 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 \ 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 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 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 @sleep 1
cp -f two_file_test_1.o two_file_test_tmp_2.o 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 $(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

View 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@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@ 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@ 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@ @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@ 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 @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

View file

@ -62,7 +62,7 @@
bool bool
t1() t1()
{ {
return t1_2() == 0; return t1_2() == 0; // Intentionally wrong.
} }
// 2 Code in file 1 refers to global data in file 2. // 2 Code in file 1 refers to global data in file 2.
@ -70,7 +70,7 @@ t1()
bool bool
t2() t2()
{ {
return v2 == 0; return v2 == 0; // Intentionally wrong.
} }
// 3 Code in file 1 referes to common symbol in file 2. // 3 Code in file 1 referes to common symbol in file 2.
@ -78,7 +78,7 @@ t2()
bool bool
t3() t3()
{ {
return v3 == 0; return v3 == 0; // Intentionally wrong.
} }
// 4 Code in file 1 refers to offset within global data in file 2. // 4 Code in file 1 refers to offset within global data in file 2.
@ -231,13 +231,6 @@ t17()
bool bool
t18() t18()
{ {
char c = 'a'; // Stubbed out; full implementation in two_file_test_1.cc.
for (int i = 0; i < T17_COUNT; ++i)
{
const char* s = f18(i);
if (s[0] != c || s[1] != '\0')
return false;
++c;
}
return true; return true;
} }