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:
Doug Kwan 2010-05-23 07:43:39 +00:00
parent f434ba0309
commit 0439c7962a
6 changed files with 564 additions and 182 deletions

View File

@ -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>
PR gold/11619

View File

@ -1202,7 +1202,8 @@ class Arm_input_section : public Output_relaxed_input_section
if ((object == this->relobj())
&& (shndx == this->shndx())
&& (offset >= 0)
&& (offset <= static_cast<section_offset_type>(this->original_size_)))
&& (offset <=
convert_types<section_offset_type, uint32_t>(this->original_size_)))
{
*poutput = offset;
return true;
@ -10898,13 +10899,11 @@ Target_arm<big_endian>::apply_cortex_a8_workaround(
switch (stub->stub_template()->type())
{
case arm_stub_a8_veneer_b_cond:
gold_assert(!utils::has_overflow<21>(branch_offset));
upper_insn = RelocFuncs::thumb32_cond_branch_upper(upper_insn,
branch_offset);
lower_insn = RelocFuncs::thumb32_cond_branch_lower(lower_insn,
branch_offset);
break;
// For a conditional branch, we re-write it to be a uncondition
// branch to the stub. We use the THUMB-2 encoding here.
upper_insn = 0xf000U;
lower_insn = 0xb800U;
// Fall through
case arm_stub_a8_veneer_b:
case arm_stub_a8_veneer_bl:
case arm_stub_a8_veneer_blx:

View File

@ -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);
}
// 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.
// 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);
}
// For script processing, we keep the input sections.
if (this->keeps_input_sections())
record_input_section(object, shndx);
return true;
}
@ -517,6 +541,10 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
this->input_count_ += count;
// For script processing, we keep the input sections.
if (this->keeps_input_sections())
record_input_section(object, shndx);
return true;
}

View File

@ -216,7 +216,9 @@ class Output_merge_base : public Output_section_data
{
public:
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.
@ -230,6 +232,52 @@ class Output_merge_base : public Output_section_data
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:
// Return the output offset for an input offset.
bool
@ -257,6 +305,15 @@ class Output_merge_base : public Output_section_data
do_is_string()
{ 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:
// A mapping from input object/section/offset to offset in output
// 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 constants. For strings, this is the size of a character.
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.
@ -303,6 +369,14 @@ class Output_merge_data : public Output_merge_base
void
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:
// We build a hash table of the fixed-size constants. Each constant
// 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()
{ 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:
// The name of the string type, for stats.
const char*

View File

@ -1749,6 +1749,42 @@ Output_section::Input_section::data_size() const
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.
void
@ -1914,10 +1950,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
is_noload_(false),
tls_offset_(0),
checkpoint_(NULL),
merge_section_map_(),
merge_section_by_properties_map_(),
relaxed_input_section_map_(),
is_relaxed_input_section_map_valid_(true)
lookup_maps_(new Output_section_lookup_maps)
{
// An unallocated section has no address. Forcing this means that
// 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
&& shdr.get_sh_size() > 0)
{
if (this->add_merge_input_section(object, shndx, sh_flags,
entsize, addralign))
// Keep information about merged input sections for rebuilding fast
// 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
// 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);
this->add_output_section_data(&inp);
if (this->is_relaxed_input_section_map_valid_)
{
Const_section_id csid(poris->relobj(), poris->shndx());
this->relaxed_input_section_map_[csid] = poris;
}
if (this->lookup_maps_->is_valid())
this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
poris->shndx(), poris);
// For a relaxed section, we use the current data size. Linker scripts
// 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
Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
uint64_t flags, uint64_t entsize,
uint64_t addralign)
uint64_t addralign,
bool keeps_input_sections)
{
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);
// 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_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* pomb = this->lookup_maps_->find_merge_section(msp);
bool is_new = false;
if (pomb != NULL)
{
pomb = p->second;
gold_assert(pomb->is_string() == is_string
&& pomb->entsize() == entsize
&& pomb->addralign() == addralign);
@ -2188,22 +2226,36 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
return false;
}
}
// 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;
// If we need to do script processing or relaxation, we need to keep
// the original input sections to rebuild the fast lookup maps.
if (keeps_input_sections)
pomb->set_keeps_input_sections();
is_new = true;
}
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
// merge section in map.
Const_section_id csid(object, shndx);
this->merge_section_map_[csid] = pomb;
this->lookup_maps_->add_merge_input_section(object, shndx, pomb);
return true;
}
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.
@ -2298,12 +2350,12 @@ Output_section::convert_input_sections_to_relaxed_sections(
&this->input_sections_);
// 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)
{
Output_relaxed_input_section* poris = relaxed_sections[i];
Const_section_id csid(poris->relobj(), poris->shndx());
this->relaxed_input_section_map_[csid] = poris;
this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
poris->shndx(), poris);
}
}
@ -2348,17 +2400,47 @@ Output_section_data*
Output_section::find_merge_section(const Relobj* object,
unsigned int shndx) const
{
Const_section_id csid(object, shndx);
Output_section_data_by_input_section_map::const_iterator p =
this->merge_section_map_.find(csid);
if (p != this->merge_section_map_.end())
if (!this->lookup_maps_->is_valid())
this->build_lookup_maps();
return this->lookup_maps_->find_merge_section(object, shndx);
}
// 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;
gold_assert(posd->is_merge_section_for(object, shndx));
return posd;
if (p->is_merge_section())
{
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
@ -2368,31 +2450,9 @@ const Output_relaxed_input_section*
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())
{
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;
if (!this->lookup_maps_->is_valid())
this->build_lookup_maps();
return this->lookup_maps_->find_relaxed_input_section(object, shndx);
}
// 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_->save_input_sections();
// Invalidate the relaxed input section map.
this->is_relaxed_input_section_map_valid_ = false;
// Invalidate fast look-up maps.
this->lookup_maps_->invalidate();
uint64_t orig_address = address;
@ -3064,7 +3124,9 @@ Output_section::get_input_sections(
p != this->input_sections_.end();
++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);
else
{
@ -3121,6 +3183,30 @@ Output_section::add_script_input_section(const Input_section& sis)
+ data_size);
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.
@ -3146,9 +3232,9 @@ Output_section::discard_states()
this->checkpoint_ = NULL;
gold_assert(this->fills_.empty());
// Simply invalidate the relaxed input section map since we do not keep
// track of it.
this->is_relaxed_input_section_map_valid_ = false;
// Simply invalidate the fast lookup maps since we do not keep
// track of them.
this->lookup_maps_->invalidate();
}
void
@ -3180,9 +3266,9 @@ Output_section::restore_states()
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;
// Simply invalidate the fast lookup maps since we do not keep
// track of them.
this->lookup_maps_->invalidate();
}
// Update the section offsets of input sections in this. This is required if

View File

@ -2314,6 +2314,188 @@ class Output_relaxed_input_section : public Output_section_data_build
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
// 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);
}
// 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.
bool
is_relaxed_input_section() const
@ -2895,27 +3085,11 @@ class Output_section : public Output_data
// Return the object for an input section.
Relobj*
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();
}
relobj() const;
// Return the input section index for an input section.
unsigned int
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();
}
shndx() const;
// For non-input-sections, return the associated Output_section_data
// object.
@ -2926,6 +3100,14 @@ class Output_section : public Output_data
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.
Output_relaxed_input_section*
relaxed_input_section() const
@ -3048,6 +3230,7 @@ class Output_section : public Output_data
// For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
// MERGE_STRING_SECTION_CODE, the data.
Output_section_data* posd;
Output_merge_base* pomb;
// For RELAXED_INPUT_SECTION_CODE, the data.
Output_relaxed_input_section* poris;
} u2_;
@ -3389,78 +3572,6 @@ 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 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
// a section id an input section list index. We assume that
// Input_section_list is a vector.
@ -3471,10 +3582,12 @@ class Output_section : public Output_data
add_output_section_data(Input_section*);
// 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
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.
// 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,
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.
// 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_;
// 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
// 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_;
// Fast lookup maps for merged and relaxed input sections.
Output_section_lookup_maps* lookup_maps_;
};
// An output segment. PT_LOAD segments are built from collections of