diff options
-rw-r--r-- | gold/ChangeLog | 79 | ||||
-rw-r--r-- | gold/arm.cc | 15 | ||||
-rw-r--r-- | gold/merge.cc | 28 | ||||
-rw-r--r-- | gold/merge.h | 84 | ||||
-rw-r--r-- | gold/output.cc | 226 | ||||
-rw-r--r-- | gold/output.h | 314 |
6 files changed, 564 insertions, 182 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index c9ecbe7..b66743a 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -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 diff --git a/gold/arm.cc b/gold/arm.cc index 31454e9..8bcd5d2 100644 --- a/gold/arm.cc +++ b/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: diff --git a/gold/merge.cc b/gold/merge.cc index e2b6eef..6e44ddd 100644 --- a/gold/merge.cc +++ b/gold/merge.cc @@ -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; } diff --git a/gold/merge.h b/gold/merge.h index 345b115..c2d305b 100644 --- a/gold/merge.h +++ b/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* diff --git a/gold/output.cc b/gold/output.cc index 4c9776d..752a1d3 100644 --- a/gold/output.cc +++ b/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 diff --git a/gold/output.h b/gold/output.h index a15fe27..eb5d836 100644 --- a/gold/output.h +++ b/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 |