2009-10-09 Doug Kwan <dougkwan@google.com>

* layout.cc (Layout::make_output_section): Call target hook to make
	ordinary output section.
	(Layout::finalize): Adjust parameter list of call the
	Target::may_relax().
	* layout.h (class Layout::section_list): New method.
	* merge.h (Output_merge_base::entsize): Change visibility to public.
	(Output_merge_base::is_string, Output_merge_base::do_is_string):
	New methods.
	(Output_merge_string::do_is_string): New method.
	* object.cc (Sized_relobj::do_setup): renamed from
	Sized_relobj::set_up.
	* object.h (Sized_relobj::adjust_shndx,
	Sized_relobj::initializ_input_to_output_maps,
	Sized_relobj::free_input_to_output_maps): Change visibilities to
	protected.
	(Sized_relobj::setup): Virtualize.
	(Sized_relobj::do_setup): New method declaration.
	(Sized_relobj::invalidate_section_offset,
	Sized_relobj::do_invalidate_section_offset): New method decfinitions.
	(Sized_relobj::elf_file, Sized_relobj::local_values): New methods.
	* options.cc (parse_int): New function.
	* options.h (parse_int): New declaration.
	(DEFINE_int): New macro.
	(stub_group_size): New option.
	* output.cc (Output_section::Output_section): Initialize memebers
	merge_section_map_, merge_section_by_properties_map_,
	relaxed_input_section_map_, is_relaxed_input_section_map_valid_.
	(Output_section::add_input_section): Handled deferred code-fill
	generation and remove an old comment.
	(Output_section::add_relaxed_input_section): New method definition.
	(Output_section::add_merge_input_section): Use merge section by
	properties map to speed to search.  Update merge section maps
	as appropriate.
	(Output_section::build_relaxation_map): New method definition.
	(Output_section::convert_input_sections_in_list_to_relaxed_sections):
	Same.
	(Output_section::relax_input_section): Renamed to
	Output_section::convert_input_sections_to_relaxed_sections and change
	interface to take a vector of pointers to relaxed sections.
	(Output_section::find_merge_section,
	Output_section::find_relaxed_input_section): New method definitions.
	(Output_section::is_input_address_mapped,
	Output_section::output_offset, Output_section::output_address):
	Use output section data maps to speed up searching.
	(Output_section::find_starting_output_address): Add comments.
	(Output_section::do_write,
	Output_section::write_to_postprocessing_buffer): Do code-fill
	generation as appropriate.
	(Output_section::get_input_sections): Invalidate relaxed input section
	map.
	(Output_section::restore_states): Adjust type of checkpoint .
	Invalidate relaxed input section map.
	* output.h (Output_merge_base): New class declaration.
	(Input_section_specifier): New class defintion.
	(class Output_relaxed_input_section) Change base class to
	Output_section_data_build.
	(Output_relaxed_input_section::Output_relaxed_input_section): Adjust
	base class initializer.
	(Output_section::add_relaxed_input_section): New method declaration.
	(Output_section::Input_section): Change visibility to protected.
     	(Output_section::Input_section::relobj,
	Output_section::Input_section::shndx): Handle relaxed input sections.
	Output_section::input_sections) Change visibility to protected.  Also
	define overload to return a non-const pointer.
	(Output_section::Merge_section_properties): New class defintion.
	(Output_section::Merge_section_by_properties_map,
	Output_section::Output_section_data_by_input_section_map,
	Output_section::Relaxation_map): New types.
	(Output_section::relax_input_section): Rename method to
	Output_section::convert_input_sections_to_relaxed_sections and change
	interface to take a vector of relaxed section pointers.
	(Output_section::find_merge_section,
	Output_section::find_relaxed_input_section,
	Output_section::build_relaxation_map,
	Output_section::convert_input_sections_in_list_to_relaxed_sections):
	New method declarations.
	(Output_section::merge_section_map_
	Output_section::merge_section_by_properties_map_,
	Output_section::relaxed_input_section_map_,
	Output_section::is_relaxed_input_section_map_valid_,
	Output_section::generate_code_fills_at_write_): New data members.
	* script-sections.cc
	(Output_section_element_input::set_section_addresses): Call
	current_data_size and addralign methods of relaxed input sections.
	(Orphan_output_section::set_section_addresses): Call current_data_size
	and addralign methods of relaxed input sections.
	* symtab.cc (Symbol_table::compute_final_value): Extract template
	from the body of Symbol_table::sized_finalize_symbol.
	(Symbol_table::sized_finalized_symbol): Call
	Symbol_table::compute_final_value.
	* symtab.h (Symbol_table::Compute_final_value_status): New enum type.
	(Symbol_table::compute_final_value): New templated method declaration.
	* target.cc (Target::do_make_output_section): New method defintion.
	* target.h (Target::make_output_section): New method declaration.
	(Target::relax): Add more parameters for input objects, symbol table
	and layout.  Adjust call to do_relax.
	(Target::do_make_output_section): New method declaration.
	(Target::do_relax): Add parameters for input objects, symbol table
	and layout.
This commit is contained in:
Doug Kwan 2009-10-09 23:18:19 +00:00
parent d446d6c4f7
commit c0a6286595
15 changed files with 843 additions and 125 deletions

View File

