2010-05-23 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_input_section::do_output_offset): Use convert_types instead of a cast. (Target_arm::apply_cortex_a8_workaround): Rewrite a conditional branch with a direct branch, not a conditional branch, to a stub. * merge.cc (Output_merge_base::record_input_section): New method defintion. (Output_merge_data::do_add_input_section): Record input section if keeps-input-sections flag is set. (Output_merge_string::do_add_input_section): Ditto. * merge.h (Output_merge_base::Output_merge_base): Initialize new data members KEEPS_INPUT_SECTIONS_, FIRST_RELOBJ_, FIRST_SHNDX_ and INPUT_SECTIONS_. (Output_merge_base::keeps_input_sections, Output_merge_base::set_keeps_input_sections, Output_merge_base::first_relobj, Output_merge_base::first_shndx): New method definitions. (Output_merge_base::Input_sections): New type declaration. (Output_merge_base::input_sections_begin, Output_merge_base::input_sections_end, Output_merge_base::do_set_keeps_input_sections): New method definitions. (Output_merge_base::bool keeps_input_sections_, Output_merge_base::first_relobj_, Output_merge_base::first_shndx_, Output_merge_base::input_sections_): New data members. (Output_merge_data::do_set_keeps_input_sections): New method defintion. (Output_merge_string::do_set_keeps_input_sections): Ditto. * output.cc (Output_section::Input_section::relobj): Move method defintion from class declaration to here and handle merge sections. (Output_section::Input_section::shndx): Ditto. (Output_section::Output_section): Remove initializations of removed data members and initialize new data member LOOKUP_MAPS_. (Output_section::add_input_section): Set keeps-input-sections flag for a newly created merge output section as appropriate. Adjust code to use Output_section_lookup_maps class. (Output_section::add_relaxed_input_section): Adjst code for lookup maps code refactoring. (Output_section::add_merge_input_section): Add a new parameter KEEPS_INPUT_SECTION. Adjust code to use Output_section_lookup_maps class. If adding input section to a newly created merge output section fails, remove the new merge section. (Output_section::convert_input_sections_in_list_to_relaxed_input_sections): Adjust code for use of the Output_section_lookup_maps class. (Output_section::find_merge_section): Ditto. (Output_section::build_lookup_maps): New method defintion. (Output_section::find_relaxed_input_section): Adjust code to use Output_section_lookup_maps class. (Output_section::get_input_sections): Export merge sections. Adjust code to use Output_section_lookup_maps class. (Output_section:::add_script_input_section): Adjust code to use Output_section_lookup_maps class. Update lookup maps for merge sections also. (Output_section::discard_states): Use Output_section_lookup_maps. (Output_section::restore_states): Same. * output.h (Merge_section_properties): Move class defintion out of Output_section. (Output_section_lookup_maps): New class. (Output_section::Input_section::is_merge_section): New method defintion. (Output_section::Input_section::relobj): Move defintion out of class defintion. Declare method only. (Output_section::Input_section::shndx): Ditto. (Output_section::Input_section::output_merge_base): New method defintion. (Output_section::Input_section::u2_.pomb): New union field. (Output_section::Merge_section_by_properties_map, Output_section::Output_section_data_by_input_section_map, Output_section::Ouptut_relaxed_input_section_by_input_section_map): Remove types. (Output_section::add_merge_input_section): Add new parameter KEEPS_INPUT_SECTIONS. (Output_section::build_lookup_maps): New method declaration. (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_): Remove data members. (Output_section::lookup_maps_): New data member.
This commit is contained in:
parent
f434ba0309
commit
0439c7962a
6 changed files with 564 additions and 182 deletions
|
@ -1,3 +1,82 @@
|
||||||
|
2010-05-23 Doug Kwan <dougkwan@google.com>
|
||||||
|
|
||||||
|
* arm.cc (Arm_input_section::do_output_offset): Use convert_types
|
||||||
|
instead of a cast.
|
||||||
|
(Target_arm::apply_cortex_a8_workaround): Rewrite a conditional branch
|
||||||
|
with a direct branch, not a conditional branch, to a stub.
|
||||||
|
* merge.cc (Output_merge_base::record_input_section): New method
|
||||||
|
defintion.
|
||||||
|
(Output_merge_data::do_add_input_section): Record input section if
|
||||||
|
keeps-input-sections flag is set.
|
||||||
|
(Output_merge_string::do_add_input_section): Ditto.
|
||||||
|
* merge.h (Output_merge_base::Output_merge_base): Initialize new data
|
||||||
|
members KEEPS_INPUT_SECTIONS_, FIRST_RELOBJ_, FIRST_SHNDX_ and
|
||||||
|
INPUT_SECTIONS_.
|
||||||
|
(Output_merge_base::keeps_input_sections,
|
||||||
|
Output_merge_base::set_keeps_input_sections,
|
||||||
|
Output_merge_base::first_relobj, Output_merge_base::first_shndx): New
|
||||||
|
method definitions.
|
||||||
|
(Output_merge_base::Input_sections): New type declaration.
|
||||||
|
(Output_merge_base::input_sections_begin,
|
||||||
|
Output_merge_base::input_sections_end,
|
||||||
|
Output_merge_base::do_set_keeps_input_sections): New method definitions.
|
||||||
|
(Output_merge_base::bool keeps_input_sections_,
|
||||||
|
Output_merge_base::first_relobj_, Output_merge_base::first_shndx_,
|
||||||
|
Output_merge_base::input_sections_): New data members.
|
||||||
|
(Output_merge_data::do_set_keeps_input_sections): New method
|
||||||
|
defintion.
|
||||||
|
(Output_merge_string::do_set_keeps_input_sections): Ditto.
|
||||||
|
* output.cc (Output_section::Input_section::relobj): Move method
|
||||||
|
defintion from class declaration to here and handle merge sections.
|
||||||
|
(Output_section::Input_section::shndx): Ditto.
|
||||||
|
(Output_section::Output_section): Remove initializations of removed
|
||||||
|
data members and initialize new data member LOOKUP_MAPS_.
|
||||||
|
(Output_section::add_input_section): Set keeps-input-sections flag
|
||||||
|
for a newly created merge output section as appropriate. Adjust code
|
||||||
|
to use Output_section_lookup_maps class.
|
||||||
|
(Output_section::add_relaxed_input_section): Adjst code for lookup
|
||||||
|
maps code refactoring.
|
||||||
|
(Output_section::add_merge_input_section): Add a new parameter
|
||||||
|
KEEPS_INPUT_SECTION. Adjust code to use Output_section_lookup_maps
|
||||||
|
class. If adding input section to a newly created merge output
|
||||||
|
section fails, remove the new merge section.
|
||||||
|
(Output_section::convert_input_sections_in_list_to_relaxed_input_sections):
|
||||||
|
Adjust code for use of the Output_section_lookup_maps class.
|
||||||
|
(Output_section::find_merge_section): Ditto.
|
||||||
|
(Output_section::build_lookup_maps): New method defintion.
|
||||||
|
(Output_section::find_relaxed_input_section): Adjust code to use
|
||||||
|
Output_section_lookup_maps class.
|
||||||
|
(Output_section::get_input_sections): Export merge sections. Adjust
|
||||||
|
code to use Output_section_lookup_maps class.
|
||||||
|
(Output_section:::add_script_input_section): Adjust code to use
|
||||||
|
Output_section_lookup_maps class. Update lookup maps for merge
|
||||||
|
sections also.
|
||||||
|
(Output_section::discard_states): Use Output_section_lookup_maps.
|
||||||
|
(Output_section::restore_states): Same.
|
||||||
|
* output.h (Merge_section_properties): Move class defintion out of
|
||||||
|
Output_section.
|
||||||
|
(Output_section_lookup_maps): New class.
|
||||||
|
(Output_section::Input_section::is_merge_section): New method
|
||||||
|
defintion.
|
||||||
|
(Output_section::Input_section::relobj): Move defintion out of class
|
||||||
|
defintion. Declare method only.
|
||||||
|
(Output_section::Input_section::shndx): Ditto.
|
||||||
|
(Output_section::Input_section::output_merge_base): New method defintion.
|
||||||
|
(Output_section::Input_section::u2_.pomb): New union field.
|
||||||
|
(Output_section::Merge_section_by_properties_map,
|
||||||
|
Output_section::Output_section_data_by_input_section_map,
|
||||||
|
Output_section::Ouptut_relaxed_input_section_by_input_section_map):
|
||||||
|
Remove types.
|
||||||
|
(Output_section::add_merge_input_section): Add new parameter
|
||||||
|
KEEPS_INPUT_SECTIONS.
|
||||||
|
(Output_section::build_lookup_maps): New method declaration.
|
||||||
|
(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_): Remove data
|
||||||
|
members.
|
||||||
|
(Output_section::lookup_maps_): New data member.
|
||||||
|
|
||||||
2010-05-21 Doug Kwan <dougkwan@google.com>
|
2010-05-21 Doug Kwan <dougkwan@google.com>
|
||||||
|
|
||||||
PR gold/11619
|
PR gold/11619
|
||||||
|
|
15
gold/arm.cc
15
gold/arm.cc
|
@ -1202,7 +1202,8 @@ class Arm_input_section : public Output_relaxed_input_section
|
||||||
if ((object == this->relobj())
|
if ((object == this->relobj())
|
||||||
&& (shndx == this->shndx())
|
&& (shndx == this->shndx())
|
||||||
&& (offset >= 0)
|
&& (offset >= 0)
|
||||||
&& (offset <= static_cast<section_offset_type>(this->original_size_)))
|
&& (offset <=
|
||||||
|
convert_types<section_offset_type, uint32_t>(this->original_size_)))
|
||||||
{
|
{
|
||||||
*poutput = offset;
|
*poutput = offset;
|
||||||
return true;
|
return true;
|
||||||
|
@ -10898,13 +10899,11 @@ Target_arm<big_endian>::apply_cortex_a8_workaround(
|
||||||
switch (stub->stub_template()->type())
|
switch (stub->stub_template()->type())
|
||||||
{
|
{
|
||||||
case arm_stub_a8_veneer_b_cond:
|
case arm_stub_a8_veneer_b_cond:
|
||||||
gold_assert(!utils::has_overflow<21>(branch_offset));
|
// For a conditional branch, we re-write it to be a uncondition
|
||||||
upper_insn = RelocFuncs::thumb32_cond_branch_upper(upper_insn,
|
// branch to the stub. We use the THUMB-2 encoding here.
|
||||||
branch_offset);
|
upper_insn = 0xf000U;
|
||||||
lower_insn = RelocFuncs::thumb32_cond_branch_lower(lower_insn,
|
lower_insn = 0xb800U;
|
||||||
branch_offset);
|
// Fall through
|
||||||
break;
|
|
||||||
|
|
||||||
case arm_stub_a8_veneer_b:
|
case arm_stub_a8_veneer_b:
|
||||||
case arm_stub_a8_veneer_bl:
|
case arm_stub_a8_veneer_bl:
|
||||||
case arm_stub_a8_veneer_blx:
|
case arm_stub_a8_veneer_blx:
|
||||||
|
|
|
@ -304,6 +304,26 @@ Output_merge_base::do_is_merge_section_for(const Relobj* object,
|
||||||
return this->merge_map_.is_merge_section_for(object, shndx);
|
return this->merge_map_.is_merge_section_for(object, shndx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record a merged input section for script processing.
|
||||||
|
|
||||||
|
void
|
||||||
|
Output_merge_base::record_input_section(Relobj* relobj, unsigned int shndx)
|
||||||
|
{
|
||||||
|
gold_assert(this->keeps_input_sections_ && relobj != NULL);
|
||||||
|
// If this is the first input section, record it. We need do this because
|
||||||
|
// this->input_sections_ is unordered.
|
||||||
|
if (this->first_relobj_ == NULL)
|
||||||
|
{
|
||||||
|
this->first_relobj_ = relobj;
|
||||||
|
this->first_shndx_ = shndx;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Input_sections::iterator, bool> result =
|
||||||
|
this->input_sections_.insert(Section_id(relobj, shndx));
|
||||||
|
// We should insert a merge section once only.
|
||||||
|
gold_assert(result.second);
|
||||||
|
}
|
||||||
|
|
||||||
// Class Output_merge_data.
|
// Class Output_merge_data.
|
||||||
|
|
||||||
// Compute the hash code for a fixed-size constant.
|
// Compute the hash code for a fixed-size constant.
|
||||||
|
@ -414,6 +434,10 @@ Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx)
|
||||||
this->add_mapping(object, shndx, i, entsize, k);
|
this->add_mapping(object, shndx, i, entsize, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For script processing, we keep the input sections.
|
||||||
|
if (this->keeps_input_sections())
|
||||||
|
record_input_section(object, shndx);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,6 +541,10 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
|
||||||
|
|
||||||
this->input_count_ += count;
|
this->input_count_ += count;
|
||||||
|
|
||||||
|
// For script processing, we keep the input sections.
|
||||||
|
if (this->keeps_input_sections())
|
||||||
|
record_input_section(object, shndx);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
84
gold/merge.h
84
gold/merge.h
|
@ -216,7 +216,9 @@ class Output_merge_base : public Output_section_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Output_merge_base(uint64_t entsize, uint64_t addralign)
|
Output_merge_base(uint64_t entsize, uint64_t addralign)
|
||||||
: Output_section_data(addralign), merge_map_(), entsize_(entsize)
|
: Output_section_data(addralign), merge_map_(), entsize_(entsize),
|
||||||
|
keeps_input_sections_(false), first_relobj_(NULL), first_shndx_(-1),
|
||||||
|
input_sections_()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// Return the entry size.
|
// Return the entry size.
|
||||||
|
@ -230,6 +232,52 @@ class Output_merge_base : public Output_section_data
|
||||||
is_string()
|
is_string()
|
||||||
{ return this->do_is_string(); }
|
{ return this->do_is_string(); }
|
||||||
|
|
||||||
|
// Whether this keeps input sections.
|
||||||
|
bool
|
||||||
|
keeps_input_sections() const
|
||||||
|
{ return this->keeps_input_sections_; }
|
||||||
|
|
||||||
|
// Set the keeps-input-sections flag. This is virtual so that sub-classes
|
||||||
|
// can perform additional checks.
|
||||||
|
void
|
||||||
|
set_keeps_input_sections()
|
||||||
|
{ this->do_set_keeps_input_sections(); }
|
||||||
|
|
||||||
|
// Return the object of the first merged input section. This used
|
||||||
|
// for script processing. This is NULL if merge section is empty.
|
||||||
|
Relobj*
|
||||||
|
first_relobj() const
|
||||||
|
{ return this->first_relobj_; }
|
||||||
|
|
||||||
|
// Return the section index of the first merged input section. This
|
||||||
|
// is used for script processing. This is valid only if merge section
|
||||||
|
// is not valid.
|
||||||
|
unsigned int
|
||||||
|
first_shndx() const
|
||||||
|
{
|
||||||
|
gold_assert(this->first_relobj_ != NULL);
|
||||||
|
return this->first_shndx_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set of merged input sections.
|
||||||
|
typedef Unordered_set<Section_id, Section_id_hash> Input_sections;
|
||||||
|
|
||||||
|
// Beginning of merged input sections.
|
||||||
|
Input_sections::const_iterator
|
||||||
|
input_sections_begin() const
|
||||||
|
{
|
||||||
|
gold_assert(this->keeps_input_sections_);
|
||||||
|
return this->input_sections_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beginning of merged input sections.
|
||||||
|
Input_sections::const_iterator
|
||||||
|
input_sections_end() const
|
||||||
|
{
|
||||||
|
gold_assert(this->keeps_input_sections_);
|
||||||
|
return this->input_sections_.end();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Return the output offset for an input offset.
|
// Return the output offset for an input offset.
|
||||||
bool
|
bool
|
||||||
|
@ -257,6 +305,15 @@ class Output_merge_base : public Output_section_data
|
||||||
do_is_string()
|
do_is_string()
|
||||||
{ return false; }
|
{ return false; }
|
||||||
|
|
||||||
|
// This may be overridden by the child class.
|
||||||
|
virtual void
|
||||||
|
do_set_keeps_input_sections()
|
||||||
|
{ this->keeps_input_sections_ = true; }
|
||||||
|
|
||||||
|
// Record the merged input section for script processing.
|
||||||
|
void
|
||||||
|
record_input_section(Relobj* relobj, unsigned int shndx);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// A mapping from input object/section/offset to offset in output
|
// A mapping from input object/section/offset to offset in output
|
||||||
// section.
|
// section.
|
||||||
|
@ -264,6 +321,15 @@ class Output_merge_base : public Output_section_data
|
||||||
// The entry size. For fixed-size constants, this is the size of
|
// The entry size. For fixed-size constants, this is the size of
|
||||||
// the constants. For strings, this is the size of a character.
|
// the constants. For strings, this is the size of a character.
|
||||||
uint64_t entsize_;
|
uint64_t entsize_;
|
||||||
|
// Whether we keep input sections.
|
||||||
|
bool keeps_input_sections_;
|
||||||
|
// Object of the first merged input section. We use this for script
|
||||||
|
// processing.
|
||||||
|
Relobj* first_relobj_;
|
||||||
|
// Section index of the first merged input section.
|
||||||
|
unsigned int first_shndx_;
|
||||||
|
// Input sections. We only keep them is keeps_input_sections_ is true.
|
||||||
|
Input_sections input_sections_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle SHF_MERGE sections with fixed-size constant data.
|
// Handle SHF_MERGE sections with fixed-size constant data.
|
||||||
|
@ -303,6 +369,14 @@ class Output_merge_data : public Output_merge_base
|
||||||
void
|
void
|
||||||
do_print_merge_stats(const char* section_name);
|
do_print_merge_stats(const char* section_name);
|
||||||
|
|
||||||
|
// Set keeps-input-sections flag.
|
||||||
|
void
|
||||||
|
do_set_keeps_input_sections()
|
||||||
|
{
|
||||||
|
gold_assert(this->input_count_ == 0);
|
||||||
|
Output_merge_base::do_set_keeps_input_sections();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// We build a hash table of the fixed-size constants. Each constant
|
// We build a hash table of the fixed-size constants. Each constant
|
||||||
// is stored as a pointer into the section data we are accumulating.
|
// is stored as a pointer into the section data we are accumulating.
|
||||||
|
@ -440,6 +514,14 @@ class Output_merge_string : public Output_merge_base
|
||||||
do_is_string()
|
do_is_string()
|
||||||
{ return true; }
|
{ return true; }
|
||||||
|
|
||||||
|
// Set keeps-input-sections flag.
|
||||||
|
void
|
||||||
|
do_set_keeps_input_sections()
|
||||||
|
{
|
||||||
|
gold_assert(this->input_count_ == 0);
|
||||||
|
Output_merge_base::do_set_keeps_input_sections();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The name of the string type, for stats.
|
// The name of the string type, for stats.
|
||||||
const char*
|
const char*
|
||||||
|
|
226
gold/output.cc
226
gold/output.cc
|
@ -1749,6 +1749,42 @@ Output_section::Input_section::data_size() const
|
||||||
return this->u2_.posd->data_size();
|
return this->u2_.posd->data_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the object for an input section.
|
||||||
|
|
||||||
|
Relobj*
|
||||||
|
Output_section::Input_section::relobj() const
|
||||||
|
{
|
||||||
|
if (this->is_input_section())
|
||||||
|
return this->u2_.object;
|
||||||
|
else if (this->is_merge_section())
|
||||||
|
{
|
||||||
|
gold_assert(this->u2_.pomb->first_relobj() != NULL);
|
||||||
|
return this->u2_.pomb->first_relobj();
|
||||||
|
}
|
||||||
|
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
|
||||||
|
Output_section::Input_section::shndx() const
|
||||||
|
{
|
||||||
|
if (this->is_input_section())
|
||||||
|
return this->shndx_;
|
||||||
|
else if (this->is_merge_section())
|
||||||
|
{
|
||||||
|
gold_assert(this->u2_.pomb->first_relobj() != NULL);
|
||||||
|
return this->u2_.pomb->first_shndx();
|
||||||
|
}
|
||||||
|
else if (this->is_relaxed_input_section())
|
||||||
|
return this->u2_.poris->shndx();
|
||||||
|
else
|
||||||
|
gold_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
// Set the address and file offset.
|
// Set the address and file offset.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1914,10 +1950,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
||||||
is_noload_(false),
|
is_noload_(false),
|
||||||
tls_offset_(0),
|
tls_offset_(0),
|
||||||
checkpoint_(NULL),
|
checkpoint_(NULL),
|
||||||
merge_section_map_(),
|
lookup_maps_(new Output_section_lookup_maps)
|
||||||
merge_section_by_properties_map_(),
|
|
||||||
relaxed_input_section_map_(),
|
|
||||||
is_relaxed_input_section_map_valid_(true)
|
|
||||||
{
|
{
|
||||||
// An unallocated section has no address. Forcing this means that
|
// An unallocated section has no address. Forcing this means that
|
||||||
// we don't need special treatment for symbols defined in debug
|
// we don't need special treatment for symbols defined in debug
|
||||||
|
@ -2001,8 +2034,12 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
|
||||||
&& reloc_shndx == 0
|
&& reloc_shndx == 0
|
||||||
&& shdr.get_sh_size() > 0)
|
&& shdr.get_sh_size() > 0)
|
||||||
{
|
{
|
||||||
if (this->add_merge_input_section(object, shndx, sh_flags,
|
// Keep information about merged input sections for rebuilding fast
|
||||||
entsize, addralign))
|
// lookup maps if we have sections-script or we do relaxation.
|
||||||
|
bool keeps_input_sections =
|
||||||
|
have_sections_script || parameters->target().may_relax();
|
||||||
|
if (this->add_merge_input_section(object, shndx, sh_flags, entsize,
|
||||||
|
addralign, keeps_input_sections))
|
||||||
{
|
{
|
||||||
// Tell the relocation routines that they need to call the
|
// Tell the relocation routines that they need to call the
|
||||||
// output_offset method to determine the final address.
|
// output_offset method to determine the final address.
|
||||||
|
@ -2092,11 +2129,9 @@ Output_section::add_relaxed_input_section(Output_relaxed_input_section* poris)
|
||||||
{
|
{
|
||||||
Input_section inp(poris);
|
Input_section inp(poris);
|
||||||
this->add_output_section_data(&inp);
|
this->add_output_section_data(&inp);
|
||||||
if (this->is_relaxed_input_section_map_valid_)
|
if (this->lookup_maps_->is_valid())
|
||||||
{
|
this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
|
||||||
Const_section_id csid(poris->relobj(), poris->shndx());
|
poris->shndx(), poris);
|
||||||
this->relaxed_input_section_map_[csid] = poris;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For a relaxed section, we use the current data size. Linker scripts
|
// For a relaxed section, we use the current data size. Linker scripts
|
||||||
// get all the input sections, including relaxed one from an output
|
// get all the input sections, including relaxed one from an output
|
||||||
|
@ -2142,7 +2177,8 @@ Output_section::add_output_merge_section(Output_section_data* posd,
|
||||||
bool
|
bool
|
||||||
Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
|
Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
|
||||||
uint64_t flags, uint64_t entsize,
|
uint64_t flags, uint64_t entsize,
|
||||||
uint64_t addralign)
|
uint64_t addralign,
|
||||||
|
bool keeps_input_sections)
|
||||||
{
|
{
|
||||||
bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
|
bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
|
||||||
|
|
||||||
|
@ -2155,13 +2191,15 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
|
||||||
gold_assert(this->checkpoint_ == NULL);
|
gold_assert(this->checkpoint_ == NULL);
|
||||||
|
|
||||||
// Look up merge sections by required properties.
|
// Look up merge sections by required properties.
|
||||||
Output_merge_base* pomb;
|
// Currently, we only invalidate the lookup maps in script processing
|
||||||
|
// and relaxation. We should not have done either when we reach here.
|
||||||
|
// So we assume that the lookup maps are valid to simply code.
|
||||||
|
gold_assert(this->lookup_maps_->is_valid());
|
||||||
Merge_section_properties msp(is_string, entsize, addralign);
|
Merge_section_properties msp(is_string, entsize, addralign);
|
||||||
Merge_section_by_properties_map::const_iterator p =
|
Output_merge_base* pomb = this->lookup_maps_->find_merge_section(msp);
|
||||||
this->merge_section_by_properties_map_.find(msp);
|
bool is_new = false;
|
||||||
if (p != this->merge_section_by_properties_map_.end())
|
if (pomb != NULL)
|
||||||
{
|
{
|
||||||
pomb = p->second;
|
|
||||||
gold_assert(pomb->is_string() == is_string
|
gold_assert(pomb->is_string() == is_string
|
||||||
&& pomb->entsize() == entsize
|
&& pomb->entsize() == entsize
|
||||||
&& pomb->addralign() == addralign);
|
&& pomb->addralign() == addralign);
|
||||||
|
@ -2188,22 +2226,36 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add new merge section to this output section and link merge
|
// If we need to do script processing or relaxation, we need to keep
|
||||||
// section properties to new merge section in map.
|
// the original input sections to rebuild the fast lookup maps.
|
||||||
this->add_output_merge_section(pomb, is_string, entsize);
|
if (keeps_input_sections)
|
||||||
this->merge_section_by_properties_map_[msp] = pomb;
|
pomb->set_keeps_input_sections();
|
||||||
|
is_new = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pomb->add_input_section(object, shndx))
|
if (pomb->add_input_section(object, shndx))
|
||||||
{
|
{
|
||||||
|
// Add new merge section to this output section and link merge
|
||||||
|
// section properties to new merge section in map.
|
||||||
|
if (is_new)
|
||||||
|
{
|
||||||
|
this->add_output_merge_section(pomb, is_string, entsize);
|
||||||
|
this->lookup_maps_->add_merge_section(msp, pomb);
|
||||||
|
}
|
||||||
|
|
||||||
// Add input section to new merge section and link input section to new
|
// Add input section to new merge section and link input section to new
|
||||||
// merge section in map.
|
// merge section in map.
|
||||||
Const_section_id csid(object, shndx);
|
this->lookup_maps_->add_merge_input_section(object, shndx, pomb);
|
||||||
this->merge_section_map_[csid] = pomb;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
{
|
||||||
|
// If add_input_section failed, delete new merge section to avoid
|
||||||
|
// exporting empty merge sections in Output_section::get_input_section.
|
||||||
|
if (is_new)
|
||||||
|
delete pomb;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a relaxation map to speed up relaxation of existing input sections.
|
// Build a relaxation map to speed up relaxation of existing input sections.
|
||||||
|
@ -2298,12 +2350,12 @@ Output_section::convert_input_sections_to_relaxed_sections(
|
||||||
&this->input_sections_);
|
&this->input_sections_);
|
||||||
|
|
||||||
// Update fast look-up map.
|
// Update fast look-up map.
|
||||||
if (this->is_relaxed_input_section_map_valid_)
|
if (this->lookup_maps_->is_valid())
|
||||||
for (size_t i = 0; i < relaxed_sections.size(); ++i)
|
for (size_t i = 0; i < relaxed_sections.size(); ++i)
|
||||||
{
|
{
|
||||||
Output_relaxed_input_section* poris = relaxed_sections[i];
|
Output_relaxed_input_section* poris = relaxed_sections[i];
|
||||||
Const_section_id csid(poris->relobj(), poris->shndx());
|
this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
|
||||||
this->relaxed_input_section_map_[csid] = poris;
|
poris->shndx(), poris);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2348,17 +2400,47 @@ Output_section_data*
|
||||||
Output_section::find_merge_section(const Relobj* object,
|
Output_section::find_merge_section(const Relobj* object,
|
||||||
unsigned int shndx) const
|
unsigned int shndx) const
|
||||||
{
|
{
|
||||||
Const_section_id csid(object, shndx);
|
if (!this->lookup_maps_->is_valid())
|
||||||
Output_section_data_by_input_section_map::const_iterator p =
|
this->build_lookup_maps();
|
||||||
this->merge_section_map_.find(csid);
|
return this->lookup_maps_->find_merge_section(object, shndx);
|
||||||
if (p != this->merge_section_map_.end())
|
}
|
||||||
|
|
||||||
|
// Build the lookup maps for merge and relaxed sections. This is needs
|
||||||
|
// to be declared as a const methods so that it is callable with a const
|
||||||
|
// Output_section pointer. The method only updates states of the maps.
|
||||||
|
|
||||||
|
void
|
||||||
|
Output_section::build_lookup_maps() const
|
||||||
|
{
|
||||||
|
this->lookup_maps_->clear();
|
||||||
|
for (Input_section_list::const_iterator p = this->input_sections_.begin();
|
||||||
|
p != this->input_sections_.end();
|
||||||
|
++p)
|
||||||
{
|
{
|
||||||
Output_section_data* posd = p->second;
|
if (p->is_merge_section())
|
||||||
gold_assert(posd->is_merge_section_for(object, shndx));
|
{
|
||||||
return posd;
|
Output_merge_base* pomb = p->output_merge_base();
|
||||||
|
Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
|
||||||
|
pomb->addralign());
|
||||||
|
this->lookup_maps_->add_merge_section(msp, pomb);
|
||||||
|
for (Output_merge_base::Input_sections::const_iterator is =
|
||||||
|
pomb->input_sections_begin();
|
||||||
|
is != pomb->input_sections_end();
|
||||||
|
++is)
|
||||||
|
{
|
||||||
|
const Const_section_id& csid = *is;
|
||||||
|
this->lookup_maps_->add_merge_input_section(csid.first,
|
||||||
|
csid.second, pomb);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (p->is_relaxed_input_section())
|
||||||
|
{
|
||||||
|
Output_relaxed_input_section* poris = p->relaxed_input_section();
|
||||||
|
this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
|
||||||
|
poris->shndx(), poris);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find an relaxed input section corresponding to an input section
|
// Find an relaxed input section corresponding to an input section
|
||||||
|
@ -2368,31 +2450,9 @@ const Output_relaxed_input_section*
|
||||||
Output_section::find_relaxed_input_section(const Relobj* object,
|
Output_section::find_relaxed_input_section(const Relobj* object,
|
||||||
unsigned int shndx) const
|
unsigned int shndx) const
|
||||||
{
|
{
|
||||||
// Be careful that the map may not be valid due to input section export
|
if (!this->lookup_maps_->is_valid())
|
||||||
// to scripts or a check-point restore.
|
this->build_lookup_maps();
|
||||||
if (!this->is_relaxed_input_section_map_valid_)
|
return this->lookup_maps_->find_relaxed_input_section(object, shndx);
|
||||||
{
|
|
||||||
// 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())
|
|
||||||
{
|
|
||||||
Const_section_id csid(p->relobj(), p->shndx());
|
|
||||||
this->relaxed_input_section_map_[csid] =
|
|
||||||
p->relaxed_input_section();
|
|
||||||
}
|
|
||||||
this->is_relaxed_input_section_map_valid_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Const_section_id csid(object, shndx);
|
|
||||||
Output_relaxed_input_section_by_input_section_map::const_iterator p =
|
|
||||||
this->relaxed_input_section_map_.find(csid);
|
|
||||||
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
|
// Given an address OFFSET relative to the start of input section
|
||||||
|
@ -3052,8 +3112,8 @@ Output_section::get_input_sections(
|
||||||
&& !this->checkpoint_->input_sections_saved())
|
&& !this->checkpoint_->input_sections_saved())
|
||||||
this->checkpoint_->save_input_sections();
|
this->checkpoint_->save_input_sections();
|
||||||
|
|
||||||
// Invalidate the relaxed input section map.
|
// Invalidate fast look-up maps.
|
||||||
this->is_relaxed_input_section_map_valid_ = false;
|
this->lookup_maps_->invalidate();
|
||||||
|
|
||||||
uint64_t orig_address = address;
|
uint64_t orig_address = address;
|
||||||
|
|
||||||
|
@ -3064,7 +3124,9 @@ Output_section::get_input_sections(
|
||||||
p != this->input_sections_.end();
|
p != this->input_sections_.end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
if (p->is_input_section() || p->is_relaxed_input_section())
|
if (p->is_input_section()
|
||||||
|
|| p->is_relaxed_input_section()
|
||||||
|
|| p->is_merge_section())
|
||||||
input_sections->push_back(*p);
|
input_sections->push_back(*p);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3121,6 +3183,30 @@ Output_section::add_script_input_section(const Input_section& sis)
|
||||||
+ data_size);
|
+ data_size);
|
||||||
|
|
||||||
this->input_sections_.push_back(sis);
|
this->input_sections_.push_back(sis);
|
||||||
|
|
||||||
|
// Update fast lookup maps if necessary.
|
||||||
|
if (this->lookup_maps_->is_valid())
|
||||||
|
{
|
||||||
|
if (sis.is_merge_section())
|
||||||
|
{
|
||||||
|
Output_merge_base* pomb = sis.output_merge_base();
|
||||||
|
Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
|
||||||
|
pomb->addralign());
|
||||||
|
this->lookup_maps_->add_merge_section(msp, pomb);
|
||||||
|
for (Output_merge_base::Input_sections::const_iterator p =
|
||||||
|
pomb->input_sections_begin();
|
||||||
|
p != pomb->input_sections_end();
|
||||||
|
++p)
|
||||||
|
this->lookup_maps_->add_merge_input_section(p->first, p->second,
|
||||||
|
pomb);
|
||||||
|
}
|
||||||
|
else if (sis.is_relaxed_input_section())
|
||||||
|
{
|
||||||
|
Output_relaxed_input_section* poris = sis.relaxed_input_section();
|
||||||
|
this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
|
||||||
|
poris->shndx(), poris);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save states for relaxation.
|
// Save states for relaxation.
|
||||||
|
@ -3146,9 +3232,9 @@ Output_section::discard_states()
|
||||||
this->checkpoint_ = NULL;
|
this->checkpoint_ = NULL;
|
||||||
gold_assert(this->fills_.empty());
|
gold_assert(this->fills_.empty());
|
||||||
|
|
||||||
// Simply invalidate the relaxed input section map since we do not keep
|
// Simply invalidate the fast lookup maps since we do not keep
|
||||||
// track of it.
|
// track of them.
|
||||||
this->is_relaxed_input_section_map_valid_ = false;
|
this->lookup_maps_->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3180,9 +3266,9 @@ Output_section::restore_states()
|
||||||
this->attached_input_sections_are_sorted_ =
|
this->attached_input_sections_are_sorted_ =
|
||||||
checkpoint->attached_input_sections_are_sorted();
|
checkpoint->attached_input_sections_are_sorted();
|
||||||
|
|
||||||
// Simply invalidate the relaxed input section map since we do not keep
|
// Simply invalidate the fast lookup maps since we do not keep
|
||||||
// track of it.
|
// track of them.
|
||||||
this->is_relaxed_input_section_map_valid_ = false;
|
this->lookup_maps_->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the section offsets of input sections in this. This is required if
|
// Update the section offsets of input sections in this. This is required if
|
||||||
|
|
314
gold/output.h
314
gold/output.h
|
@ -2314,6 +2314,188 @@ class Output_relaxed_input_section : public Output_section_data_build
|
||||||
unsigned int shndx_;
|
unsigned int shndx_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class is used to speed up look up of special input sections in an
|
||||||
|
// Output_section.
|
||||||
|
|
||||||
|
class Output_section_lookup_maps
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Output_section_lookup_maps()
|
||||||
|
: is_valid_(true), merge_sections_by_properties_(),
|
||||||
|
merge_sections_by_id_(), relaxed_input_sections_by_id_()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Whether the maps are valid.
|
||||||
|
bool
|
||||||
|
is_valid() const
|
||||||
|
{ return this->is_valid_; }
|
||||||
|
|
||||||
|
// Invalidate the maps.
|
||||||
|
void
|
||||||
|
invalidate()
|
||||||
|
{ this->is_valid_ = false; }
|
||||||
|
|
||||||
|
// Clear the maps.
|
||||||
|
void
|
||||||
|
clear()
|
||||||
|
{
|
||||||
|
this->merge_sections_by_properties_.clear();
|
||||||
|
this->merge_sections_by_id_.clear();
|
||||||
|
this->relaxed_input_sections_by_id_.clear();
|
||||||
|
// A cleared map is valid.
|
||||||
|
this->is_valid_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a merge section by merge section properties. Return NULL if none
|
||||||
|
// is found.
|
||||||
|
Output_merge_base*
|
||||||
|
find_merge_section(const Merge_section_properties& msp) const
|
||||||
|
{
|
||||||
|
gold_assert(this->is_valid_);
|
||||||
|
Merge_sections_by_properties::const_iterator p =
|
||||||
|
this->merge_sections_by_properties_.find(msp);
|
||||||
|
return p != this->merge_sections_by_properties_.end() ? p->second : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a merge section by section ID of a merge input section. Return NULL
|
||||||
|
// if none is found.
|
||||||
|
Output_merge_base*
|
||||||
|
find_merge_section(const Object* object, unsigned int shndx) const
|
||||||
|
{
|
||||||
|
gold_assert(this->is_valid_);
|
||||||
|
Merge_sections_by_id::const_iterator p =
|
||||||
|
this->merge_sections_by_id_.find(Const_section_id(object, shndx));
|
||||||
|
return p != this->merge_sections_by_id_.end() ? p->second : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a merge section pointed by POMB with properties MSP.
|
||||||
|
void
|
||||||
|
add_merge_section(const Merge_section_properties& msp,
|
||||||
|
Output_merge_base* pomb)
|
||||||
|
{
|
||||||
|
std::pair<Merge_section_properties, Output_merge_base*> value(msp, pomb);
|
||||||
|
std::pair<Merge_sections_by_properties::iterator, bool> result =
|
||||||
|
this->merge_sections_by_properties_.insert(value);
|
||||||
|
gold_assert(value.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a mapping from a merged input section in OBJECT with index SHNDX
|
||||||
|
// to a merge output section pointed by POMB.
|
||||||
|
void
|
||||||
|
add_merge_input_section(const Object* object, unsigned int shndx,
|
||||||
|
Output_merge_base* pomb)
|
||||||
|
{
|
||||||
|
Const_section_id csid(object, shndx);
|
||||||
|
std::pair<Const_section_id, Output_merge_base*> value(csid, pomb);
|
||||||
|
std::pair<Merge_sections_by_id::iterator, bool> result =
|
||||||
|
this->merge_sections_by_id_.insert(value);
|
||||||
|
gold_assert(value.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a relaxed input section of OBJECT with index SHNDX.
|
||||||
|
Output_relaxed_input_section*
|
||||||
|
find_relaxed_input_section(const Object* object, unsigned int shndx) const
|
||||||
|
{
|
||||||
|
gold_assert(this->is_valid_);
|
||||||
|
Relaxed_input_sections_by_id::const_iterator p =
|
||||||
|
this->relaxed_input_sections_by_id_.find(Const_section_id(object, shndx));
|
||||||
|
return p != this->relaxed_input_sections_by_id_.end() ? p->second : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a relaxed input section pointed by POMB and whose original input
|
||||||
|
// section is in OBJECT with index SHNDX.
|
||||||
|
void
|
||||||
|
add_relaxed_input_section(const Relobj* relobj, unsigned int shndx,
|
||||||
|
Output_relaxed_input_section* poris)
|
||||||
|
{
|
||||||
|
Const_section_id csid(relobj, shndx);
|
||||||
|
std::pair<Const_section_id, Output_relaxed_input_section*>
|
||||||
|
value(csid, poris);
|
||||||
|
std::pair<Relaxed_input_sections_by_id::iterator, bool> result =
|
||||||
|
this->relaxed_input_sections_by_id_.insert(value);
|
||||||
|
gold_assert(value.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef Unordered_map<Const_section_id, Output_merge_base*,
|
||||||
|
Const_section_id_hash>
|
||||||
|
Merge_sections_by_id;
|
||||||
|
|
||||||
|
typedef Unordered_map<Merge_section_properties, Output_merge_base*,
|
||||||
|
Merge_section_properties::hash,
|
||||||
|
Merge_section_properties::equal_to>
|
||||||
|
Merge_sections_by_properties;
|
||||||
|
|
||||||
|
typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
|
||||||
|
Const_section_id_hash>
|
||||||
|
Relaxed_input_sections_by_id;
|
||||||
|
|
||||||
|
// Whether this is valid
|
||||||
|
bool is_valid_;
|
||||||
|
// Merge sections by merge section properties.
|
||||||
|
Merge_sections_by_properties merge_sections_by_properties_;
|
||||||
|
// Merge sections by section IDs.
|
||||||
|
Merge_sections_by_id merge_sections_by_id_;
|
||||||
|
// Relaxed sections by section IDs.
|
||||||
|
Relaxed_input_sections_by_id relaxed_input_sections_by_id_;
|
||||||
|
};
|
||||||
|
|
||||||
// An output section. We don't expect to have too many output
|
// An output section. We don't expect to have too many output
|
||||||
// sections, so we don't bother to do a template on the size.
|
// sections, so we don't bother to do a template on the size.
|
||||||
|
|
||||||
|
@ -2881,6 +3063,14 @@ class Output_section : public Output_data
|
||||||
&& this->addralign() == addralign);
|
&& this->addralign() == addralign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return whether this is a merge section for some input section.
|
||||||
|
bool
|
||||||
|
is_merge_section() const
|
||||||
|
{
|
||||||
|
return (this->shndx_ == MERGE_DATA_SECTION_CODE
|
||||||
|
|| this->shndx_ == MERGE_STRING_SECTION_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
// Return whether this is a relaxed input section.
|
// Return whether this is a relaxed input section.
|
||||||
bool
|
bool
|
||||||
is_relaxed_input_section() const
|
is_relaxed_input_section() const
|
||||||
|
@ -2895,27 +3085,11 @@ class Output_section : public Output_data
|
||||||
|
|
||||||
// Return the object for an input section.
|
// Return the object for an input section.
|
||||||
Relobj*
|
Relobj*
|
||||||
relobj() const
|
relobj() const;
|
||||||
{
|
|
||||||
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.
|
// Return the input section index for an input section.
|
||||||
unsigned int
|
unsigned int
|
||||||
shndx() const
|
shndx() const;
|
||||||
{
|
|
||||||
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
|
// For non-input-sections, return the associated Output_section_data
|
||||||
// object.
|
// object.
|
||||||
|
@ -2926,6 +3100,14 @@ class Output_section : public Output_data
|
||||||
return this->u2_.posd;
|
return this->u2_.posd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For a merge section, return the Output_merge_base pointer.
|
||||||
|
Output_merge_base*
|
||||||
|
output_merge_base() const
|
||||||
|
{
|
||||||
|
gold_assert(this->is_merge_section());
|
||||||
|
return this->u2_.pomb;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the Output_relaxed_input_section object.
|
// Return the Output_relaxed_input_section object.
|
||||||
Output_relaxed_input_section*
|
Output_relaxed_input_section*
|
||||||
relaxed_input_section() const
|
relaxed_input_section() const
|
||||||
|
@ -3048,6 +3230,7 @@ class Output_section : public Output_data
|
||||||
// For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
|
// For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
|
||||||
// MERGE_STRING_SECTION_CODE, the data.
|
// MERGE_STRING_SECTION_CODE, the data.
|
||||||
Output_section_data* posd;
|
Output_section_data* posd;
|
||||||
|
Output_merge_base* pomb;
|
||||||
// For RELAXED_INPUT_SECTION_CODE, the data.
|
// For RELAXED_INPUT_SECTION_CODE, the data.
|
||||||
Output_relaxed_input_section* poris;
|
Output_relaxed_input_section* poris;
|
||||||
} u2_;
|
} u2_;
|
||||||
|
@ -3389,78 +3572,6 @@ class Output_section : public Output_data
|
||||||
|
|
||||||
typedef std::vector<Fill> Fill_list;
|
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 Const_section_id to Output_section_data.
|
|
||||||
typedef Unordered_map<Const_section_id, Output_section_data*,
|
|
||||||
Const_section_id_hash>
|
|
||||||
Output_section_data_by_input_section_map;
|
|
||||||
|
|
||||||
// Map that link Const_section_id to Output_relaxed_input_section.
|
|
||||||
typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
|
|
||||||
Const_section_id_hash>
|
|
||||||
Output_relaxed_input_section_by_input_section_map;
|
|
||||||
|
|
||||||
// Map used during relaxation of existing sections. This map
|
// Map used during relaxation of existing sections. This map
|
||||||
// a section id an input section list index. We assume that
|
// a section id an input section list index. We assume that
|
||||||
// Input_section_list is a vector.
|
// Input_section_list is a vector.
|
||||||
|
@ -3471,10 +3582,12 @@ class Output_section : public Output_data
|
||||||
add_output_section_data(Input_section*);
|
add_output_section_data(Input_section*);
|
||||||
|
|
||||||
// Add an SHF_MERGE input section. Returns true if the section was
|
// Add an SHF_MERGE input section. Returns true if the section was
|
||||||
// handled.
|
// handled. If KEEPS_INPUT_SECTIONS is true, the output merge section
|
||||||
|
// stores information about the merged input sections.
|
||||||
bool
|
bool
|
||||||
add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
|
add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
|
||||||
uint64_t entsize, uint64_t addralign);
|
uint64_t entsize, uint64_t addralign,
|
||||||
|
bool keeps_input_sections);
|
||||||
|
|
||||||
// Add an output SHF_MERGE section POSD to this output section.
|
// Add an output SHF_MERGE section POSD to this output section.
|
||||||
// IS_STRING indicates whether it is a SHF_STRINGS section, and
|
// IS_STRING indicates whether it is a SHF_STRINGS section, and
|
||||||
|
@ -3507,6 +3620,10 @@ class Output_section : public Output_data
|
||||||
const Relaxation_map& map,
|
const Relaxation_map& map,
|
||||||
Input_section_list* input_sections);
|
Input_section_list* input_sections);
|
||||||
|
|
||||||
|
// Build the lookup maps for merge and relaxed input sections.
|
||||||
|
void
|
||||||
|
build_lookup_maps() const;
|
||||||
|
|
||||||
// Most of these fields are only valid after layout.
|
// Most of these fields are only valid after layout.
|
||||||
|
|
||||||
// The name of the section. This will point into a Stringpool.
|
// The name of the section. This will point into a Stringpool.
|
||||||
|
@ -3629,17 +3746,8 @@ class Output_section : public Output_data
|
||||||
uint64_t tls_offset_;
|
uint64_t tls_offset_;
|
||||||
// Saved checkpoint.
|
// Saved checkpoint.
|
||||||
Checkpoint_output_section* checkpoint_;
|
Checkpoint_output_section* checkpoint_;
|
||||||
// Map from input sections to merge sections.
|
// Fast lookup maps for merged and relaxed input sections.
|
||||||
Output_section_data_by_input_section_map merge_section_map_;
|
Output_section_lookup_maps* lookup_maps_;
|
||||||
// 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
|
|
||||||
// because it is updated lazily. We may need to update it in a
|
|
||||||
// const qualified method.
|
|
||||||
mutable Output_relaxed_input_section_by_input_section_map
|
|
||||||
relaxed_input_section_map_;
|
|
||||||
// Whether relaxed_input_section_map_ is valid.
|
|
||||||
mutable bool is_relaxed_input_section_map_valid_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// An output segment. PT_LOAD segments are built from collections of
|
// An output segment. PT_LOAD segments are built from collections of
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue