+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
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;
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:
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.
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;
}
this->input_count_ += count;
+ // For script processing, we keep the input sections.
+ if (this->keeps_input_sections())
+ record_input_section(object, shndx);
+
return true;
}
{
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.
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
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.
// 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.
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.
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*
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
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
&& 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.
{
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
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;
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);
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.
&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);
}
}
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
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
&& !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;
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
{
+ 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.
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
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
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.
&& 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
// 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.
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
// 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_;
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.
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
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.
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