@ -1,3 +1,105 @@
2009-10-09 Doug Kwan <dougkwan@google.com>
* layout.cc (Layout::make_output_section): Call target hook to make
ordinary output section.
(Layout::finalize): Adjust parameter list of call the
Target::may_relax().
* layout.h (class Layout::section_list): New method.
* merge.h (Output_merge_base::entsize): Change visibility to public.
(Output_merge_base::is_string, Output_merge_base::do_is_string):
New methods.
(Output_merge_string::do_is_string): New method.
* object.cc (Sized_relobj::do_setup): renamed from
Sized_relobj::set_up.
* object.h (Sized_relobj::adjust_shndx,
Sized_relobj::initializ_input_to_output_maps,
Sized_relobj::free_input_to_output_maps): Change visibilities to
protected.
(Sized_relobj::setup): Virtualize.
(Sized_relobj::do_setup): New method declaration.
(Sized_relobj::invalidate_section_offset,
Sized_relobj::do_invalidate_section_offset): New method decfinitions.
(Sized_relobj::elf_file, Sized_relobj::local_values): New methods.
* options.cc (parse_int): New function.
* options.h (parse_int): New declaration.
(DEFINE_int): New macro.
(stub_group_size): New option.
* output.cc (Output_section::Output_section): Initialize memebers
merge_section_map_, merge_section_by_properties_map_,
relaxed_input_section_map_, is_relaxed_input_section_map_valid_.
(Output_section::add_input_section): Handled deferred code-fill
generation and remove an old comment.
(Output_section::add_relaxed_input_section): New method definition.
(Output_section::add_merge_input_section): Use merge section by
properties map to speed to search. Update merge section maps
as appropriate.
(Output_section::build_relaxation_map): New method definition.
(Output_section::convert_input_sections_in_list_to_relaxed_sections):
Same.
(Output_section::relax_input_section): Renamed to
Output_section::convert_input_sections_to_relaxed_sections and change
interface to take a vector of pointers to relaxed sections.
(Output_section::find_merge_section,
Output_section::find_relaxed_input_section): New method definitions.
(Output_section::is_input_address_mapped,
Output_section::output_offset, Output_section::output_address):
Use output section data maps to speed up searching.
(Output_section::find_starting_output_address): Add comments.
(Output_section::do_write,
Output_section::write_to_postprocessing_buffer): Do code-fill
generation as appropriate.
(Output_section::get_input_sections): Invalidate relaxed input section
map.
(Output_section::restore_states): Adjust type of checkpoint .
Invalidate relaxed input section map.
* output.h (Output_merge_base): New class declaration.
(Input_section_specifier): New class defintion.
(class Output_relaxed_input_section) Change base class to
Output_section_data_build.
(Output_relaxed_input_section::Output_relaxed_input_section): Adjust
base class initializer.
(Output_section::add_relaxed_input_section): New method declaration.
(Output_section::Input_section): Change visibility to protected.
(Output_section::Input_section::relobj,
Output_section::Input_section::shndx): Handle relaxed input sections.
Output_section::input_sections) Change visibility to protected. Also
define overload to return a non-const pointer.
(Output_section::Merge_section_properties): New class defintion.
(Output_section::Merge_section_by_properties_map,
Output_section::Output_section_data_by_input_section_map,
Output_section::Relaxation_map): New types.
(Output_section::relax_input_section): Rename method to
Output_section::convert_input_sections_to_relaxed_sections and change
interface to take a vector of relaxed section pointers.
(Output_section::find_merge_section,
Output_section::find_relaxed_input_section,
Output_section::build_relaxation_map,
Output_section::convert_input_sections_in_list_to_relaxed_sections):
New method declarations.
(Output_section::merge_section_map_
Output_section::merge_section_by_properties_map_,
Output_section::relaxed_input_section_map_,
Output_section::is_relaxed_input_section_map_valid_,
Output_section::generate_code_fills_at_write_): New data members.
* script-sections.cc
(Output_section_element_input::set_section_addresses): Call
current_data_size and addralign methods of relaxed input sections.
(Orphan_output_section::set_section_addresses): Call current_data_size
and addralign methods of relaxed input sections.
* symtab.cc (Symbol_table::compute_final_value): Extract template
from the body of Symbol_table::sized_finalize_symbol.
(Symbol_table::sized_finalized_symbol): Call
Symbol_table::compute_final_value.
* symtab.h (Symbol_table::Compute_final_value_status): New enum type.
(Symbol_table::compute_final_value): New templated method declaration.
* target.cc (Target::do_make_output_section): New method defintion.
* target.h (Target::make_output_section): New method declaration.
(Target::relax): Add more parameters for input objects, symbol table
and layout. Adjust call to do_relax.
(Target::do_make_output_section): New method declaration.
(Target::do_relax): Add parameters for input objects, symbol table
and layout.
2009-10-09 Andrew Pinski <andrew_pinski@playstation.sony.com>
* pread.c: Include stdio.h.

View File

@ -870,7 +870,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
this->debug_info_->set_abbreviations(this->debug_abbrev_);
}
else
os = new Output_section(name, type, flags);
{
// FIXME: const_cast is ugly.
Target* target = const_cast<Target*>(&parameters->target());
os = target->make_output_section(name, type, flags);
}
parameters->target().new_output_section(os);
@ -1592,7 +1596,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
&shndx);
pass++;
}
while (target->may_relax() && target->relax(pass));
while (target->may_relax()
&& target->relax(pass, input_objects, symtab, this));
// Set the file offsets of all the non-data sections we've seen so
// far which don't have to wait for the input sections. We need

View File

@ -602,6 +602,11 @@ class Layout
this->script_output_section_data_list_.push_back(posd);
}
// Return section list.
const Section_list&
section_list() const
{ return this->section_list_; }
private:
Layout(const Layout&);
Layout& operator=(const Layout&);

View File

@ -219,6 +219,17 @@ class Output_merge_base : public Output_section_data
: Output_section_data(addralign), merge_map_(), entsize_(entsize)
{ }
// Return the entry size.
uint64_t
entsize() const
{ return this->entsize_; }
// Whether this is a merge string section. This is only true of
// Output_merge_string.
bool
is_string()
{ return this->do_is_string(); }
protected:
// Return the output offset for an input offset.
bool
@ -230,11 +241,6 @@ class Output_merge_base : public Output_section_data
bool
do_is_merge_section_for(const Relobj*, unsigned int shndx) const;
// Return the entry size.
uint64_t
entsize() const
{ return this->entsize_; }
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in the output section. OUTPUT_OFFSET
// is the offset from the start of the merged data in the output
@ -246,6 +252,11 @@ class Output_merge_base : public Output_section_data
this->merge_map_.add_mapping(object, shndx, offset, length, output_offset);
}
// This may be overriden by the child class.
virtual bool
do_is_string()
{ return false; }
private:
// A mapping from input object/section/offset to offset in output
// section.
@ -424,6 +435,11 @@ class Output_merge_string : public Output_merge_base
clear_stringpool()
{ this->stringpool_.clear(); }
// Whether this is a merge string section.
virtual bool
do_is_string()
{ return true; }
private:
// The name of the string type, for stats.
const char*

