mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-01-18 23:13:46 +00:00
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:
parent
d446d6c4f7
commit
c0a6286595
102
gold/ChangeLog
102
gold/ChangeLog
@ -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.
|
||||
|
@ -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*>(¶meters->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
|
||||
|
@ -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&);
|
||||
|
26
gold/merge.h
26
gold/merge.h
@ -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*
|
||||
|
@ -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);
|
||||
|
@ -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*,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
349
gold/output.cc
349
gold/output.cc
@ -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.
|
||||
|
225
gold/output.h
225
gold/output.h
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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*,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user