+ : output_symtab_index_(0), output_dynsym_index_(-1U), input_shndx_(0),
+ is_ordinary_shndx_(false), is_section_symbol_(false),
+ is_tls_symbol_(false), is_ifunc_symbol_(false), has_output_value_(true)
+ { this->u_.value = 0; }
+
+ ~Symbol_value()
+ {
+ if (!this->has_output_value_)
+ delete this->u_.merged_symbol_value;
+ }
+
+ // Get the value of this symbol. OBJECT is the object in which this
+ // symbol is defined, and ADDEND is an addend to add to the value.
+ template<bool big_endian>
+ Value
+ value(const Sized_relobj_file<size, big_endian>* object, Value addend) const
+ {
+ if (this->has_output_value_)
+ return this->u_.value + addend;
+ else
+ {
+ gold_assert(this->is_ordinary_shndx_);
+ return this->u_.merged_symbol_value->value(object, this->input_shndx_,
+ addend);
+ }
+ }
+
+ // Set the value of this symbol in the output symbol table.
+ void
+ set_output_value(Value value)
+ { this->u_.value = value; }
+
+ // For a section symbol in a merged section, we need more
+ // information.
+ void
+ set_merged_symbol_value(Merged_symbol_value<size>* msv)
+ {
+ gold_assert(this->is_section_symbol_);
+ this->has_output_value_ = false;
+ this->u_.merged_symbol_value = msv;
+ }
+
+ // Initialize the input to output map for a section symbol in a
+ // merged section. We also initialize the value of a non-section
+ // symbol in a merged section.
+ void
+ initialize_input_to_output_map(const Relobj* object)
+ {
+ if (!this->has_output_value_)
+ {
+ gold_assert(this->is_section_symbol_ && this->is_ordinary_shndx_);
+ Merged_symbol_value<size>* msv = this->u_.merged_symbol_value;
+ msv->initialize_input_to_output_map(object, this->input_shndx_);
+ }
+ }
+
+ // Free the input to output map for a section symbol in a merged
+ // section.
+ void
+ free_input_to_output_map()
+ {
+ if (!this->has_output_value_)
+ this->u_.merged_symbol_value->free_input_to_output_map();
+ }
+
+ // Set the value of the symbol from the input file. This is only
+ // called by count_local_symbols, to communicate the value to
+ // finalize_local_symbols.
+ void
+ set_input_value(Value value)
+ { this->u_.value = value; }
+
+ // Return the input value. This is only called by
+ // finalize_local_symbols and (in special cases) relocate_section.
+ Value
+ input_value() const
+ { return this->u_.value; }
+
+ // Return whether we have set the index in the output symbol table
+ // yet.
+ bool
+ is_output_symtab_index_set() const
+ {
+ return (this->output_symtab_index_ != 0
+ && this->output_symtab_index_ != -2U);
+ }
+
+ // Return whether this symbol may be discarded from the normal
+ // symbol table.
+ bool
+ may_be_discarded_from_output_symtab() const
+ {
+ gold_assert(!this->is_output_symtab_index_set());
+ return this->output_symtab_index_ != -2U;
+ }
+
+ // Return whether this symbol has an entry in the output symbol
+ // table.
+ bool
+ has_output_symtab_entry() const
+ {
+ gold_assert(this->is_output_symtab_index_set());
+ return this->output_symtab_index_ != -1U;
+ }
+
+ // Return the index in the output symbol table.
+ unsigned int
+ output_symtab_index() const
+ {
+ gold_assert(this->is_output_symtab_index_set()
+ && this->output_symtab_index_ != -1U);
+ return this->output_symtab_index_;
+ }
+
+ // Set the index in the output symbol table.
+ void
+ set_output_symtab_index(unsigned int i)
+ {
+ gold_assert(!this->is_output_symtab_index_set());
+ gold_assert(i != 0 && i != -1U && i != -2U);
+ this->output_symtab_index_ = i;
+ }
+
+ // Record that this symbol should not go into the output symbol
+ // table.
+ void
+ set_no_output_symtab_entry()
+ {
+ gold_assert(this->output_symtab_index_ == 0);
+ this->output_symtab_index_ = -1U;
+ }
+
+ // Record that this symbol must go into the output symbol table,
+ // because it there is a relocation that uses it.
+ void
+ set_must_have_output_symtab_entry()
+ {
+ gold_assert(!this->is_output_symtab_index_set());
+ this->output_symtab_index_ = -2U;
+ }
+
+ // Set the index in the output dynamic symbol table.
+ void
+ set_needs_output_dynsym_entry()
+ {
+ gold_assert(!this->is_section_symbol());
+ this->output_dynsym_index_ = 0;
+ }
+
+ // Return whether this symbol should go into the dynamic symbol
+ // table.
+ bool
+ needs_output_dynsym_entry() const
+ {
+ return this->output_dynsym_index_ != -1U;
+ }
+
+ // Return whether this symbol has an entry in the dynamic symbol
+ // table.
+ bool
+ has_output_dynsym_entry() const
+ {
+ gold_assert(this->output_dynsym_index_ != 0);
+ return this->output_dynsym_index_ != -1U;
+ }
+
+ // Record that this symbol should go into the dynamic symbol table.
+ void
+ set_output_dynsym_index(unsigned int i)
+ {
+ gold_assert(this->output_dynsym_index_ == 0);
+ gold_assert(i != 0 && i != -1U);
+ this->output_dynsym_index_ = i;
+ }
+
+ // Return the index in the output dynamic symbol table.
+ unsigned int
+ output_dynsym_index() const
+ {
+ gold_assert(this->output_dynsym_index_ != 0
+ && this->output_dynsym_index_ != -1U);
+ return this->output_dynsym_index_;
+ }
+
+ // Set the index of the input section in the input file.
+ void
+ set_input_shndx(unsigned int i, bool is_ordinary)
+ {
+ this->input_shndx_ = i;
+ // input_shndx_ field is a bitfield, so make sure that the value
+ // fits.
+ gold_assert(this->input_shndx_ == i);
+ this->is_ordinary_shndx_ = is_ordinary;
+ }
+
+ // Return the index of the input section in the input file.
+ unsigned int
+ input_shndx(bool* is_ordinary) const
+ {
+ *is_ordinary = this->is_ordinary_shndx_;
+ return this->input_shndx_;
+ }
+
+ // Whether this is a section symbol.
+ bool
+ is_section_symbol() const
+ { return this->is_section_symbol_; }
+
+ // Record that this is a section symbol.
+ void
+ set_is_section_symbol()
+ {
+ gold_assert(!this->needs_output_dynsym_entry());
+ this->is_section_symbol_ = true;
+ }
+
+ // Record that this is a TLS symbol.
+ void
+ set_is_tls_symbol()
+ { this->is_tls_symbol_ = true; }
+
+ // Return true if this is a TLS symbol.
+ bool
+ is_tls_symbol() const
+ { return this->is_tls_symbol_; }
+
+ // Record that this is an IFUNC symbol.
+ void
+ set_is_ifunc_symbol()
+ { this->is_ifunc_symbol_ = true; }
+
+ // Return true if this is an IFUNC symbol.
+ bool
+ is_ifunc_symbol() const
+ { return this->is_ifunc_symbol_; }
+
+ // Return true if this has output value.
+ bool
+ has_output_value() const
+ { return this->has_output_value_; }
+
+ private:
+ // The index of this local symbol in the output symbol table. This
+ // will be 0 if no value has been assigned yet, and the symbol may
+ // be omitted. This will be -1U if the symbol should not go into
+ // the symbol table. This will be -2U if the symbol must go into
+ // the symbol table, but no index has been assigned yet.
+ unsigned int output_symtab_index_;
+ // The index of this local symbol in the dynamic symbol table. This
+ // will be -1U if the symbol should not go into the symbol table.
+ unsigned int output_dynsym_index_;
+ // The section index in the input file in which this symbol is
+ // defined.
+ unsigned int input_shndx_ : 27;
+ // Whether the section index is an ordinary index, not a special
+ // value.
+ bool is_ordinary_shndx_ : 1;
+ // Whether this is a STT_SECTION symbol.
+ bool is_section_symbol_ : 1;
+ // Whether this is a STT_TLS symbol.
+ bool is_tls_symbol_ : 1;
+ // Whether this is a STT_GNU_IFUNC symbol.
+ bool is_ifunc_symbol_ : 1;
+ // Whether this symbol has a value for the output file. This is
+ // normally set to true during Layout::finalize, by
+ // finalize_local_symbols. It will be false for a section symbol in
+ // a merge section, as for such symbols we can not determine the
+ // value to use in a relocation until we see the addend.
+ bool has_output_value_ : 1;
+ union
+ {
+ // This is used if has_output_value_ is true. Between
+ // count_local_symbols and finalize_local_symbols, this is the
+ // value in the input file. After finalize_local_symbols, it is
+ // the value in the output file.
+ Value value;
+ // This is used if has_output_value_ is false. It points to the
+ // information we need to get the value for a merge section.
+ Merged_symbol_value<size>* merged_symbol_value;
+ } u_;
+};
+
+// This type is used to modify relocations for -fsplit-stack. It is
+// indexed by relocation index, and means that the relocation at that
+// index should use the symbol from the vector, rather than the one
+// indicated by the relocation.
+
+class Reloc_symbol_changes
+{
+ public:
+ Reloc_symbol_changes(size_t count)
+ : vec_(count, NULL)
+ { }
+
+ void
+ set(size_t i, Symbol* sym)
+ { this->vec_[i] = sym; }
+
+ const Symbol*
+ operator[](size_t i) const
+ { return this->vec_[i]; }
+
+ private:
+ std::vector<Symbol*> vec_;
+};
+
+// Type for mapping section index to uncompressed size and contents.
+
+struct Compressed_section_info
+{
+ section_size_type size;
+ const unsigned char* contents;
+};
+typedef std::map<unsigned int, Compressed_section_info> Compressed_section_map;
+
+// Abstract base class for a regular object file, either a real object file
+// or an incremental (unchanged) object. This is size and endian specific.
+
+template<int size, bool big_endian>
+class Sized_relobj : public Relobj
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef Relobj::Symbols Symbols;
+
+ static const Address invalid_address = static_cast<Address>(0) - 1;
+
+ Sized_relobj(const std::string& name, Input_file* input_file)
+ : Relobj(name, input_file), local_got_offsets_(), section_offsets_()
+ { }
+
+ Sized_relobj(const std::string& name, Input_file* input_file,
+ off_t offset)
+ : Relobj(name, input_file, offset), local_got_offsets_(), section_offsets_()
+ { }
+
+ ~Sized_relobj()