View File

@ -359,7 +359,7 @@ Sized_relobj<size, big_endian>::~Sized_relobj()
template<int size, bool big_endian>
void
Sized_relobj<size, big_endian>::setup()
Sized_relobj<size, big_endian>::do_setup()
{
const unsigned int shnum = this->elf_file_.shnum();
this->set_shnum(shnum);

View File

@ -1324,7 +1324,8 @@ class Sized_relobj : public Relobj
// Set up the object file based on TARGET.
void
setup();
setup()
{ this->do_setup(); }
// Return the number of symbols. This is only valid after
// Object::add_symbols has been called.
@ -1462,7 +1463,16 @@ class Sized_relobj : public Relobj
Address
map_to_kept_section(unsigned int shndx, bool* found) const;
// Make section offset invalid. This is needed for relaxation.
void
invalidate_section_offset(unsigned int shndx)
{ this->do_invalidate_section_offset(shndx); }
protected:
// Set up.
virtual void
do_setup();
// Read the symbols.
void
do_read_symbols(Read_symbols_data*);
@ -1596,6 +1606,48 @@ class Sized_relobj : public Relobj
this->section_offsets_[shndx] = convert_types<Address, uint64_t>(off);
}
// Set the offset of a section to invalid_address.
virtual void
do_invalidate_section_offset(unsigned int shndx)
{
gold_assert(shndx < this->section_offsets_.size());
this->section_offsets_[shndx] = invalid_address;
}
// Adjust a section index if necessary.
unsigned int
adjust_shndx(unsigned int shndx)
{
if (shndx >= elfcpp::SHN_LORESERVE)
shndx += this->elf_file_.large_shndx_offset();
return shndx;
}
// Initialize input to output maps for section symbols in merged
// sections.
void
initialize_input_to_output_maps();
// Free the input to output maps for section symbols in merged
// sections.
void
free_input_to_output_maps();
// Return symbol table section index.
unsigned int
symtab_shndx() const
{ return this->symtab_shndx_; }
// Allow a child class to access the ELF file.
elfcpp::Elf_file<size, big_endian, Object>*
elf_file()
{ return &this->elf_file_; }
// Allow a child class to access the local values.
Local_values*
local_values()
{ return &this->local_values_; }
private:
// For convenience.
typedef Sized_relobj<size, big_endian> This;
@ -1618,15 +1670,6 @@ class Sized_relobj : public Relobj
typedef std::map<unsigned int, Kept_comdat_section>
Kept_comdat_section_table;
// Adjust a section index if necessary.
unsigned int
adjust_shndx(unsigned int shndx)
{
if (shndx >= elfcpp::SHN_LORESERVE)
shndx += this->elf_file_.large_shndx_offset();
return shndx;
}
// Find the SHT_SYMTAB section, given the section headers.
void
find_symtab(const unsigned char* pshdrs);
@ -1742,16 +1785,6 @@ class Sized_relobj : public Relobj
find_functions(const unsigned char* pshdrs, unsigned int shndx,
Function_offsets*);
// Initialize input to output maps for section symbols in merged
// sections.
void
initialize_input_to_output_maps();
// Free the input to output maps for section symbols in merged
// sections.
void
free_input_to_output_maps();
// Write out the local symbols.
void
write_local_symbols(Output_file*,

View File

@ -194,6 +194,16 @@ parse_uint(const char* option_name, const char* arg, int* retval)
option_name, arg);
}
void
parse_int(const char* option_name, const char* arg, int* retval)
{
char* endptr;
*retval = strtol(arg, &endptr, 0);
if (*endptr != '\0')
gold_fatal(_("%s: invalid option value (expected an integer): %s"),
option_name, arg);
}
void
parse_uint64(const char* option_name, const char* arg, uint64_t *retval)
{

View File

@ -82,6 +82,9 @@ typedef Unordered_set<std::string> String_set;
extern void
parse_bool(const char* option_name, const char* arg, bool* retval);
extern void
parse_int(const char* option_name, const char* arg, int* retval);
extern void
parse_uint(const char* option_name, const char* arg, int* retval);
@ -333,6 +336,12 @@ struct Struct_special : public Struct_var
}; \
Struct_disable_##varname__ disable_##varname__##_initializer_
#define DEFINE_int(varname__, dashes__, shortname__, default_value__, \
helpstring__, helparg__) \
DEFINE_var(varname__, dashes__, shortname__, default_value__, \
#default_value__, helpstring__, helparg__, false, \
int, int, options::parse_int)
#define DEFINE_uint(varname__, dashes__, shortname__, default_value__, \
helpstring__, helparg__) \
DEFINE_var(varname__, dashes__, shortname__, default_value__, \
@ -802,6 +811,12 @@ class General_options
DEFINE_bool(strip_lto_sections, options::TWO_DASHES, '\0', true,
N_("Strip LTO intermediate code sections"), NULL);
DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
N_("(ARM only) The maximum distance from instructions in a group "
"of sections to their stubs. Negative values mean stubs "
"are always after the group. 1 means using default size.\n"),
N_("SIZE"));
DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false,
N_("Use less memory and more disk I/O "
"(included only for compatibility with GNU ld)"), NULL);

View File

