+// Output_symtab_xindex is used to handle SHT_SYMTAB_SHNDX sections,
+// which may be required if the object file has more than
+// SHN_LORESERVE sections.
+
+class Output_symtab_xindex : public Output_section_data
+{
+ public:
+ Output_symtab_xindex(size_t symcount)
+ : Output_section_data(symcount * 4, 4, true),
+ entries_()
+ { }
+
+ // Add an entry: symbol number SYMNDX has section SHNDX.
+ void
+ add(unsigned int symndx, unsigned int shndx)
+ { this->entries_.push_back(std::make_pair(symndx, shndx)); }
+
+ protected:
+ void
+ do_write(Output_file*);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** symtab xindex")); }
+
+ private:
+ template<bool big_endian>
+ void
+ endian_do_write(unsigned char*);
+
+ // It is likely that most symbols will not require entries. Rather
+ // than keep a vector for all symbols, we keep pairs of symbol index
+ // and section index.
+ typedef std::vector<std::pair<unsigned int, unsigned int> > Xindex_entries;
+
+ // The entries we need.
+ Xindex_entries entries_;
+};
+
+// A relaxed input section.
+class Output_relaxed_input_section : public Output_section_data_build
+{
+ public:
+ // We would like to call relobj->section_addralign(shndx) to get the
+ // alignment but we do not want the constructor to fail. So callers
+ // are repsonsible for ensuring that.
+ Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
+ uint64_t addralign)
+ : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
+ { }
+
+ // Return the Relobj of this relaxed input section.
+ Relobj*
+ relobj() const
+ { return this->relobj_; }
+
+ // Return the section index of this relaxed input section.
+ unsigned int
+ shndx() const
+ { return this->shndx_; }
+
+ private:
+ Relobj* relobj_;
+ 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(result.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(result.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(result.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_;
+};
+