// target.h -- target support for gold   -*- C++ -*-

// The abstract class Target is the interface for target specific
// support.  It defines abstract methods which each target must
// implement.  Typically there will be one target per processor, but
// in some cases it may be necessary to have subclasses.

// For speed and consistency we want to use inline functions to handle
// relocation processing.  So besides implementations of the abstract
// methods, each target is expected to define a template
// specialization of the relocation functions.

#ifndef GOLD_TARGET_H
#define GOLD_TARGET_H

#include "elfcpp.h"

namespace gold
{

class General_options;
class Object;
template<int size, bool big_endian>
class Sized_relobj;
template<int size, bool big_endian>
struct Relocate_info;
class Symbol;
template<int size>
class Sized_symbol;
class Symbol_table;

// The abstract class for target specific handling.

class Target
{
 public:
  virtual ~Target()
  { }

  // Return the bit size that this target implements.  This should
  // return 32 or 64.
  int
  get_size() const
  { return this->pti_->size; }

  // Return whether this target is big-endian.
  bool
  is_big_endian() const
  { return this->pti_->is_big_endian; }

  // Machine code to store in e_machine field of ELF header.
  elfcpp::EM
  machine_code() const
  { return this->pti_->machine_code; }

  // Whether this target has a specific make_symbol function.
  bool
  has_make_symbol() const
  { return this->pti_->has_make_symbol; }

  // Whether this target has a specific resolve function.
  bool
  has_resolve() const
  { return this->pti_->has_resolve; }

  // Return the default name of the dynamic linker.
  const char*
  dynamic_linker() const
  { return this->pti_->dynamic_linker; }

  // Return the default address to use for the text segment.
  uint64_t
  text_segment_address() const
  { return this->pti_->text_segment_address; }

  // Return the ABI specified page size.
  uint64_t
  abi_pagesize() const
  { return this->pti_->abi_pagesize; }

  // Return the common page size used on actual systems.
  uint64_t
  common_pagesize() const
  { return this->pti_->common_pagesize; }

  // This is called to tell the target to complete any sections it is
  // handling.  After this all sections must have their final size.
  void
  finalize_sections(const General_options* options, Layout* layout)
  { return this->do_finalize_sections(options, layout); }

 protected:
  // This struct holds the constant information for a child class.  We
  // use a struct to avoid the overhead of virtual function calls for
  // simple information.
  struct Target_info
  {
    // Address size (32 or 64).
    int size;
    // Whether the target is big endian.
    bool is_big_endian;
    // The code to store in the e_machine field of the ELF header.
    elfcpp::EM machine_code;
    // Whether this target has a specific make_symbol function.
    bool has_make_symbol;
    // Whether this target has a specific resolve function.
    bool has_resolve;
    // The default dynamic linker name.
    const char* dynamic_linker;
    // The default text segment address.
    uint64_t text_segment_address;
    // The ABI specified page size.
    uint64_t abi_pagesize;
    // The common page size used by actual implementations.
    uint64_t common_pagesize;
  };

  Target(const Target_info* pti)
    : pti_(pti)
  { }

  // Virtual function which may be implemented by the child class.
  virtual void
  do_finalize_sections(const General_options*, Layout*)
  { }

 private:
  Target(const Target&);
  Target& operator=(const Target&);

  // The target information.
  const Target_info* pti_;
};

// The abstract class for a specific size and endianness of target.
// Each actual target implementation class should derive from an
// instantiation of Sized_target.

template<int size, bool big_endian>
class Sized_target : public Target
{
 public:
  // Make a new symbol table entry for the target.  This should be
  // overridden by a target which needs additional information in the
  // symbol table.  This will only be called if has_make_symbol()
  // returns true.
  virtual Sized_symbol<size>*
  make_symbol() const
  { gold_unreachable(); }

  // Resolve a symbol for the target.  This should be overridden by a
  // target which needs to take special action.  TO is the
  // pre-existing symbol.  SYM is the new symbol, seen in OBJECT.
  // VERSION is the version of SYM.  This will only be called if
  // has_resolve() returns true.
  virtual void
  resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*,
	  const char*)
  { gold_unreachable(); }

  // Scan the relocs for a section, and record any information
  // required for the symbol.  OPTIONS is the command line options.
  // SYMTAB is the symbol table.  OBJECT is the object in which the
  // section appears.  DATA_SHNDX is the section index that these
  // relocs apply to.  SH_TYPE is the type of the relocation section,
  // SHT_REL or SHT_RELA.  PRELOCS points to the relocation data.
  // RELOC_COUNT is the number of relocs.  LOCAL_SYMBOL_COUNT is the
  // number of local symbols.  PLOCAL_SYMBOLS points to the local
  // symbol data from OBJECT.  GLOBAL_SYMBOLS is the array of pointers
  // to the global symbol table from OBJECT.
  virtual void
  scan_relocs(const General_options& options,
	      Symbol_table* symtab,
	      Layout* layout,
	      Sized_relobj<size, big_endian>* object,
	      unsigned int data_shndx,
	      unsigned int sh_type,
	      const unsigned char* prelocs,
	      size_t reloc_count,
	      size_t local_symbol_count,
	      const unsigned char* plocal_symbols,
	      Symbol** global_symbols) = 0;

  // Relocate section data.  SH_TYPE is the type of the relocation
  // section, SHT_REL or SHT_RELA.  PRELOCS points to the relocation
  // information.  RELOC_COUNT is the number of relocs.  VIEW is a
  // view into the output file holding the section contents,
  // VIEW_ADDRESS is the virtual address of the view, and VIEW_SIZE is
  // the size of the view.
  virtual void
  relocate_section(const Relocate_info<size, big_endian>*,
		   unsigned int sh_type,
		   const unsigned char* prelocs,
		   size_t reloc_count,
		   unsigned char* view,
		   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
		   off_t view_size) = 0;

 protected:
  Sized_target(const Target::Target_info* pti)
    : Target(pti)
  {
    gold_assert(pti->size == size);
    gold_assert(pti->is_big_endian ? big_endian : !big_endian);
  }
};

} // End namespace gold.

#endif // !defined(GOLD_TARGET_H)