@ -1801,7 +1801,12 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
is_small_section_(false),
is_large_section_(false),
tls_offset_(0),
checkpoint_(NULL)
checkpoint_(NULL),
merge_section_map_(),
merge_section_by_properties_map_(),
relaxed_input_section_map_(),
is_relaxed_input_section_map_valid_(true),
generate_code_fills_at_write_(false)
{
// An unallocated section has no address. Forcing this means that
// we don't need special treatment for symbols defined in debug
@ -1892,7 +1897,21 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
off_t aligned_offset_in_section = align_address(offset_in_section,
addralign);
// Determine if we want to delay code-fill generation until the output
// section is written. When the target is relaxing, we want to delay fill
// generating to avoid adjusting them during relaxation.
if (!this->generate_code_fills_at_write_
&& !have_sections_script
&& (sh_flags & elfcpp::SHF_EXECINSTR) != 0
&& parameters->target().has_code_fill()
&& parameters->target().may_relax())
{
gold_assert(this->fills_.empty());
this->generate_code_fills_at_write_ = true;
}
if (aligned_offset_in_section > offset_in_section
&& !this->generate_code_fills_at_write_
&& !have_sections_script
&& (sh_flags & elfcpp::SHF_EXECINSTR) != 0
&& parameters->target().has_code_fill())
@ -1905,8 +1924,6 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
this->fills_.push_back(Fill(offset_in_section, fill_len));
else
{
// FIXME: When relaxing, the size needs to adjust to
// maintain a constant alignment.
std::string fill_data(parameters->target().code_fill(fill_len));
Output_data_const* odc = new Output_data_const(fill_data, 1);
this->input_sections_.push_back(Input_section(odc));
@ -1951,6 +1968,31 @@ Output_section::add_output_section_data(Output_section_data* posd)
}
}
// Add a relaxed input section.
void
Output_section::add_relaxed_input_section(Output_relaxed_input_section* poris)
{
Input_section inp(poris);
this->add_output_section_data(&inp);
if (this->is_relaxed_input_section_map_valid_)
{
Input_section_specifier iss(poris->relobj(), poris->shndx());
this->relaxed_input_section_map_[iss] = poris;
}
// For a relaxed section, we use the current data size. Linker scripts
// get all the input sections, including relaxed one from an output
// section and add them back to them same output section to compute the
// output section size. If we do not account for sizes of relaxed input
// sections, an output section would be incorrectly sized.
off_t offset_in_section = this->current_data_size_for_child();
off_t aligned_offset_in_section = align_address(offset_in_section,
poris->addralign());
this->set_current_data_size_for_child(aligned_offset_in_section
+ poris->current_data_size());
}
// Add arbitrary data to an output section by Input_section.
void
@ -1995,73 +2037,151 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
// We cannot restore merged input section states.
gold_assert(this->checkpoint_ == NULL);
Input_section_list::iterator p;
for (p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
if (p->is_merge_section(is_string, entsize, addralign))
{
p->add_input_section(object, shndx);
return true;
}
// Look up merge sections by required properties.
Merge_section_properties msp(is_string, entsize, addralign);
Merge_section_by_properties_map::const_iterator p =
this->merge_section_by_properties_map_.find(msp);
if (p != this->merge_section_by_properties_map_.end())
{
Output_merge_base* merge_section = p->second;
merge_section->add_input_section(object, shndx);
gold_assert(merge_section->is_string() == is_string
&& merge_section->entsize() == entsize
&& merge_section->addralign() == addralign);
// Link input section to found merge section.
Input_section_specifier iss(object, shndx);
this->merge_section_map_[iss] = merge_section;
return true;
}
// We handle the actual constant merging in Output_merge_data or
// Output_merge_string_data.
Output_section_data* posd;
Output_merge_base* pomb;
if (!is_string)
posd = new Output_merge_data(entsize, addralign);
pomb = new Output_merge_data(entsize, addralign);
else
{
switch (entsize)
{
case 1:
posd = new Output_merge_string<char>(addralign);
pomb = new Output_merge_string<char>(addralign);
break;
case 2:
posd = new Output_merge_string<uint16_t>(addralign);
pomb = new Output_merge_string<uint16_t>(addralign);
break;
case 4:
posd = new Output_merge_string<uint32_t>(addralign);
pomb = new Output_merge_string<uint32_t>(addralign);
break;
default:
return false;
}
}
this->add_output_merge_section(posd, is_string, entsize);
posd->add_input_section(object, shndx);
// Add new merge section to this output section and link merge section
// properties to new merge section in map.
this->add_output_merge_section(pomb, is_string, entsize);
this->merge_section_by_properties_map_[msp] = pomb;
// Add input section to new merge section and link input section to new
// merge section in map.
pomb->add_input_section(object, shndx);
Input_section_specifier iss(object, shndx);
this->merge_section_map_[iss] = pomb;
return true;
}
// Relax an existing input section.
void
Output_section::relax_input_section(Output_relaxed_input_section *psection)
{
Relobj* relobj = psection->relobj();
unsigned int shndx = psection->shndx();
// Build a relaxation map to speed up relaxation of existing input sections.
// Look up to the first LIMIT elements in INPUT_SECTIONS.
void
Output_section::build_relaxation_map(
const Input_section_list& input_sections,
size_t limit,
Relaxation_map* relaxation_map) const
{
for (size_t i = 0; i < limit; ++i)
{
const Input_section& is(input_sections[i]);
if (is.is_input_section() || is.is_relaxed_input_section())
{
Input_section_specifier iss(is.relobj(), is.shndx());
(*relaxation_map)[iss] = i;
}
}
}
// Convert regular input sections in INPUT_SECTIONS into relaxed input
// sections in RELAXED_SECTIONS. MAP is a prebuilt map from input section
// specifier to indices of INPUT_SECTIONS.
void
Output_section::convert_input_sections_in_list_to_relaxed_sections(
const std::vector<Output_relaxed_input_section*>& relaxed_sections,
const Relaxation_map& map,
Input_section_list* input_sections)
{
for (size_t i = 0; i < relaxed_sections.size(); ++i)
{
Output_relaxed_input_section* poris = relaxed_sections[i];
Input_section_specifier iss(poris->relobj(), poris->shndx());
Relaxation_map::const_iterator p = map.find(iss);
gold_assert(p != map.end());
gold_assert((*input_sections)[p->second].is_input_section());
(*input_sections)[p->second] = Input_section(poris);
}
}
// Convert regular input sections into relaxed input sections. RELAXED_SECTIONS
// is a vector of pointers to Output_relaxed_input_section or its derived
// classes. The relaxed sections must correspond to existing input sections.
void
Output_section::convert_input_sections_to_relaxed_sections(
const std::vector<Output_relaxed_input_section*>& relaxed_sections)
{
gold_assert(parameters->target().may_relax());
// This is not very efficient if we a going to relax a number of sections
// in an Output_section with lot of Input_sections.
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
{
if (p->is_input_section())
{
if (p->relobj() == relobj && p->shndx() == shndx)
{
gold_assert(p->addralign() == psection->addralign());
*p = Input_section(psection);
return;
}
}
else if (p->is_relaxed_input_section())
gold_assert(p->relobj() != relobj || p->shndx() != shndx);
// We want to make sure that restore_states does not undo the effect of
// this. If there is no checkpoint active, just search the current
// input section list and replace the sections there. If there is
// a checkpoint, also replace the sections there.
// By default, we look at the whole list.
size_t limit = this->input_sections_.size();
if (this->checkpoint_ != NULL)
{
// Replace input sections with relaxed input section in the saved
// copy of the input section list.
if (this->checkpoint_->input_sections_saved())
{
Relaxation_map map;
this->build_relaxation_map(
*(this->checkpoint_->input_sections()),
this->checkpoint_->input_sections()->size(),
&map);
this->convert_input_sections_in_list_to_relaxed_sections(
relaxed_sections,
map,
this->checkpoint_->input_sections());
}
else
{
// We have not copied the input section list yet. Instead, just
// look at the portion that would be saved.
limit = this->checkpoint_->input_sections_size();
}
}
// Convert input sections in input_section_list.
Relaxation_map map;
this->build_relaxation_map(this->input_sections_, limit, &map);
this->convert_input_sections_in_list_to_relaxed_sections(
relaxed_sections,
map,
&this->input_sections_);
}
// Update the output section flags based on input section flags.
@ -2082,6 +2202,60 @@ Output_section::update_flags_for_input_section(elfcpp::Elf_Xword flags)
| elfcpp::SHF_EXECINSTR));
}
// Find the merge section into which an input section with index SHNDX in
// OBJECT has been added. Return NULL if none found.
Output_section_data*
Output_section::find_merge_section(const Relobj* object,
unsigned int shndx) const
{
Input_section_specifier iss(object, shndx);
Output_section_data_by_input_section_map::const_iterator p =
this->merge_section_map_.find(iss);
if (p != this->merge_section_map_.end())
{
Output_section_data* posd = p->second;
gold_assert(posd->is_merge_section_for(object, shndx));
return posd;
}
else
return NULL;
}
// Find an relaxed input section corresponding to an input section
// in OBJECT with index SHNDX.
const Output_section_data*
Output_section::find_relaxed_input_section(const Relobj* object,
unsigned int shndx) const
{
// Be careful that the map may not be valid due to input section export
// to scripts or a check-point restore.
if (!this->is_relaxed_input_section_map_valid_)
{
// Rebuild the map as needed.
this->relaxed_input_section_map_.clear();
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
if (p->is_relaxed_input_section())
{
Input_section_specifier iss(p->relobj(), p->shndx());
this->relaxed_input_section_map_[iss] =
p->relaxed_input_section();
}
this->is_relaxed_input_section_map_valid_ = true;
}
Input_section_specifier iss(object, shndx);
Output_section_data_by_input_section_map::const_iterator p =
this->relaxed_input_section_map_.find(iss);
if (p != this->relaxed_input_section_map_.end())
return p->second;
else
return NULL;
}
// Given an address OFFSET relative to the start of input section
// SHNDX in OBJECT, return whether this address is being included in
// the final link. This should only be called if SHNDX in OBJECT has
@ -2092,6 +2266,20 @@ Output_section::is_input_address_mapped(const Relobj* object,
unsigned int shndx,
off_t offset) const
{
// Look at the Output_section_data_maps first.
const Output_section_data* posd = this->find_merge_section(object, shndx);
if (posd == NULL)
posd = this->find_relaxed_input_section(object, shndx);
if (posd != NULL)
{
section_offset_type output_offset;
bool found = posd->output_offset(object, shndx, offset, &output_offset);
gold_assert(found);
return output_offset != -1;
}
// Fall back to the slow look-up.
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
@ -2116,9 +2304,23 @@ section_offset_type
Output_section::output_offset(const Relobj* object, unsigned int shndx,
section_offset_type offset) const
{
// This can only be called meaningfully when layout is complete.
gold_assert(Output_data::is_layout_complete());
// This can only be called meaningfully when we know the data size
// of this.
gold_assert(this->is_data_size_valid());
// Look at the Output_section_data_maps first.
const Output_section_data* posd = this->find_merge_section(object, shndx);
if (posd == NULL)
posd = this->find_relaxed_input_section(object, shndx);
if (posd != NULL)
{
section_offset_type output_offset;
bool found = posd->output_offset(object, shndx, offset, &output_offset);
gold_assert(found);
return output_offset;
}
// Fall back to the slow look-up.
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
@ -2138,6 +2340,20 @@ Output_section::output_address(const Relobj* object, unsigned int shndx,
off_t offset) const
{
uint64_t addr = this->address() + this->first_input_offset_;
// Look at the Output_section_data_maps first.
const Output_section_data* posd = this->find_merge_section(object, shndx);
if (posd == NULL)
posd = this->find_relaxed_input_section(object, shndx);
if (posd != NULL && posd->is_address_valid())
{
section_offset_type output_offset;
bool found = posd->output_offset(object, shndx, offset, &output_offset);
gold_assert(found);
return posd->address() + output_offset;
}
// Fall back to the slow look-up.
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
@ -2169,6 +2385,9 @@ Output_section::find_starting_output_address(const Relobj* object,
unsigned int shndx,
uint64_t* paddr) const
{
// FIXME: This becomes a bottle-neck if we have many relaxed sections.
// Looking up the merge section map does not always work as we sometimes
// find a merge section without its address set.
uint64_t addr = this->address() + this->first_input_offset_;
for (Input_section_list::const_iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
@ -2532,6 +2751,9 @@ Output_section::do_write(Output_file* of)
{
gold_assert(!this->requires_postprocessing());
// If the target performs relaxation, we delay filler generation until now.
gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
off_t output_section_file_offset = this->offset();
for (Fill_list::iterator p = this->fills_.begin();
p != this->fills_.end();
@ -2542,10 +2764,22 @@ Output_section::do_write(Output_file* of)
fill_data.data(), fill_data.size());
}
off_t off = this->offset() + this->first_input_offset_;
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
p->write(of);
{
off_t aligned_off = align_address(off, p->addralign());
if (this->generate_code_fills_at_write_ && (off != aligned_off))
{
size_t fill_len = aligned_off - off;
std::string fill_data(parameters->target().code_fill(fill_len));
of->write(off, fill_data.data(), fill_data.size());
}
p->write(of);
off = aligned_off + p->data_size();
}
}
// If a section requires postprocessing, create the buffer to use.
@ -2586,6 +2820,9 @@ Output_section::write_to_postprocessing_buffer()
{
gold_assert(this->requires_postprocessing());
// If the target performs relaxation, we delay filler generation until now.
gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
unsigned char* buffer = this->postprocessing_buffer();
for (Fill_list::iterator p = this->fills_.begin();
p != this->fills_.end();
@ -2601,9 +2838,16 @@ Output_section::write_to_postprocessing_buffer()
p != this->input_sections_.end();
++p)
{
off = align_address(off, p->addralign());
p->write_to_buffer(buffer + off);
off += p->data_size();
off_t aligned_off = align_address(off, p->addralign());
if (this->generate_code_fills_at_write_ && (off != aligned_off))
{
size_t fill_len = aligned_off - off;
std::string fill_data(parameters->target().code_fill(fill_len));
memcpy(buffer + off, fill_data.data(), fill_data.size());
}
p->write_to_buffer(buffer + aligned_off);
off = aligned_off + p->data_size();
}
}
@ -2627,6 +2871,9 @@ Output_section::get_input_sections(
&& !this->checkpoint_->input_sections_saved())
this->checkpoint_->save_input_sections();
// Invalidate the relaxed input section map.
this->is_relaxed_input_section_map_valid_ = false;
uint64_t orig_address = address;
address = align_address(address, this->addralign());
@ -2738,11 +2985,15 @@ Output_section::restore_states()
// extremely large output with hundreads of thousands of input
// objects. We may need to re-think how we should pass sections
// to scripts.
this->input_sections_ = checkpoint->input_sections();
this->input_sections_ = *checkpoint->input_sections();
}
this->attached_input_sections_are_sorted_ =
checkpoint->attached_input_sections_are_sorted();
// Simply invalidate the relaxed input section map since we do not keep
// track of it.
this->is_relaxed_input_section_map_valid_ = false;
}
// Print to the map file.

View File

@ -38,6 +38,7 @@ class General_options;
class Object;
class Symbol;
class Output_file;
class Output_merge_base;
class Output_section;
class Relocatable_relocs;
class Target;
@ -46,6 +47,71 @@ class Sized_target;
template<int size, bool big_endian>
class Sized_relobj;
// This class specifies an input section. It is used as a key type
// for maps.
class Input_section_specifier
{
public:
Input_section_specifier(const Relobj* relobj, unsigned int shndx)
: relobj_(relobj), shndx_(shndx)
{ }
// Return Relobj of this.
const Relobj*
relobj() const
{ return this->relobj_; }
// Return section index of this.
unsigned int
shndx() const
{ return this->shndx_; }
// Whether this equals to another specifier ISS.
bool
eq(const Input_section_specifier& iss) const
{ return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; }
// Compute a hash value of this.
size_t
hash_value() const
{ return this->string_hash(this->relobj_->name().c_str()) ^ this->shndx_; }
// Functors for containers.
struct equal_to
{
bool
operator()(const Input_section_specifier& iss1,
const Input_section_specifier& iss2) const
{ return iss1.eq(iss2); }
};
struct hash
{
size_t
operator()(const Input_section_specifier& iss) const
{ return iss.hash_value(); }
};
private:
// For portability, we use our own string hash function instead of assuming
// __gnu_cxx::hash or std::tr1::hash is available. This is the same hash
// function used in Stringpool_template::string_hash.
static size_t
string_hash(const char* s)
{
size_t h = 5381;
while (*s != '\0')
h = h * 33 + *s++;
return h;
}
// An object.
const Relobj* relobj_;
// A section index.
unsigned int shndx_;
};
// An abtract class for data which has to go into the output file.
class Output_data
@ -1987,7 +2053,7 @@ class Output_symtab_xindex : public Output_section_data
};
// A relaxed input section.
class Output_relaxed_input_section : public Output_section_data
class Output_relaxed_input_section : public Output_section_data_build
{
public:
// We would like to call relobj->section_addralign(shndx) to get the
@ -1995,7 +2061,7 @@ class Output_relaxed_input_section : public Output_section_data
// are repsonsible for ensuring that.
Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
uint64_t addralign)
: Output_section_data(addralign), relobj_(relobj), shndx_(shndx)
: Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
{ }
// Return the Relobj of this relaxed input section.
@ -2041,6 +2107,10 @@ class Output_section : public Output_data
void
add_output_section_data(Output_section_data* posd);
// Add a relaxed input section PORIS to this output section.
void
add_relaxed_input_section(Output_relaxed_input_section* poris);
// Return the section name.
const char*
name() const
@ -2510,6 +2580,11 @@ class Output_section : public Output_data
void
restore_states();
// Convert existing input sections to relaxed input sections.
void
convert_input_sections_to_relaxed_sections(
const std::vector<Output_relaxed_input_section*>& sections);
// Print merge statistics to stderr.
void
print_merge_stats();
@ -2625,7 +2700,6 @@ class Output_section : public Output_data
void
write_to_postprocessing_buffer();
private:
// In some cases we need to keep a list of the input sections
// associated with this output section. We only need the list if we
// might have to change the offsets of the input section within the
@ -2741,16 +2815,24 @@ class Output_section : public Output_data
Relobj*
relobj() const
{
gold_assert(this->is_input_section());
return this->u2_.object;
if (this->is_input_section())
return this->u2_.object;
else if (this->is_relaxed_input_section())
return this->u2_.poris->relobj();
else
gold_unreachable();
}
// Return the input section index for an input section.
unsigned int
shndx() const
{
gold_assert(this->is_input_section());
return this->shndx_;
if (this->is_input_section())
return this->shndx_;
else if (this->is_relaxed_input_section())
return this->u2_.poris->shndx();
else
gold_unreachable();
}
// For non-input-sections, return the associated Output_section_data
@ -2891,6 +2973,12 @@ class Output_section : public Output_data
typedef std::vector<Input_section> Input_section_list;
// Allow a child class to access the input sections.
const Input_section_list&
input_sections() const
{ return this->input_sections_; }
private:
// We only save enough information to undo the effects of section layout.
class Checkpoint_output_section
{
@ -2921,9 +3009,9 @@ class Output_section : public Output_data
{ return this->flags_; }
// Return a reference to the input section list copy.
const Input_section_list&
input_sections() const
{ return this->input_sections_copy_; }
Input_section_list*
input_sections()
{ return &this->input_sections_copy_; }
// Return the size of input_sections at the time when checkpoint is
// taken.
@ -2974,7 +3062,6 @@ class Output_section : public Output_data
bool attached_input_sections_are_sorted_;
};
private:
// This class is used to sort the input sections.
class Input_section_sort_entry;
@ -3018,6 +3105,82 @@ class Output_section : public Output_data
typedef std::vector<Fill> Fill_list;
// This class describes properties of merge data sections. It is used
// as a key type for maps.
class Merge_section_properties
{
public:
Merge_section_properties(bool is_string, uint64_t entsize,
uint64_t addralign)
: is_string_(is_string), entsize_(entsize), addralign_(addralign)
{ }
// Whether this equals to another Merge_section_properties MSP.
bool
eq(const Merge_section_properties& msp) const
{
return ((this->is_string_ == msp.is_string_)
&& (this->entsize_ == msp.entsize_)
&& (this->addralign_ == msp.addralign_));
}
// Compute a hash value for this using 64-bit FNV-1a hash.
size_t
hash_value() const
{
uint64_t h = 14695981039346656037ULL; // FNV offset basis.
uint64_t prime = 1099511628211ULL;
h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
return h;
}
// Functors for associative containers.
struct equal_to
{
bool
operator()(const Merge_section_properties& msp1,
const Merge_section_properties& msp2) const
{ return msp1.eq(msp2); }
};
struct hash
{
size_t
operator()(const Merge_section_properties& msp) const
{ return msp.hash_value(); }
};
private:
// Whether this merge data section is for strings.
bool is_string_;
// Entsize of this merge data section.
uint64_t entsize_;
// Address alignment.
uint64_t addralign_;
};
// Map that link Merge_section_properties to Output_merge_base.
typedef Unordered_map<Merge_section_properties, Output_merge_base*,
Merge_section_properties::hash,
Merge_section_properties::equal_to>
Merge_section_by_properties_map;
// Map that link Input_section_specifier to Output_section_data.
typedef Unordered_map<Input_section_specifier, Output_section_data*,
Input_section_specifier::hash,
Input_section_specifier::equal_to>
Output_section_data_by_input_section_map;
// Map used during relaxation of existing sections. This map
// an input section specifier to an input section list index.
// We assume that Input_section_list is a vector.
typedef Unordered_map<Input_section_specifier, size_t,
Input_section_specifier::hash,
Input_section_specifier::equal_to>
Relaxation_map;
// Add a new output section by Input_section.
void
add_output_section_data(Input_section*);
@ -3036,14 +3199,34 @@ class Output_section : public Output_data
add_output_merge_section(Output_section_data* posd, bool is_string,
uint64_t entsize);
// Relax an existing input section.
void
relax_input_section(Output_relaxed_input_section*);
// Sort the attached input sections.
void
sort_attached_input_sections();
// Find the merge section into which an input section with index SHNDX in
// OBJECT has been added. Return NULL if none found.
Output_section_data*
find_merge_section(const Relobj* object, unsigned int shndx) const;
// Find a relaxed input section to an input section in OBJECT
// with index SHNDX. Return NULL if none is found.
const Output_section_data*
find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
// Build a relaxation map.
void
build_relaxation_map(
const Input_section_list& input_sections,
size_t limit,
Relaxation_map* map) const;
// Convert input sections in an input section list into relaxed sections.
void
convert_input_sections_in_list_to_relaxed_sections(
const std::vector<Output_relaxed_input_section*>& relaxed_sections,
const Relaxation_map& map,
Input_section_list* input_sections);
// Most of these fields are only valid after layout.
// The name of the section. This will point into a Stringpool.
@ -3149,6 +3332,18 @@ class Output_section : public Output_data
uint64_t tls_offset_;
// Saved checkpoint.
Checkpoint_output_section* checkpoint_;
// Map from input sections to merge sections.
Output_section_data_by_input_section_map merge_section_map_;
// Map from merge section properties to merge_sections;
Merge_section_by_properties_map merge_section_by_properties_map_;
// Map from input sections to relaxed input sections. This is mutable
// beacause it is udpated lazily. We may need to update it in a
// const qualified method.
mutable Output_section_data_by_input_section_map relaxed_input_section_map_;
// Whether relaxed_input_section_map_ is valid.
mutable bool is_relaxed_input_section_map_valid_;
// Whether code-fills are generated at write.
bool generate_code_fills_at_write_;
};
// An output segment. PT_LOAD segments are built from collections of

