aboutsummaryrefslogtreecommitdiff
path: root/gold/output.h
diff options
context:
space:
mode:
Diffstat (limited to 'gold/output.h')
-rw-r--r--gold/output.h367
1 files changed, 353 insertions, 14 deletions
diff --git a/gold/output.h b/gold/output.h
index 9763d74..c31640f 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -9,6 +9,7 @@
#include "elfcpp.h"
#include "layout.h"
+#include "reloc-types.h"
namespace gold
{
@@ -16,9 +17,11 @@ namespace gold
class General_options;
class Object;
class Output_file;
-
+class Output_section;
template<int size, bool big_endian>
class Sized_target;
+template<int size, bool big_endian>
+class Sized_relobj;
// An abtract class for data which has to go into the output file.
@@ -361,6 +364,262 @@ class Output_data_common : public Output_section_data
{ }
};
+// 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, Address address)
+ : local_sym_index_(GSYM_CODE), type_(type), address_(address)
+ { this->u_.gsym = gsym; }
+
+ // A reloc against a local symbol.
+ Output_reloc(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index,
+ unsigned int type, Address address)
+ : local_sym_index_(local_sym_index), type_(type), address_(address)
+ {
+ assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE);
+ this->u_.object = object;
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ Output_reloc(Output_section* os, unsigned int type, Address address)
+ : local_sym_index_(SECTION_CODE), type_(type), address_(address)
+ { this->u_.os = os; }
+
+ // 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>* object;
+ // 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;
+ } u_;
+ // 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_;
+ unsigned int type_;
+ Address address_;
+};
+
+// 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, Address address, Addend addend)
+ : rel_(gsym, type, address), addend_(addend)
+ { }
+
+ // A reloc against a local symbol.
+ Output_reloc(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index,
+ unsigned int type, Address address, Addend addend)
+ : rel_(object, local_sym_index, type, address), addend_(addend)
+ { }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ Output_reloc(Output_section* os, unsigned int type, Address address,
+ Addend addend)
+ : rel_(os, type, 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:
+ // 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, Address address)
+ { this->add(Output_reloc_type(gsym, type, address)); }
+
+ // Add a reloc against a local symbol.
+ void
+ add_local(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index, unsigned int type, Address address)
+ { this->add(Output_reloc_type(object, local_sym_index, type, address)); }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ void
+ add_output_section(Output_section* os, unsigned int type, Address address)
+ { this->add(Output_reloc_type(os, type, 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, Address address, Addend addend)
+ { this->add(Output_reloc_type(gsym, type, address, addend)); }
+
+ // Add a reloc against a local symbol.
+ void
+ add_local(Sized_relobj<size, big_endian>* object,
+ unsigned int local_sym_index, unsigned int type,
+ Address address, Addend addend)
+ {
+ this->add(Output_reloc_type(object, local_sym_index, type, address,
+ addend));
+ }
+
+ // A reloc against the STT_SECTION symbol of an output section.
+ void
+ add_output_section(Output_section* os, unsigned int type, Address address,
+ Addend addend)
+ { this->add(Output_reloc_type(os, type, 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
// object. The target specific code adds entries to the GOT as
@@ -456,8 +715,8 @@ class Output_data_got : public Output_section_data
// For a constant, the constant.
Valtype constant;
} u_;
- // For a local symbol, the local symbol index. This is -1U for a
- // global symbol, or -2U for a constant.
+ // For a local symbol, the local symbol index. This is GSYM_CODE
+ // for a global symbol, or CONSTANT_CODE for a constant.
unsigned int local_sym_index_;
};
@@ -501,7 +760,7 @@ class Output_section : public Output_data
const elfcpp::Shdr<size, big_endian>& shdr);
// Add generated data ODATA to this output section.
- virtual void
+ void
add_output_section_data(Output_section_data* posd);
// Return the section name.
@@ -549,6 +808,58 @@ class Output_section : public Output_data
set_addralign(uint64_t v)
{ this->addralign_ = v; }
+ // Indicate that we need a symtab index.
+ void
+ set_needs_symtab_index()
+ { this->needs_symtab_index_ = true; }
+
+ // Return whether we need a symtab index.
+ bool
+ needs_symtab_index() const
+ { return this->needs_symtab_index_; }
+
+ // Get the symtab index.
+ unsigned int
+ symtab_index() const
+ {
+ assert(this->symtab_index_ != 0);
+ return this->symtab_index_;
+ }
+
+ // Set the symtab index.
+ void
+ set_symtab_index(unsigned int index)
+ {
+ assert(index != 0);
+ this->symtab_index_ = index;
+ }
+
+ // Indicate that we need a dynsym index.
+ void
+ set_needs_dynsym_index()
+ { this->needs_dynsym_index_ = true; }
+
+ // Return whether we need a dynsym index.
+ bool
+ needs_dynsym_index() const
+ { return this->needs_dynsym_index_; }
+
+ // Get the dynsym index.
+ unsigned int
+ dynsym_index() const
+ {
+ assert(this->dynsym_index_ != 0);
+ return this->dynsym_index_;
+ }
+
+ // Set the dynsym index.
+ void
+ set_dynsym_index(unsigned int index)
+ {
+ assert(index != 0);
+ this->dynsym_index_ = index;
+ }
+
// Set the address of the Output_section. For a typical
// Output_section, there is nothing to do, but if there are any
// Output_section_data objects we need to set the final addresses
@@ -686,13 +997,31 @@ class Output_section : public Output_data
elfcpp::Elf_Xword flags_;
// The section index.
unsigned int out_shndx_;
+ // If there is a STT_SECTION for this output section in the normal
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int symtab_index_;
+ // If there is a STT_SECTION for this output section in the dynamic
+ // symbol table, this is the symbol index. This starts out as zero.
+ // It is initialized in Layout::finalize() to be the index, or -1U
+ // if there isn't one.
+ unsigned int dynsym_index_;
// The input sections. This will be empty in cases where we don't
// need to keep track of them.
Input_section_list input_sections_;
// The offset of the first entry in input_sections_.
off_t first_input_offset_;
// Whether we permit adding data.
- bool may_add_data_;
+ bool may_add_data_ : 1;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // normal symbol table. This will be true if there is a relocation
+ // which needs it.
+ bool needs_symtab_index_ : 1;
+ // Whether this output section needs a STT_SECTION symbol in the
+ // dynamic symbol table. This will be true if there is a dynamic
+ // relocation which needs it.
+ bool needs_dynsym_index_ : 1;
};
// A special Output_section which represents the symbol table
@@ -702,18 +1031,33 @@ class Output_section : public Output_data
class Output_section_symtab : public Output_section
{
public:
- Output_section_symtab(const char* name, off_t size);
+ Output_section_symtab(const char* name, off_t data_size)
+ : Output_section(name, elfcpp::SHT_SYMTAB, 0, false)
+ { this->set_data_size(data_size); }
// The data is written out by Symbol_table::write_globals. We don't
// do anything here.
void
do_write(Output_file*)
{ }
+};
+
+// A special Output_section which represents the dynamic symbol table
+// (SHT_DYNSYM). The actual data is written out by
+// Symbol_table::write_globals.
+
+class Output_section_dynsym : public Output_section
+{
+ public:
+ Output_section_dynsym(const char* name, off_t data_size)
+ : Output_section(name, elfcpp::SHT_DYNSYM, 0, false)
+ { this->set_data_size(data_size); }
- // We don't expect to see any input sections or data here.
+ // The data is written out by Symbol_table::write_globals. We don't
+ // do anything here.
void
- add_output_section_data(Output_section_data*)
- { abort(); }
+ do_write(Output_file*)
+ { }
};
// A special Output_section which holds a string table.
@@ -727,11 +1071,6 @@ class Output_section_strtab : public Output_section
void
do_write(Output_file*);
- // We don't expect to see any input sections or data here.
- void
- add_output_section_data(Output_section_data*)
- { abort(); }
-
private:
Stringpool* contents_;
};