mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-01-22 00:54:36 +00:00
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
@ -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
|
||||
|
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())
|
||||
&& (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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
84
gold/merge.h
84
gold/merge.h
@ -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*
|
||||
|
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 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
|
||||
|
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_;
|
||||
};
|
||||
|
||||
// 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user