View File

@ -1325,10 +1325,17 @@ Output_section_element_input::set_section_addresses(
isi.set_section_name(relobj->section_name(shndx));
if (p->is_relaxed_input_section())
isi.set_size(p->relaxed_input_section()->data_size());
{
// We use current data size because relxed section sizes may not
// have finalized yet.
isi.set_size(p->relaxed_input_section()->current_data_size());
isi.set_addralign(p->relaxed_input_section()->addralign());
}
else
isi.set_size(relobj->section_size(shndx));
isi.set_addralign(relobj->section_addralign(shndx));
{
isi.set_size(relobj->section_size(shndx));
isi.set_addralign(relobj->section_addralign(shndx));
}
}
if (!this->match_file_name(relobj->name().c_str()))
@ -2292,7 +2299,9 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
Task_lock_obj<Object> tl(task, p->relobj());
addralign = p->relobj()->section_addralign(p->shndx());
if (p->is_relaxed_input_section())
size = p->relaxed_input_section()->data_size();
// We use current data size because relxed section sizes may not
// have finalized yet.
size = p->relaxed_input_section()->current_data_size();
else
size = p->relobj()->section_size(p->shndx());
}

View File

@ -2355,30 +2355,17 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool,
return off;
}
// Finalize the symbol SYM. This returns true if the symbol should be
// added to the symbol table, false otherwise.
// Compute the final value of SYM and store status in location PSTATUS.
// During relaxation, this may be called multiple times for a symbol to
// compute its would-be final value in each relaxation pass.
template<int size>
bool
Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
typename Sized_symbol<size>::Value_type
Symbol_table::compute_final_value(
const Sized_symbol<size>* sym,
Compute_final_value_status* pstatus) const
{
typedef typename Sized_symbol<size>::Value_type Value_type;
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
// The default version of a symbol may appear twice in the symbol
// table. We only need to finalize it once.
if (sym->has_symtab_index())
return false;
if (!sym->in_reg())
{
gold_assert(!sym->has_symtab_index());
sym->set_symtab_index(-1U);
gold_assert(sym->dynsym_index() == -1U);
return false;
}
Value_type value;
switch (sym->source())
@ -2392,9 +2379,8 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
&& shndx != elfcpp::SHN_ABS
&& !Symbol::is_common_shndx(shndx))
{
gold_error(_("%s: unsupported symbol section 0x%x"),
sym->demangled_name().c_str(), shndx);
shndx = elfcpp::SHN_UNDEF;
*pstatus = CFVS_UNSUPPORTED_SYMBOL_SECTION;
return 0;
}
Object* symobj = sym->object();
@ -2435,12 +2421,12 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
if (os == NULL)
{
sym->set_symtab_index(-1U);
bool static_or_reloc = (parameters->doing_static_link() ||
parameters->options().relocatable());
gold_assert(static_or_reloc || sym->dynsym_index() == -1U);
return false;
*pstatus = CFVS_NO_OUTPUT_SECTION;
return 0;
}
if (secoff64 == -1ULL)
@ -2513,6 +2499,57 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
gold_unreachable();
}
*pstatus = CFVS_OK;
return value;
}
// Finalize the symbol SYM. This returns true if the symbol should be
// added to the symbol table, false otherwise.
template<int size>
bool
Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
{
typedef typename Sized_symbol<size>::Value_type Value_type;
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
// The default version of a symbol may appear twice in the symbol
// table. We only need to finalize it once.
if (sym->has_symtab_index())
return false;
if (!sym->in_reg())
{
gold_assert(!sym->has_symtab_index());
sym->set_symtab_index(-1U);
gold_assert(sym->dynsym_index() == -1U);
return false;
}
// Compute final symbol value.
Compute_final_value_status status;
Value_type value = this->compute_final_value(sym, &status);
switch (status)
{
case CFVS_OK:
break;
case CFVS_UNSUPPORTED_SYMBOL_SECTION:
{
bool is_ordinary;
unsigned int shndx = sym->shndx(&is_ordinary);
gold_error(_("%s: unsupported symbol section 0x%x"),
sym->demangled_name().c_str(), shndx);
}
break;
case CFVS_NO_OUTPUT_SECTION:
sym->set_symtab_index(-1U);
return false;
default:
gold_unreachable();
}
sym->set_value(value);
if (parameters->options().strip_all()

View File

@ -1377,6 +1377,26 @@ class Symbol_table
finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount,
Stringpool* pool, unsigned int *plocal_symcount);
// Status code of Symbol_table::compute_final_value.
enum Compute_final_value_status
{
// No error.
CFVS_OK,
// Unspported symbol section.
CFVS_UNSUPPORTED_SYMBOL_SECTION,
// No output section.
CFVS_NO_OUTPUT_SECTION
};
// Compute the final value of SYM and store status in location PSTATUS.
// During relaxation, this may be called multiple times for a symbol to
// compute its would-be final value in each relaxation pass.
template<int size>
typename Sized_symbol<size>::Value_type
compute_final_value(const Sized_symbol<size>* sym,
Compute_final_value_status* pstatus) const;
// Write out the global symbols.
void
write_globals(const Stringpool*, const Stringpool*,

View File

@ -23,6 +23,7 @@
#include "gold.h"
#include "target.h"
#include "dynobj.h"
#include "output.h"
#include "elfcpp.h"
namespace gold
@ -136,6 +137,13 @@ Target::do_make_elf_object(const std::string& name, Input_file* input_file,
}
#endif
Output_section*
Target::do_make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
{
return new Output_section(name, type, flags);
}
// Default conversion for -fsplit-stack is to give an error.
void

View File

@ -242,6 +242,12 @@ class Target
off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
{ return this->do_make_elf_object(name, input_file, offset, ehdr); }
// Make an output section.
Output_section*
make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
{ return this->do_make_output_section(name, type, flags); }
// Return true if target wants to perform relaxation.
bool
may_relax() const
@ -255,14 +261,15 @@ class Target
// Perform a relaxation pass. Return true if layout may be changed.
bool
relax(int pass)
relax(int pass, const Input_objects* input_objects, Symbol_table* symtab,
Layout* layout)
{
// Run the dummy relaxation pass twice if relaxation debugging is enabled.
if (is_debugging_enabled(DEBUG_RELAXATION))
return pass < 2;
return this->do_relax(pass);
}
return this->do_relax(pass, input_objects, symtab, layout);
}
protected:
// This struct holds the constant information for a child class. We
@ -386,6 +393,11 @@ class Target
off_t offset, const elfcpp::Ehdr<64, true>& ehdr);
#endif
// Virtual functions which may be overriden by the child class.
virtual Output_section*
do_make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags);
// Virtual function which may be overriden by the child class.
virtual bool
do_may_relax() const
@ -393,7 +405,7 @@ class Target
// Virtual function which may be overriden by the child class.
virtual bool
do_relax(int)
do_relax(int, const Input_objects*, Symbol_table*, Layout*)
{ return false; }
// A function for targets to call. Return whether BYTES/LEN matches