+// A string table which goes into an output section.
+
+class Output_data_strtab : public Output_section_data
+{
+ public:
+ Output_data_strtab(Stringpool* strtab)
+ : Output_section_data(1), strtab_(strtab)
+ { }
+
+ // This is called to set the address and file offset. Here we make
+ // sure that the Stringpool is finalized.
+ void
+ do_set_address(uint64_t, off_t);
+
+ // Write out the data.
+ void
+ do_write(Output_file*);
+
+ private:
+ Stringpool* strtab_;
+};
+
+// This POD class is used to represent a single reloc in the output
+// file. This could be a private class within Output_data_reloc, but
+// the templatization is complex enough that I broke it out into a
+// separate class. The class is templatized on either elfcpp::SHT_REL
+// or elfcpp::SHT_RELA, and also on whether this is a dynamic
+// relocation or an ordinary relocation.
+
+// A relocation can be against a global symbol, a local symbol, an
+// output section, or the undefined symbol at index 0. We represent
+// the latter by using a NULL global symbol.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_reloc;
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ // An uninitialized entry. We need this because we want to put
+ // instances of this class into an STL container.
+ Output_reloc()
+ : local_sym_index_(INVALID_CODE)
+ { }
+
+ // A reloc against a global symbol.
+
+ Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(GSYM_CODE), type_(type),
+ shndx_(INVALID_CODE)
+ {
+ this->u1_.gsym = gsym;
+ this->u2_.od = od;
+ }
+
+ Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
+ unsigned int shndx, Address address)
+ : address_(address), local_sym_index_(GSYM_CODE), type_(type),
+ shndx_(shndx)
+ {
+ gold_assert(shndx != INVALID_CODE);
+ this->u1_.gsym = gsym;
+ this->u2_.relobj = relobj;
+ }
+
+ // A reloc against a local symbol.
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(local_sym_index), type_(type),
+ shndx_(INVALID_CODE)
+ {
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != INVALID_CODE);
+ this->u1_.relobj = relobj;
+ this->u2_.od = od;
+ }
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ unsigned int shndx,
+ Address address)
+ : address_(address), local_sym_index_(local_sym_index), type_(type),
+ shndx_(shndx)
+ {
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != INVALID_CODE);
+ gold_assert(shndx != INVALID_CODE);
+ this->u1_.relobj = relobj;
+ this->u2_.relobj = relobj;
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ Output_reloc(Output_section* os, unsigned int type, Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(SECTION_CODE), type_(type),
+ shndx_(INVALID_CODE)
+ {
+ this->u1_.os = os;
+ this->u2_.od = od;
+ }
+
+ Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
+ unsigned int shndx, Address address)
+ : address_(address), local_sym_index_(SECTION_CODE), type_(type),
+ shndx_(shndx)
+ {
+ gold_assert(shndx != INVALID_CODE);
+ this->u1_.os = os;
+ this->u2_.relobj = relobj;
+ }
+
+ // Write the reloc entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ // Write the offset and info fields to Write_rel.
+ template<typename Write_rel>
+ void write_rel(Write_rel*) const;
+
+ private:
+ // Return the symbol index. We can't do a double template
+ // specialization, so we do a secondary template here.
+ unsigned int
+ get_symbol_index() const;
+
+ // Codes for local_sym_index_.
+ enum
+ {
+ // Global symbol.
+ GSYM_CODE = -1U,
+ // Output section.
+ SECTION_CODE = -2U,
+ // Invalid uninitialized entry.
+ INVALID_CODE = -3U
+ };
+
+ union
+ {
+ // For a local symbol, the object. We will never generate a
+ // relocation against a local symbol in a dynamic object; that
+ // doesn't make sense. And our callers will always be
+ // templatized, so we use Sized_relobj here.
+ Sized_relobj<size, big_endian>* relobj;
+ // For a global symbol, the symbol. If this is NULL, it indicates
+ // a relocation against the undefined 0 symbol.
+ Symbol* gsym;
+ // For a relocation against an output section, the output section.
+ Output_section* os;
+ } u1_;
+ union
+ {
+ // If shndx_ is not INVALID CODE, the object which holds the input
+ // section being used to specify the reloc address.
+ Relobj* relobj;
+ // If shndx_ is INVALID_CODE, the output data being used to
+ // specify the reloc address. This may be NULL if the reloc
+ // address is absolute.
+ Output_data* od;
+ } u2_;
+ // The address offset within the input section or the Output_data.
+ Address address_;
+ // For a local symbol, the local symbol index. This is GSYM_CODE
+ // for a global symbol, or INVALID_CODE for an uninitialized value.
+ unsigned int local_sym_index_;
+ // The reloc type--a processor specific code.
+ unsigned int type_;
+ // If the reloc address is an input section in an object, the
+ // section index. This is INVALID_CODE if the reloc address is
+ // specified in some other way.
+ unsigned int shndx_;
+};
+
+// The SHT_RELA version of Output_reloc<>. This is just derived from
+// the SHT_REL version of Output_reloc, but it adds an addend.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
+
+ // An uninitialized entry.
+ Output_reloc()
+ : rel_()
+ { }
+
+ // A reloc against a global symbol.
+
+ Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ : rel_(gsym, type, od, address), addend_(addend)
+ { }
+
+ Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ : rel_(gsym, type, relobj, shndx, address), addend_(addend)
+ { }
+
+ // A reloc against a local symbol.
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type, Output_data* od, Address address,
+ Addend addend)
+ : rel_(relobj, local_sym_index, type, od, address), addend_(addend)
+ { }
+
+ Output_reloc(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ unsigned int shndx,
+ Address address,
+ Addend addend)
+ : rel_(relobj, local_sym_index, type, shndx, address),
+ addend_(addend)
+ { }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ Output_reloc(Output_section* os, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ : rel_(os, type, od, address), addend_(addend)
+ { }
+
+ Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ : rel_(os, type, relobj, shndx, address), addend_(addend)
+ { }
+
+ // Write the reloc entry to an output view.
+ void
+ write(unsigned char* pov) const;
+
+ private:
+ // The basic reloc.
+ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian> rel_;
+ // The addend.
+ Addend addend_;
+};
+
+// Output_data_reloc is used to manage a section containing relocs.
+// SH_TYPE is either elfcpp::SHT_REL or elfcpp::SHT_RELA. DYNAMIC
+// indicates whether this is a dynamic relocation or a normal
+// relocation. Output_data_reloc_base is a base class.
+// Output_data_reloc is the real class, which we specialize based on
+// the reloc type.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc_base : public Output_section_data
+{
+ public:
+ typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ static const int reloc_size =
+ Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+ // Construct the section.
+ Output_data_reloc_base()
+ : Output_section_data(Output_data::default_alignment(size))
+ { }
+
+ // Write out the data.
+ void
+ do_write(Output_file*);
+
+ protected:
+ // Set the entry size and the link.
+ void
+ do_adjust_output_section(Output_section *os);
+
+ // Add a relocation entry.
+ void
+ add(const Output_reloc_type& reloc)
+ {
+ this->relocs_.push_back(reloc);
+ this->set_data_size(this->relocs_.size() * reloc_size);
+ }
+
+ private:
+ typedef std::vector<Output_reloc_type> Relocs;
+
+ Relocs relocs_;
+};
+
+// The class which callers actually create.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Output_data_reloc;
+
+// The SHT_REL version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+
+ Output_data_reloc()
+ : Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>()
+ { }
+
+ // Add a reloc against a global symbol.
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
+ { this->add(Output_reloc_type(gsym, type, od, address)); }
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Relobj* relobj,
+ unsigned int shndx, Address address)
+ { this->add(Output_reloc_type(gsym, type, relobj, shndx, address)); }
+
+ // Add a reloc against a local symbol.
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address)
+ { this->add(Output_reloc_type(relobj, local_sym_index, type, od, address)); }
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ unsigned int shndx, Address address)
+ { this->add(Output_reloc_type(relobj, local_sym_index, type, shndx,
+ address)); }
+
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ void
+ add_output_section(Output_section* os, unsigned int type,
+ Output_data* od, Address address)
+ { this->add(Output_reloc_type(os, type, od, address)); }
+
+ void
+ add_output_section(Output_section* os, unsigned int type,
+ Relobj* relobj, unsigned int shndx, Address address)
+ { this->add(Output_reloc_type(os, type, relobj, shndx, address)); }
+};
+
+// The SHT_RELA version of Output_data_reloc.
+
+template<bool dynamic, int size, bool big_endian>
+class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
+ : public Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>
+{
+ private:
+ typedef Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size,
+ big_endian> Base;
+
+ public:
+ typedef typename Base::Output_reloc_type Output_reloc_type;
+ typedef typename Output_reloc_type::Address Address;
+ typedef typename Output_reloc_type::Addend Addend;
+
+ Output_data_reloc()
+ : Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>()
+ { }
+
+ // Add a reloc against a global symbol.
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ { this->add(Output_reloc_type(gsym, type, od, address, addend)); }
+
+ void
+ add_global(Symbol* gsym, unsigned int type, Relobj* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ { this->add(Output_reloc_type(gsym, type, relobj, shndx, address, addend)); }
+
+ // Add a reloc against a local symbol.
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address, Addend addend)
+ {
+ this->add(Output_reloc_type(relobj, local_sym_index, type, od, address,
+ addend));
+ }
+
+ void
+ add_local(Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index, unsigned int type,
+ unsigned int shndx, Address address, Addend addend)
+ {
+ this->add(Output_reloc_type(relobj, local_sym_index, type, shndx, address,
+ addend));
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+
+ void
+ add_output_section(Output_section* os, unsigned int type, Output_data* od,
+ Address address, Addend addend)
+ { this->add(Output_reloc_type(os, type, od, address, addend)); }
+
+ void
+ add_output_section(Output_section* os, unsigned int type, Relobj* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ { this->add(Output_reloc_type(os, type, relobj, shndx, address, addend)); }
+};
+
+// Output_data_got is used to manage a GOT. Each entry in the GOT is
+// for one symbol--either a global symbol or a local symbol in an