text: // tilegx.cc -- tilegx target support for gold.
  
  // Copyright (C) 2012-2021 Free Software Foundation, Inc.
  // Written by Jiong Wang (jiwang@tilera.com)
  
  // This file is part of gold.
  
  // This program is free software; you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation; either version 3 of the License, or
  // (at your option) any later version.
  
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  
  // You should have received a copy of the GNU General Public License
  // along with this program; if not, write to the Free Software
  // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  // MA 02110-1301, USA.
  
  #include "gold.h"
  
  #include <cstring>
  
  #include "elfcpp.h"
  #include "dwarf.h"
  #include "parameters.h"
  #include "reloc.h"
  #include "tilegx.h"
  #include "object.h"
  #include "symtab.h"
  #include "layout.h"
  #include "output.h"
  #include "copy-relocs.h"
  #include "target.h"
  #include "target-reloc.h"
  #include "target-select.h"
  #include "tls.h"
  #include "gc.h"
  #include "icf.h"
  
  // the first got entry reserved
  const int32_t TILEGX_GOT_RESERVE_COUNT = 1;
  
  // the first two .got.plt entry reserved
  const int32_t TILEGX_GOTPLT_RESERVE_COUNT = 2;
  
  // 1. for both 64/32 bit mode, the instruction bundle is always 64bit.
  // 2. thus .plt section should always be aligned to 64 bit.
  const int32_t TILEGX_INST_BUNDLE_SIZE = 64;
  
  namespace
  {
  
  using namespace gold;
  
  // A class to handle the PLT data.
  // This is an abstract base class that handles most of the linker details
  // but does not know the actual contents of PLT entries.  The derived
  // classes below fill in those details.
  
  template<int size, bool big_endian>
  class Output_data_plt_tilegx : public Output_section_data
  {
   public:
    typedef Output_data_reloc<elfcpp::SHT_RELA, true,size, big_endian>
      Reloc_section;
  
    Output_data_plt_tilegx(Layout* layout, uint64_t addralign,
                           Output_data_got<size, big_endian>* got,
                           Output_data_space* got_plt,
                           Output_data_space* got_irelative)
      : Output_section_data(addralign), layout_(layout),
        irelative_rel_(NULL), got_(got), got_plt_(got_plt),
        got_irelative_(got_irelative), count_(0),
        irelative_count_(0), free_list_()
    { this->init(layout); }
  
    Output_data_plt_tilegx(Layout* layout, uint64_t plt_entry_size,
                           Output_data_got<size, big_endian>* got,
                           Output_data_space* got_plt,
                           Output_data_space* got_irelative,
                           unsigned int plt_count)
      : Output_section_data((plt_count + 1) * plt_entry_size,
                            TILEGX_INST_BUNDLE_SIZE, false),
        layout_(layout), irelative_rel_(NULL), got_(got),
        got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count),
        irelative_count_(0), free_list_()
    {
      this->init(layout);
  
      // Initialize the free list and reserve the first entry.
      this->free_list_.init((plt_count + 1) * plt_entry_size, false);
      this->free_list_.remove(0, plt_entry_size);
    }
  
    // Initialize the PLT section.
    void
    init(Layout* layout);
  
    // Add an entry to the PLT.
    void
    add_entry(Symbol_table*, Layout*, Symbol* gsym);
  
    // Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
    unsigned int
    add_local_ifunc_entry(Symbol_table*, Layout*,
      Sized_relobj_file<size, big_endian>*, unsigned int);
  
    // Add the relocation for a PLT entry.
    void
    add_relocation(Symbol_table*, Layout*, Symbol*, unsigned int);
  
    // Return the .rela.plt section data.
    Reloc_section*
    rela_plt()
    { return this->rel_; }
  
    // Return where the IRELATIVE relocations should go in the PLT
    // relocations.
    Reloc_section*
    rela_irelative(Symbol_table*, Layout*);
  
    // Return whether we created a section for IRELATIVE relocations.
    bool
    has_irelative_section() const
    { return this->irelative_rel_ != NULL; }
  
    // Return the number of PLT entries.
    unsigned int
    entry_count() const
    { return this->count_ + this->irelative_count_; }
  
    // Return the offset of the first non-reserved PLT entry.
    unsigned int
    first_plt_entry_offset()
    { return this->get_plt_entry_size(); }
  
    // Return the size of a PLT entry.
    unsigned int
    get_plt_entry_size() const
    { return plt_entry_size; }
  
    // Reserve a slot in the PLT for an existing symbol in an incremental update.
    void
    reserve_slot(unsigned int plt_index)
    {
      this->free_list_.remove((plt_index + 1) * this->get_plt_entry_size(),
                              (plt_index + 2) * this->get_plt_entry_size());
    }
  
    // Return the PLT address to use for a global symbol.
    uint64_t
    address_for_global(const Symbol*);
  
    // Return the PLT address to use for a local symbol.
    uint64_t
    address_for_local(const Relobj*, unsigned int symndx);
  
   protected:
    // Fill in the first PLT entry.
    void
    fill_first_plt_entry(unsigned char*);
  
    // Fill in a normal PLT entry.  Returns the offset into the entry that
    // should be the initial GOT slot value.
    void
    fill_plt_entry(unsigned char*,
                   typename elfcpp::Elf_types<size>::Elf_Addr,
                   unsigned int,
                   typename elfcpp::Elf_types<size>::Elf_Addr,
                   unsigned int, unsigned int);
  
    void
    do_adjust_output_section(Output_section* os);
  
    // Write to a map file.
    void
    do_print_to_mapfile(Mapfile* mapfile) const
    { mapfile->print_output_data(this, _("** PLT")); }
  
   private:
    // Set the final size.
    void
    set_final_data_size();
  
    // Write out the PLT data.
    void
    do_write(Output_file*);
  
    // A pointer to the Layout class, so that we can find the .dynamic
    // section when we write out the GOT PLT section.
    Layout* layout_;
    // The reloc section.
    Reloc_section* rel_;
    // The IRELATIVE relocs, if necessary.  These must follow the
    // regular PLT relocations.
    Reloc_section* irelative_rel_;
    // The .got section.
    Output_data_got<size, big_endian>* got_;
    // The .got.plt section.
    Output_data_space* got_plt_;
    // The part of the .got.plt section used for IRELATIVE relocs.
    Output_data_space* got_irelative_;
    // The number of PLT entries.
    unsigned int count_;
    // Number of PLT entries with R_TILEGX_IRELATIVE relocs.  These
    // follow the regular PLT entries.
    unsigned int irelative_count_;
    // List of available regions within the section, for incremental
    // update links.
    Free_list free_list_;
    // The size of an entry in the PLT.
    static const int plt_entry_size = 40;
    // The first entry in the PLT.
    static const unsigned char first_plt_entry[plt_entry_size];
    // Other entries in the PLT for an executable.
    static const unsigned char plt_entry[plt_entry_size];
  };
  
  // The tilegx target class.
  // See the ABI at
  //   http://www.tilera.com/scm
  // TLS info comes from
  //   http://people.redhat.com/drepper/tls.pdf
  
  template<int size, bool big_endian>
  class Target_tilegx : public Sized_target<size, big_endian>
  {
   public:
    // TileGX use RELA
    typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
      Reloc_section;
  
    Target_tilegx(const Target::Target_info* info = &tilegx_info)
      : Sized_target<size, big_endian>(info),
        got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
        global_offset_table_(NULL), tilegx_dynamic_(NULL), rela_dyn_(NULL),
        rela_irelative_(NULL), copy_relocs_(elfcpp::R_TILEGX_COPY),
        got_mod_index_offset_(-1U),
        tls_get_addr_sym_defined_(false)
    { }
  
    // Scan the relocations to look for symbol adjustments.
    void
    gc_process_relocs(Symbol_table* symtab,
                      Layout* layout,
                      Sized_relobj_file<size, big_endian>* object,
                      unsigned int data_shndx,
                      unsigned int sh_type,
                      const unsigned char* prelocs,
                      size_t reloc_count,
                      Output_section* output_section,
                      bool needs_special_offset_handling,
                      size_t local_symbol_count,
                      const unsigned char* plocal_symbols);
  
    // Scan the relocations to look for symbol adjustments.
    void
    scan_relocs(Symbol_table* symtab,
                Layout* layout,
                Sized_relobj_file<size, big_endian>* object,
                unsigned int data_shndx,
                unsigned int sh_type,
                const unsigned char* prelocs,
                size_t reloc_count,
                Output_section* output_section,
                bool needs_special_offset_handling,
                size_t local_symbol_count,
                const unsigned char* plocal_symbols);
  
    // Finalize the sections.
    void
    do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);
  
    // Return the value to use for a dynamic which requires special
    // treatment.
    uint64_t
    do_dynsym_value(const Symbol*) const;
  
    // Relocate a section.
    void
    relocate_section(const Relocate_info<size, big_endian>*,
                     unsigned int sh_type,
                     const unsigned char* prelocs,
                     size_t reloc_count,
                     Output_section* output_section,
                     bool needs_special_offset_handling,
                     unsigned char* view,
                     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
                     section_size_type view_size,
                     const Reloc_symbol_changes*);
  
    // Scan the relocs during a relocatable link.
    void
    scan_relocatable_relocs(Symbol_table* symtab,
                            Layout* layout,
                            Sized_relobj_file<size, big_endian>* object,
                            unsigned int data_shndx,
                            unsigned int sh_type,
                            const unsigned char* prelocs,
                            size_t reloc_count,
                            Output_section* output_section,
                            bool needs_special_offset_handling,
                            size_t local_symbol_count,
                            const unsigned char* plocal_symbols,
                            Relocatable_relocs*);
  
    // Scan the relocs for --emit-relocs.
    void
    emit_relocs_scan(Symbol_table* symtab,
  		   Layout* layout,
  		   Sized_relobj_file<size, big_endian>* object,
  		   unsigned int data_shndx,
  		   unsigned int sh_type,
  		   const unsigned char* prelocs,
  		   size_t reloc_count,
  		   Output_section* output_section,
  		   bool needs_special_offset_handling,
  		   size_t local_symbol_count,
  		   const unsigned char* plocal_syms,
  		   Relocatable_relocs* rr);
  
    // Relocate a section during a relocatable link.
    void
    relocate_relocs(
        const Relocate_info<size, big_endian>*,
        unsigned int sh_type,
        const unsigned char* prelocs,
        size_t reloc_count,
        Output_section* output_section,
        typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
        unsigned char* view,
        typename elfcpp::Elf_types<size>::Elf_Addr view_address,
        section_size_type view_size,
        unsigned char* reloc_view,
        section_size_type reloc_view_size);
  
    // Return whether SYM is defined by the ABI.
    bool
    do_is_defined_by_abi(const Symbol* sym) const
    { return strcmp(sym->name(), "__tls_get_addr") == 0; }
  
    // define tilegx specific symbols
    virtual void
    do_define_standard_symbols(Symbol_table*, Layout*);
  
    // Return the PLT section.
    uint64_t
    do_plt_address_for_global(const Symbol* gsym) const
    { return this->plt_section()->address_for_global(gsym); }
  
    uint64_t
    do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
    { return this->plt_section()->address_for_local(relobj, symndx); }
  
    // This function should be defined in targets that can use relocation
    // types to determine (implemented in local_reloc_may_be_function_pointer
    // and global_reloc_may_be_function_pointer)
    // if a function's pointer is taken.  ICF uses this in safe mode to only
    // fold those functions whose pointer is defintely not taken.  For tilegx
    // pie binaries, safe ICF cannot be done by looking at relocation types.
    bool
    do_can_check_for_function_pointers() const
    { return true; }
  
    // Return the base for a DW_EH_PE_datarel encoding.
    uint64_t
    do_ehframe_datarel_base() const;
  
    // Return whether there is a GOT section.
    bool
    has_got_section() const
    { return this->got_ != NULL; }
  
    // Return the size of the GOT section.
    section_size_type
    got_size() const
    {
      gold_assert(this->got_ != NULL);
      return this->got_->data_size();
    }
  
    // Return the number of entries in the GOT.
    unsigned int
    got_entry_count() const
    {
      if (this->got_ == NULL)
        return 0;
      return this->got_size() / (size / 8);
    }
  
    // Return the number of entries in the PLT.
    unsigned int
    plt_entry_count() const;
  
    // Return the offset of the first non-reserved PLT entry.
    unsigned int
    first_plt_entry_offset() const;
  
    // Return the size of each PLT entry.
    unsigned int
    plt_entry_size() const;
  
    // Create the GOT section for an incremental update.
    Output_data_got_base*
    init_got_plt_for_update(Symbol_table* symtab,
                            Layout* layout,
                            unsigned int got_count,
                            unsigned int plt_count);
  
    // Reserve a GOT entry for a local symbol, and regenerate any
    // necessary dynamic relocations.
    void
    reserve_local_got_entry(unsigned int got_index,
                            Sized_relobj<size, big_endian>* obj,
                            unsigned int r_sym,
                            unsigned int got_type);
  
    // Reserve a GOT entry for a global symbol, and regenerate any
    // necessary dynamic relocations.
    void
    reserve_global_got_entry(unsigned int got_index, Symbol* gsym,
                             unsigned int got_type);
  
    // Register an existing PLT entry for a global symbol.
    void
    register_global_plt_entry(Symbol_table*, Layout*, unsigned int plt_index,
                              Symbol* gsym);
  
    // Force a COPY relocation for a given symbol.
    void
    emit_copy_reloc(Symbol_table*, Symbol*, Output_section*, off_t);
  
    // Apply an incremental relocation.
    void
    apply_relocation(const Relocate_info<size, big_endian>* relinfo,
                     typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
                     unsigned int r_type,
                     typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
                     const Symbol* gsym,
                     unsigned char* view,
                     typename elfcpp::Elf_types<size>::Elf_Addr address,
                     section_size_type view_size);
  
   private:
    // The class which scans relocations.
    class Scan
    {
    public:
      Scan()
        : issued_non_pic_error_(false)
      { }
  
      static inline int
      get_reference_flags(unsigned int r_type);
  
      inline void
      local(Symbol_table* symtab, Layout* layout, Target_tilegx* target,
            Sized_relobj_file<size, big_endian>* object,
            unsigned int data_shndx,
            Output_section* output_section,
            const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
            const elfcpp::Sym<size, big_endian>& lsym,
            bool is_discarded);
  
      inline void
      global(Symbol_table* symtab, Layout* layout, Target_tilegx* target,
             Sized_relobj_file<size, big_endian>* object,
             unsigned int data_shndx,
             Output_section* output_section,
             const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
             Symbol* gsym);
  
      inline bool
      local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
                              Target_tilegx* target,
                              Sized_relobj_file<size, big_endian>* object,
                              unsigned int data_shndx,
                              Output_section* output_section,
                              const elfcpp::Rela<size, big_endian>& reloc,
                              unsigned int r_type,
                              const elfcpp::Sym<size, big_endian>& lsym);
  
      inline bool
      global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
                              Target_tilegx* target,
                              Sized_relobj_file<size, big_endian>* object,
                              unsigned int data_shndx,
                              Output_section* output_section,
                              const elfcpp::Rela<size, big_endian>& reloc,
                              unsigned int r_type,
                              Symbol* gsym);
  
    private:
      static void
      unsupported_reloc_local(Sized_relobj_file<size, big_endian>*,
                              unsigned int r_type);
  
      static void
      unsupported_reloc_global(Sized_relobj_file<size, big_endian>*,
                               unsigned int r_type, Symbol*);
  
      void
      check_non_pic(Relobj*, unsigned int r_type);
  
      inline bool
      possible_function_pointer_reloc(unsigned int r_type);
  
      bool
      reloc_needs_plt_for_ifunc(Sized_relobj_file<size, big_endian>*,
                                unsigned int r_type);
  
      // Whether we have issued an error about a non-PIC compilation.
      bool issued_non_pic_error_;
    };
  
    // The class which implements relocation.
    class Relocate
    {
     public:
      Relocate()
      { }
  
      ~Relocate()
      {
      }
  
      // Do a relocation.  Return false if the caller should not issue
      // any warnings about this relocation.
      inline bool
      relocate(const Relocate_info<size, big_endian>*, unsigned int,
  	     Target_tilegx*, Output_section*, size_t, const unsigned char*,
  	     const Sized_symbol<size>*, const Symbol_value<size>*,
  	     unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
  	     section_size_type);
    };
  
    // Adjust TLS relocation type based on the options and whether this
    // is a local symbol.
    static tls::Tls_optimization
    optimize_tls_reloc(bool is_final, int r_type);
  
    // Get the GOT section, creating it if necessary.
    Output_data_got<size, big_endian>*
    got_section(Symbol_table*, Layout*);
  
    // Get the GOT PLT section.
    Output_data_space*
    got_plt_section() const
    {
      gold_assert(this->got_plt_ != NULL);
      return this->got_plt_;
    }
  
    // Create the PLT section.
    void
    make_plt_section(Symbol_table* symtab, Layout* layout);
  
    // Create a PLT entry for a global symbol.
    void
    make_plt_entry(Symbol_table*, Layout*, Symbol*);
  
    // Create a PLT entry for a local STT_GNU_IFUNC symbol.
    void
    make_local_ifunc_plt_entry(Symbol_table*, Layout*,
                               Sized_relobj_file<size, big_endian>* relobj,
                               unsigned int local_sym_index);
  
    // Create a GOT entry for the TLS module index.
    unsigned int
    got_mod_index_entry(Symbol_table* symtab, Layout* layout,
                        Sized_relobj_file<size, big_endian>* object);
  
    // Get the PLT section.
    Output_data_plt_tilegx<size, big_endian>*
    plt_section() const
    {
      gold_assert(this->plt_ != NULL);
      return this->plt_;
    }
  
    // Get the dynamic reloc section, creating it if necessary.
    Reloc_section*
    rela_dyn_section(Layout*);
  
    // Get the section to use for IRELATIVE relocations.
    Reloc_section*
    rela_irelative_section(Layout*);
  
    // Add a potential copy relocation.
    void
    copy_reloc(Symbol_table* symtab, Layout* layout,
               Sized_relobj_file<size, big_endian>* object,
               unsigned int shndx, Output_section* output_section,
               Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
    {
      unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
      this->copy_relocs_.copy_reloc(symtab, layout,
                                    symtab->get_sized_symbol<size>(sym),
                                    object, shndx, output_section,
  				  r_type, reloc.get_r_offset(),
  				  reloc.get_r_addend(),
                                    this->rela_dyn_section(layout));
    }
  
    // Information about this specific target which we pass to the
    // general Target structure.
    static const Target::Target_info tilegx_info;
  
    // The types of GOT entries needed for this platform.
    // These values are exposed to the ABI in an incremental link.
    // Do not renumber existing values without changing the version
    // number of the .gnu_incremental_inputs section.
    enum Got_type
    {
      GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
      GOT_TYPE_TLS_OFFSET = 1,    // GOT entry for TLS offset
      GOT_TYPE_TLS_PAIR = 2,      // GOT entry for TLS module/offset pair
      GOT_TYPE_TLS_DESC = 3       // GOT entry for TLS_DESC pair
    };
  
    // This type is used as the argument to the target specific
    // relocation routines.  The only target specific reloc is
    // R_X86_64_TLSDESC against a local symbol.
    struct Tlsdesc_info
    {
      Tlsdesc_info(Sized_relobj_file<size, big_endian>* a_object,
                   unsigned int a_r_sym)
        : object(a_object), r_sym(a_r_sym)
      { }
  
      // The object in which the local symbol is defined.
      Sized_relobj_file<size, big_endian>* object;
      // The local symbol index in the object.
      unsigned int r_sym;
    };
  
    // The GOT section.
    Output_data_got<size, big_endian>* got_;
    // The PLT section.
    Output_data_plt_tilegx<size, big_endian>* plt_;
    // The GOT PLT section.
    Output_data_space* got_plt_;
    // The GOT section for IRELATIVE relocations.
    Output_data_space* got_irelative_;
    // The _GLOBAL_OFFSET_TABLE_ symbol.
    Symbol* global_offset_table_;
    // The _TILEGX_DYNAMIC_ symbol.
    Symbol* tilegx_dynamic_;
    // The dynamic reloc section.
    Reloc_section* rela_dyn_;
    // The section to use for IRELATIVE relocs.
    Reloc_section* rela_irelative_;
    // Relocs saved to avoid a COPY reloc.
    Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
    // Offset of the GOT entry for the TLS module index.
    unsigned int got_mod_index_offset_;
    // True if the _tls_get_addr symbol has been defined.
    bool tls_get_addr_sym_defined_;
  };
  
  template<>
  const Target::Target_info Target_tilegx<64, false>::tilegx_info =
  {
    64,                   // size
    false,                // is_big_endian
    elfcpp::EM_TILEGX,    // machine_code
    false,                // has_make_symbol
    false,                // has_resolve
    false,                // has_code_fill
    true,                 // is_default_stack_executable
    false,                // can_icf_inline_merge_sections
    '\0',                 // wrap_char
    "/lib/ld.so.1",       // program interpreter
    0x10000,              // default_text_segment_address
    0x10000,              // abi_pagesize (overridable by -z max-page-size)
    0x10000,              // common_pagesize (overridable by -z common-page-size)
    false,                // isolate_execinstr
    0,                    // rosegment_gap
    elfcpp::SHN_UNDEF,    // small_common_shndx
    elfcpp::SHN_UNDEF,    // large_common_shndx
    0,                    // small_common_section_flags
    0,                    // large_common_section_flags
    NULL,                 // attributes_section
    NULL,                 // attributes_vendor
    "_start",		// entry_symbol_name
    32,			// hash_entry_size
    elfcpp::SHT_PROGBITS,	// unwind_section_type
  };
  
  template<>
  const Target::Target_info Target_tilegx<32, false>::tilegx_info =
  {
    32,                   // size
    false,                // is_big_endian
    elfcpp::EM_TILEGX,    // machine_code
    false,                // has_make_symbol
    false,                // has_resolve
    false,                // has_code_fill
    true,                 // is_default_stack_executable
    false,                // can_icf_inline_merge_sections
    '\0',                 // wrap_char
    "/lib32/ld.so.1",     // program interpreter
    0x10000,              // default_text_segment_address
    0x10000,              // abi_pagesize (overridable by -z max-page-size)
    0x10000,              // common_pagesize (overridable by -z common-page-size)
    false,                // isolate_execinstr
    0,                    // rosegment_gap
    elfcpp::SHN_UNDEF,    // small_common_shndx
    elfcpp::SHN_UNDEF,    // large_common_shndx
    0,                    // small_common_section_flags
    0,                    // large_common_section_flags
    NULL,                 // attributes_section
    NULL,                 // attributes_vendor
    "_start",		// entry_symbol_name
    32,			// hash_entry_size
    elfcpp::SHT_PROGBITS,	// unwind_section_type
  };
  
  template<>
  const Target::Target_info Target_tilegx<64, true>::tilegx_info =
  {
    64,                   // size
    true,                 // is_big_endian
    elfcpp::EM_TILEGX,    // machine_code
    false,                // has_make_symbol
    false,                // has_resolve
    false,                // has_code_fill
    true,                 // is_default_stack_executable
    false,                // can_icf_inline_merge_sections
    '\0',                 // wrap_char
    "/lib/ld.so.1",       // program interpreter
    0x10000,              // default_text_segment_address
    0x10000,              // abi_pagesize (overridable by -z max-page-size)
    0x10000,              // common_pagesize (overridable by -z common-page-size)
    false,                // isolate_execinstr
    0,                    // rosegment_gap
    elfcpp::SHN_UNDEF,    // small_common_shndx
    elfcpp::SHN_UNDEF,    // large_common_shndx
    0,                    // small_common_section_flags
    0,                    // large_common_section_flags
    NULL,                 // attributes_section
    NULL,                 // attributes_vendor
    "_start",		// entry_symbol_name
    32,			// hash_entry_size
    elfcpp::SHT_PROGBITS,	// unwind_section_type
  };
  
  template<>
  const Target::Target_info Target_tilegx<32, true>::tilegx_info =
  {
    32,                   // size
    true,                 // is_big_endian
    elfcpp::EM_TILEGX,    // machine_code
    false,                // has_make_symbol
    false,                // has_resolve
    false,                // has_code_fill
    true,                 // is_default_stack_executable
    false,                // can_icf_inline_merge_sections
    '\0',                 // wrap_char
    "/lib32/ld.so.1",     // program interpreter
    0x10000,              // default_text_segment_address
    0x10000,              // abi_pagesize (overridable by -z max-page-size)
    0x10000,              // common_pagesize (overridable by -z common-page-size)
    false,                // isolate_execinstr
    0,                    // rosegment_gap
    elfcpp::SHN_UNDEF,    // small_common_shndx
    elfcpp::SHN_UNDEF,    // large_common_shndx
    0,                    // small_common_section_flags
    0,                    // large_common_section_flags
    NULL,                 // attributes_section
    NULL,                  // attributes_vendor
    "_start",		// entry_symbol_name
    32,			// hash_entry_size
    elfcpp::SHT_PROGBITS,	// unwind_section_type
  };
  
  // tilegx relocation handlers
  template<int size, bool big_endian>
  class Tilegx_relocate_functions
  {
  public:
    // overflow check will be supported later
    typedef enum
    {
      STATUS_OKAY,        // No error during relocation.
      STATUS_OVERFLOW,    // Relocation overflow.
      STATUS_BAD_RELOC    // Relocation cannot be applied.
    } Status;
  
    struct Tilegx_howto
    {
      // right shift operand by this number of bits.
      unsigned char srshift;
  
      // the offset to apply relocation.
      unsigned char doffset;
  
      // set to 1 for pc-relative relocation.
      unsigned char is_pcrel;
  
      // size in bits, or 0 if this table entry should be ignored.
      unsigned char bsize;
  
      // whether we need to check overflow.
      unsigned char overflow;
    };
  
    static const Tilegx_howto howto[elfcpp::R_TILEGX_NUM];
  
  private:
  
    // Do a simple rela relocation
    template<int valsize>
    static inline void
    rela(unsigned char* view,
         const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         typename elfcpp::Swap<size, big_endian>::Valtype addend,
         elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
         elfcpp::Elf_Xword bitmask)
    {
      typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
      Valtype* wv = reinterpret_cast<Valtype*>(view);
      Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
      Valtype reloc = 0;
      if (size == 32)
        reloc = Bits<32>::sign_extend(psymval->value(object, addend)) >> srshift;
      else
        reloc = psymval->value(object, addend) >> srshift;
  
      elfcpp::Elf_Xword dst_mask = bitmask << doffset;
  
      val &= ~dst_mask;
      reloc &= bitmask;
  
      elfcpp::Swap<valsize, big_endian>::writeval(wv, val | (reloc<<doffset));
    }
  
    // Do a simple rela relocation
    template<int valsize>
    static inline void
    rela_ua(unsigned char* view,
            const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Swap<size, big_endian>::Valtype addend,
            elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
            elfcpp::Elf_Xword bitmask)
    {
      typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
        Valtype;
      unsigned char* wv = view;
      Valtype val = elfcpp::Swap_unaligned<valsize, big_endian>::readval(wv);
      Valtype reloc = 0;
      if (size == 32)
        reloc = Bits<32>::sign_extend(psymval->value(object, addend)) >> srshift;
      else
        reloc = psymval->value(object, addend) >> srshift;
  
      elfcpp::Elf_Xword dst_mask = bitmask << doffset;
  
      val &= ~dst_mask;
      reloc &= bitmask;
  
      elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv,
        val | (reloc<<doffset));
    }
  
    template<int valsize>
    static inline void
    rela(unsigned char* view,
         const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         typename elfcpp::Swap<size, big_endian>::Valtype addend,
         elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset1,
         elfcpp::Elf_Xword bitmask1, elfcpp::Elf_Xword doffset2,
         elfcpp::Elf_Xword bitmask2)
    {
      typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
      Valtype* wv = reinterpret_cast<Valtype*>(view);
      Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
      Valtype reloc = 0;
      if (size == 32)
        reloc = Bits<32>::sign_extend(psymval->value(object, addend)) >> srshift;
      else
        reloc = psymval->value(object, addend) >> srshift;
  
      elfcpp::Elf_Xword dst_mask = (bitmask1 << doffset1)
                                    | (bitmask2 << doffset2);
      val &= ~dst_mask;
      reloc = ((reloc & bitmask1) << doffset1)
               | ((reloc & bitmask2) << doffset2);
  
      elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
  
    }
  
    // Do a simple PC relative relocation with a Symbol_value with the
    // addend in the relocation.
    template<int valsize>
    static inline void
    pcrela(unsigned char* view,
           const Sized_relobj_file<size, big_endian>* object,
           const Symbol_value<size>* psymval,
           typename elfcpp::Swap<size, big_endian>::Valtype addend,
           typename elfcpp::Elf_types<size>::Elf_Addr address,
           elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
           elfcpp::Elf_Xword bitmask)
  
    {
      typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
      Valtype* wv = reinterpret_cast<Valtype*>(view);
      Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
      Valtype reloc = 0;
      if (size == 32)
        reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
                 >> srshift;
      else
        reloc = (psymval->value(object, addend) - address) >> srshift;
  
      elfcpp::Elf_Xword dst_mask = bitmask << doffset;
      val &= ~dst_mask;
      reloc &= bitmask;
  
      elfcpp::Swap<valsize, big_endian>::writeval(wv, val | (reloc<<doffset));
    }
  
    template<int valsize>
    static inline void
    pcrela_ua(unsigned char* view,
             const Sized_relobj_file<size, big_endian>* object,
             const Symbol_value<size>* psymval,
             typename elfcpp::Swap<size, big_endian>::Valtype addend,
             typename elfcpp::Elf_types<size>::Elf_Addr address,
             elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset,
             elfcpp::Elf_Xword bitmask)
  
    {
      typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
        Valtype;
      unsigned char* wv = view;
      Valtype reloc = 0;
      if (size == 32)
        reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
                 >> srshift;
      else
        reloc = (psymval->value(object, addend) - address) >> srshift;
  
      reloc &= bitmask;
  
      elfcpp::Swap<valsize, big_endian>::writeval(wv, reloc << doffset);
    }
  
    template<int valsize>
    static inline void
    pcrela(unsigned char* view,
           const Sized_relobj_file<size, big_endian>* object,
           const Symbol_value<size>* psymval,
           typename elfcpp::Swap<size, big_endian>::Valtype addend,
           typename elfcpp::Elf_types<size>::Elf_Addr address,
           elfcpp::Elf_Xword srshift, elfcpp::Elf_Xword doffset1,
           elfcpp::Elf_Xword bitmask1, elfcpp::Elf_Xword doffset2,
           elfcpp::Elf_Xword bitmask2)
  
    {
      typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
      Valtype* wv = reinterpret_cast<Valtype*>(view);
      Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
      Valtype reloc = 0;
      if (size == 32)
        reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
                 >> srshift;
      else
        reloc = (psymval->value(object, addend) - address) >> srshift;
  
      elfcpp::Elf_Xword dst_mask = (bitmask1 << doffset1)
                                    | (bitmask2 << doffset2);
      val &= ~dst_mask;
      reloc = ((reloc & bitmask1) << doffset1)
               | ((reloc & bitmask2) << doffset2);
  
      elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
    }
  
    typedef Tilegx_relocate_functions<size, big_endian> This;
    typedef Relocate_functions<size, big_endian> Base;
  
  public:
  
    static inline void
    abs64(unsigned char* view,
          const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend)
    {
      This::template rela_ua<64>(view, object, psymval, addend, 0, 0,
                                 0xffffffffffffffffllu);
    }
  
    static inline void
    abs32(unsigned char* view,
          const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend)
    {
      This::template rela_ua<32>(view, object, psymval, addend, 0, 0,
                                 0xffffffff);
    }
  
    static inline void
    abs16(unsigned char* view,
          const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend)
    {
      This::template rela_ua<16>(view, object, psymval, addend, 0, 0,
                                 0xffff);
    }
  
    static inline void
    pc_abs64(unsigned char* view,
          const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
  	    typename elfcpp::Elf_types<size>::Elf_Addr address)
    {
      This::template pcrela_ua<64>(view, object, psymval, addend, address, 0, 0,
                                 0xffffffffffffffffllu);
    }
  
    static inline void
    pc_abs32(unsigned char* view,
          const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
  	    typename elfcpp::Elf_types<size>::Elf_Addr address)
    {
      This::template pcrela_ua<32>(view, object, psymval, addend, address, 0, 0,
                                   0xffffffff);
    }
  
    static inline void
    pc_abs16(unsigned char* view,
          const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
  	    typename elfcpp::Elf_types<size>::Elf_Addr address)
    {
      This::template pcrela_ua<16>(view, object, psymval, addend, address, 0, 0,
                                   0xffff);
    }
  
    static inline void
    imm_x_general(unsigned char* view,
                  const Sized_relobj_file<size, big_endian>* object,
                  const Symbol_value<size>* psymval,
                  typename elfcpp::Elf_types<size>::Elf_Addr addend,
                  Tilegx_howto &r_howto)
    {
      This::template rela<64>(view, object, psymval, addend,
                              (elfcpp::Elf_Xword)(r_howto.srshift),
                              (elfcpp::Elf_Xword)(r_howto.doffset),
                              (elfcpp::Elf_Xword)((1 << r_howto.bsize) - 1));
    }
  
    static inline void
    imm_x_pcrel_general(unsigned char* view,
                        const Sized_relobj_file<size, big_endian>* object,
                        const Symbol_value<size>* psymval,
                        typename elfcpp::Elf_types<size>::Elf_Addr addend,
                        typename elfcpp::Elf_types<size>::Elf_Addr address,
                        Tilegx_howto &r_howto)
    {
      This::template pcrela<64>(view, object, psymval, addend, address,
                                (elfcpp::Elf_Xword)(r_howto.srshift),
                                (elfcpp::Elf_Xword)(r_howto.doffset),
                                (elfcpp::Elf_Xword)((1 << r_howto.bsize) - 1));
    }
  
    static inline void
    imm_x_two_part_general(unsigned char* view,
                           const Sized_relobj_file<size, big_endian>* object,
                           const Symbol_value<size>* psymval,
                           typename elfcpp::Elf_types<size>::Elf_Addr addend,
                           typename elfcpp::Elf_types<size>::Elf_Addr address,
                           unsigned int r_type)
    {
  
      elfcpp::Elf_Xword doffset1 = 0llu;
      elfcpp::Elf_Xword doffset2 = 0llu;
      elfcpp::Elf_Xword dmask1   = 0llu;
      elfcpp::Elf_Xword dmask2   = 0llu;
      elfcpp::Elf_Xword rshift   = 0llu;
      unsigned int pc_rel        = 0;
  
      switch (r_type)
        {
        case elfcpp::R_TILEGX_BROFF_X1:
          doffset1 = 31llu;
          doffset2 = 37llu;
          dmask1   = 0x3fllu;
          dmask2   = 0x1ffc0llu;
          rshift   = 3llu;
          pc_rel   = 1;
          break;
        case elfcpp::R_TILEGX_DEST_IMM8_X1:
          doffset1 = 31llu;
          doffset2 = 43llu;
          dmask1   = 0x3fllu;
          dmask2   = 0xc0llu;
          rshift   = 0llu;
          break;
        }
  
      if (pc_rel)
        This::template pcrela<64>(view, object, psymval, addend, address,
                                  rshift, doffset1, dmask1, doffset2, dmask2);
      else
        This::template rela<64>(view, object, psymval, addend, rshift,
                                doffset1, dmask1, doffset2, dmask2);
  
    }
  
    static inline void
    tls_relax(unsigned char* view, unsigned int r_type,
              tls::Tls_optimization opt_t)
    {
  
      const uint64_t TILEGX_X_MOVE_R0_R0 = 0x283bf8005107f000llu;
      const uint64_t TILEGX_Y_MOVE_R0_R0 = 0xae05f800540bf000llu;
      const uint64_t TILEGX_X_LD         = 0x286ae80000000000llu;
      const uint64_t TILEGX_X_LD4S       = 0x286a980000000000llu;
      const uint64_t TILEGX_X1_FULL_MASK = 0x3fffffff80000000llu;
      const uint64_t TILEGX_X0_RRR_MASK  = 0x000000007ffc0000llu;
      const uint64_t TILEGX_X1_RRR_MASK  = 0x3ffe000000000000llu;
      const uint64_t TILEGX_Y0_RRR_MASK  = 0x00000000780c0000llu;
      const uint64_t TILEGX_Y1_RRR_MASK  = 0x3c06000000000000llu;
      const uint64_t TILEGX_X0_RRR_SRCB_MASK = 0x000000007ffff000llu;
      const uint64_t TILEGX_X1_RRR_SRCB_MASK = 0x3ffff80000000000llu;
      const uint64_t TILEGX_Y0_RRR_SRCB_MASK = 0x00000000780ff000llu;
      const uint64_t TILEGX_Y1_RRR_SRCB_MASK = 0x3c07f80000000000llu;
      const uint64_t TILEGX_X_ADD_R0_R0_TP   = 0x2807a800500f5000llu;
      const uint64_t TILEGX_Y_ADD_R0_R0_TP   = 0x9a13a8002c275000llu;
      const uint64_t TILEGX_X_ADDX_R0_R0_TP  = 0x2805a800500b5000llu;
      const uint64_t TILEGX_Y_ADDX_R0_R0_TP  = 0x9a01a8002c035000llu;
  
      const uint64_t R_TILEGX_IMM8_X0_TLS_ADD_MASK =
        (TILEGX_X0_RRR_MASK | (0x3Fllu << 12));
  
      const uint64_t R_TILEGX_IMM8_X1_TLS_ADD_MASK =
        (TILEGX_X1_RRR_MASK | (0x3Fllu << 43));
  
      const uint64_t R_TILEGX_IMM8_Y0_TLS_ADD_MASK =
        (TILEGX_Y0_RRR_MASK | (0x3Fllu << 12));
  
      const uint64_t R_TILEGX_IMM8_Y1_TLS_ADD_MASK =
        (TILEGX_Y1_RRR_MASK | (0x3Fllu << 43));
  
      const uint64_t R_TILEGX_IMM8_X0_TLS_ADD_LE_MASK =
        (TILEGX_X0_RRR_SRCB_MASK | (0x3Fllu << 6));
  
      const uint64_t R_TILEGX_IMM8_X1_TLS_ADD_LE_MASK =
        (TILEGX_X1_RRR_SRCB_MASK | (0x3Fllu << 37));
  
      const uint64_t R_TILEGX_IMM8_Y0_TLS_ADD_LE_MASK =
        (TILEGX_Y0_RRR_SRCB_MASK | (0x3Fllu << 6));
  
      const uint64_t R_TILEGX_IMM8_Y1_TLS_ADD_LE_MASK =
        (TILEGX_Y1_RRR_SRCB_MASK | (0x3Fllu << 37));
  
      typedef typename elfcpp::Swap<64, big_endian>::Valtype Valtype;
      Valtype* wv = reinterpret_cast<Valtype*>(view);
      Valtype val = elfcpp::Swap<64, big_endian>::readval(wv);
      Valtype reloc = 0;
  
      switch (r_type)
      {
        case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            // GD/IE: 1. copy dest operand into the second source operand
            //        2. change the opcode to "add"
            reloc = (val & 0x3Fllu) << 12;  // featch the dest reg
            reloc |= ((size == 32
                       ? TILEGX_X_ADDX_R0_R0_TP
                       : TILEGX_X_ADD_R0_R0_TP)
                      & TILEGX_X0_RRR_MASK);  // change opcode
            val &= ~R_TILEGX_IMM8_X0_TLS_ADD_MASK;
          } else if (opt_t == tls::TLSOPT_TO_LE) {
            // LE: 1. copy dest operand into the first source operand
            //     2. change the opcode to "move"
            reloc = (val & 0x3Fllu) << 6;
            reloc |= (TILEGX_X_MOVE_R0_R0 & TILEGX_X0_RRR_SRCB_MASK);
            val &= ~R_TILEGX_IMM8_X0_TLS_ADD_LE_MASK;
          } else
            gold_unreachable();
          break;
        case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            reloc = (val & (0x3Fllu << 31)) << 12;
            reloc |= ((size == 32
                       ? TILEGX_X_ADDX_R0_R0_TP
                       : TILEGX_X_ADD_R0_R0_TP)
                      & TILEGX_X1_RRR_MASK);
            val &= ~R_TILEGX_IMM8_X1_TLS_ADD_MASK;
          } else if (opt_t == tls::TLSOPT_TO_LE) {
            reloc = (val & (0x3Fllu << 31)) << 6;
            reloc |= (TILEGX_X_MOVE_R0_R0 & TILEGX_X1_RRR_SRCB_MASK);
            val &= ~R_TILEGX_IMM8_X1_TLS_ADD_LE_MASK;
          } else
            gold_unreachable();
          break;
        case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            reloc = (val & 0x3Fllu) << 12;
            reloc |= ((size == 32
                       ? TILEGX_Y_ADDX_R0_R0_TP
                       : TILEGX_Y_ADD_R0_R0_TP)
                      & TILEGX_Y0_RRR_MASK);
            val &= ~R_TILEGX_IMM8_Y0_TLS_ADD_MASK;
          } else if (opt_t == tls::TLSOPT_TO_LE) {
            reloc = (val & 0x3Fllu) << 6;
            reloc |= (TILEGX_Y_MOVE_R0_R0 & TILEGX_Y0_RRR_SRCB_MASK);
            val &= ~R_TILEGX_IMM8_Y0_TLS_ADD_LE_MASK;
          } else
            gold_unreachable();
          break;
        case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            reloc = (val & (0x3Fllu << 31)) << 12;
            reloc |= ((size == 32
                       ? TILEGX_Y_ADDX_R0_R0_TP
                       : TILEGX_Y_ADD_R0_R0_TP)
                      & TILEGX_Y1_RRR_MASK);
            val &= ~R_TILEGX_IMM8_Y1_TLS_ADD_MASK;
          } else if (opt_t == tls::TLSOPT_TO_LE) {
            reloc = (val & (0x3Fllu << 31)) << 6;
            reloc |= (TILEGX_Y_MOVE_R0_R0 & TILEGX_Y1_RRR_SRCB_MASK);
            val &= ~R_TILEGX_IMM8_Y1_TLS_ADD_LE_MASK;
          } else
            gold_unreachable();
          break;
        case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            // GD see comments for optimize_tls_reloc
            reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X0_RRR_SRCB_MASK;
            val &= ~TILEGX_X0_RRR_SRCB_MASK;
          } else if (opt_t == tls::TLSOPT_TO_IE
                     || opt_t == tls::TLSOPT_TO_LE) {
            // IE/LE
            reloc = (size == 32
                     ? TILEGX_X_ADDX_R0_R0_TP
                     : TILEGX_X_ADD_R0_R0_TP)
                     & TILEGX_X0_RRR_SRCB_MASK;
            val &= ~TILEGX_X0_RRR_SRCB_MASK;
          }
          break;
        case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X1_RRR_SRCB_MASK;
            val &= ~TILEGX_X1_RRR_SRCB_MASK;
          } else if (opt_t == tls::TLSOPT_TO_IE
                     || opt_t == tls::TLSOPT_TO_LE) {
            reloc = (size == 32
                     ? TILEGX_X_ADDX_R0_R0_TP
                     : TILEGX_X_ADD_R0_R0_TP)
                     & TILEGX_X1_RRR_SRCB_MASK;
            val &= ~TILEGX_X1_RRR_SRCB_MASK;
          }
          break;
        case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            reloc = TILEGX_Y_MOVE_R0_R0 & TILEGX_Y0_RRR_SRCB_MASK;
            val &= ~TILEGX_Y0_RRR_SRCB_MASK;
          } else if (opt_t == tls::TLSOPT_TO_IE
                     || opt_t == tls::TLSOPT_TO_LE) {
            reloc = (size == 32
                     ? TILEGX_Y_ADDX_R0_R0_TP
                     : TILEGX_Y_ADD_R0_R0_TP)
                     & TILEGX_Y0_RRR_SRCB_MASK;
            val &= ~TILEGX_Y0_RRR_SRCB_MASK;
          }
          break;
        case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
          if (opt_t == tls::TLSOPT_NONE) {
            reloc = TILEGX_Y_MOVE_R0_R0 & TILEGX_Y1_RRR_SRCB_MASK;
            val &= ~TILEGX_Y1_RRR_SRCB_MASK;
          } else if (opt_t == tls::TLSOPT_TO_IE
                     || opt_t == tls::TLSOPT_TO_LE) {
            reloc = (size == 32
                     ? TILEGX_Y_ADDX_R0_R0_TP
                     : TILEGX_Y_ADD_R0_R0_TP)
                     & TILEGX_Y1_RRR_SRCB_MASK;
            val &= ~TILEGX_Y1_RRR_SRCB_MASK;
          }
          break;
        case elfcpp::R_TILEGX_TLS_IE_LOAD:
          if (opt_t == tls::TLSOPT_NONE) {
            // IE
            reloc = (size == 32
                     ? TILEGX_X_LD4S
                     : TILEGX_X_LD)
                     & TILEGX_X1_RRR_SRCB_MASK;
            val &= ~TILEGX_X1_RRR_SRCB_MASK;
          } else if (opt_t == tls::TLSOPT_TO_LE) {
            // LE
            reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X1_RRR_SRCB_MASK;
            val &= ~TILEGX_X1_RRR_SRCB_MASK;
          } else
            gold_unreachable();
          break;
        case elfcpp::R_TILEGX_TLS_GD_CALL:
          if (opt_t == tls::TLSOPT_TO_IE) {
            // ld/ld4s r0, r0
            reloc = (size == 32
                    ? TILEGX_X_LD4S
                    : TILEGX_X_LD) & TILEGX_X1_FULL_MASK;
            val &= ~TILEGX_X1_FULL_MASK;
          } else if (opt_t == tls::TLSOPT_TO_LE) {
            // move r0, r0
            reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X1_FULL_MASK;
            val &= ~TILEGX_X1_FULL_MASK;
          } else
            // should be handled in ::relocate
            gold_unreachable();
          break;
        default:
          gold_unreachable();
          break;
      }
      elfcpp::Swap<64, big_endian>::writeval(wv, val | reloc);
    }
  };
  
  template<>
  const Tilegx_relocate_functions<64, false>::Tilegx_howto
  Tilegx_relocate_functions<64, false>::howto[elfcpp::R_TILEGX_NUM] =
  {
    {  0,  0, 0,  0, 0}, // R_TILEGX_NONE
    {  0,  0, 0, 64, 0}, // R_TILEGX_64
    {  0,  0, 0, 32, 0}, // R_TILEGX_32
    {  0,  0, 0, 16, 0}, // R_TILEGX_16
    {  0,  0, 0,  8, 0}, // R_TILEGX_8
    {  0,  0, 1, 64, 0}, // R_TILEGX_64_PCREL
    {  0,  0, 1, 32, 0}, // R_TILEGX_32_PCREL
    {  0,  0, 1, 16, 0}, // R_TILEGX_16_PCREL
    {  0,  0, 1,  8, 0}, // R_TILEGX_8_PCREL
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1
    { 32,  0, 0,  0, 0}, // R_TILEGX_HW2
    { 48,  0, 0,  0, 0}, // R_TILEGX_HW3
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0_LAST
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1_LAST
    { 32,  0, 0,  0, 0}, // R_TILEGX_HW2_LAST
    {  0,  0, 0,  0, 0}, // R_TILEGX_COPY
    {  0,  0, 0,  8, 0}, // R_TILEGX_GLOB_DAT
    {  0,  0, 0,  0, 0}, // R_TILEGX_JMP_SLOT
    {  0,  0, 0,  0, 0}, // R_TILEGX_RELATIVE
    {  3,  1, 1,  0, 0}, // R_TILEGX_BROFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y1
    {  0,  1, 0,  8, 0}, // R_TILEGX_DEST_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MT_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MF_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMSTART_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMEND_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y1
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
    { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
    { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
    { 32, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
    { 32, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
    { 48, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
    { 48, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
    { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
    { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
    { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
    { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
    { 48, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
    { 48, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
    { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
    { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
    { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
    { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
    { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
    { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IRELATIVE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
    { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
    { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF32
    {  3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_IE_LOAD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTINHERIT
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTENTRY
  };
  
  template<>
  const Tilegx_relocate_functions<32, false>::Tilegx_howto
  Tilegx_relocate_functions<32, false>::howto[elfcpp::R_TILEGX_NUM] =
  {
    {  0,  0, 0,  0, 0}, // R_TILEGX_NONE
    {  0,  0, 0, 64, 0}, // R_TILEGX_64
    {  0,  0, 0, 32, 0}, // R_TILEGX_32
    {  0,  0, 0, 16, 0}, // R_TILEGX_16
    {  0,  0, 0,  8, 0}, // R_TILEGX_8
    {  0,  0, 1, 64, 0}, // R_TILEGX_64_PCREL
    {  0,  0, 1, 32, 0}, // R_TILEGX_32_PCREL
    {  0,  0, 1, 16, 0}, // R_TILEGX_16_PCREL
    {  0,  0, 1,  8, 0}, // R_TILEGX_8_PCREL
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1
    { 31,  0, 0,  0, 0}, // R_TILEGX_HW2
    { 31,  0, 0,  0, 0}, // R_TILEGX_HW3
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0_LAST
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1_LAST
    { 31,  0, 0,  0, 0}, // R_TILEGX_HW2_LAST
    {  0,  0, 0,  0, 0}, // R_TILEGX_COPY
    {  0,  0, 0,  8, 0}, // R_TILEGX_GLOB_DAT
    {  0,  0, 0,  0, 0}, // R_TILEGX_JMP_SLOT
    {  0,  0, 0,  0, 0}, // R_TILEGX_RELATIVE
    {  3,  1, 1,  0, 0}, // R_TILEGX_BROFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y1
    {  0,  1, 0,  8, 0}, // R_TILEGX_DEST_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MT_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MF_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMSTART_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMEND_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y1
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
    { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
    { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
    { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
    { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
    { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
    { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
    { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
    { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
    { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
    { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
    { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
    { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
    { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
    { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
    { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
    { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
    { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
    { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IRELATIVE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
    { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
    { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF32
    {  3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_IE_LOAD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTINHERIT
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTENTRY
  };
  
  template<>
  const Tilegx_relocate_functions<64, true>::Tilegx_howto
  Tilegx_relocate_functions<64, true>::howto[elfcpp::R_TILEGX_NUM] =
  {
    {  0,  0, 0,  0, 0}, // R_TILEGX_NONE
    {  0,  0, 0, 64, 0}, // R_TILEGX_64
    {  0,  0, 0, 32, 0}, // R_TILEGX_32
    {  0,  0, 0, 16, 0}, // R_TILEGX_16
    {  0,  0, 0,  8, 0}, // R_TILEGX_8
    {  0,  0, 1, 64, 0}, // R_TILEGX_64_PCREL
    {  0,  0, 1, 32, 0}, // R_TILEGX_32_PCREL
    {  0,  0, 1, 16, 0}, // R_TILEGX_16_PCREL
    {  0,  0, 1,  8, 0}, // R_TILEGX_8_PCREL
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1
    { 32,  0, 0,  0, 0}, // R_TILEGX_HW2
    { 48,  0, 0,  0, 0}, // R_TILEGX_HW3
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0_LAST
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1_LAST
    { 32,  0, 0,  0, 0}, // R_TILEGX_HW2_LAST
    {  0,  0, 0,  0, 0}, // R_TILEGX_COPY
    {  0,  0, 0,  8, 0}, // R_TILEGX_GLOB_DAT
    {  0,  0, 0,  0, 0}, // R_TILEGX_JMP_SLOT
    {  0,  0, 0,  0, 0}, // R_TILEGX_RELATIVE
    {  3,  1, 1,  0, 0}, // R_TILEGX_BROFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y1
    {  0,  1, 0,  8, 0}, // R_TILEGX_DEST_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MT_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MF_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMSTART_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMEND_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y1
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
    { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
    { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
    { 32, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
    { 32, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
    { 48, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
    { 48, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
    { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
    { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
    { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
    { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
    { 48, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
    { 48, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
    { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
    { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
    { 32, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
    { 32, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
    { 32, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
    { 32, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IRELATIVE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
    { 32, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
    { 32, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF32
    {  3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_IE_LOAD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTINHERIT
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTENTRY
  };
  
  template<>
  const Tilegx_relocate_functions<32, true>::Tilegx_howto
  Tilegx_relocate_functions<32, true>::howto[elfcpp::R_TILEGX_NUM] =
  {
    {  0,  0, 0,  0, 0}, // R_TILEGX_NONE
    {  0,  0, 0, 64, 0}, // R_TILEGX_64
    {  0,  0, 0, 32, 0}, // R_TILEGX_32
    {  0,  0, 0, 16, 0}, // R_TILEGX_16
    {  0,  0, 0,  8, 0}, // R_TILEGX_8
    {  0,  0, 1, 64, 0}, // R_TILEGX_64_PCREL
    {  0,  0, 1, 32, 0}, // R_TILEGX_32_PCREL
    {  0,  0, 1, 16, 0}, // R_TILEGX_16_PCREL
    {  0,  0, 1,  8, 0}, // R_TILEGX_8_PCREL
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1
    { 31,  0, 0,  0, 0}, // R_TILEGX_HW2
    { 31,  0, 0,  0, 0}, // R_TILEGX_HW3
    {  0,  0, 0,  0, 0}, // R_TILEGX_HW0_LAST
    { 16,  0, 0,  0, 0}, // R_TILEGX_HW1_LAST
    { 31,  0, 0,  0, 0}, // R_TILEGX_HW2_LAST
    {  0,  0, 0,  0, 0}, // R_TILEGX_COPY
    {  0,  0, 0,  8, 0}, // R_TILEGX_GLOB_DAT
    {  0,  0, 0,  0, 0}, // R_TILEGX_JMP_SLOT
    {  0,  0, 0,  0, 0}, // R_TILEGX_RELATIVE
    {  3,  1, 1,  0, 0}, // R_TILEGX_BROFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1
    {  3, 31, 1, 27, 0}, // R_TILEGX_JUMPOFF_X1_PLT
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_IMM8_Y1
    {  0,  1, 0,  8, 0}, // R_TILEGX_DEST_IMM8_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MT_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MF_IMM14_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMSTART_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_MMEND_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_X1
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y0
    {  0,  1, 0,  8, 0}, // R_TILEGX_SHAMT_Y1
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0
    { 16, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW1
    { 16, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW1
    { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW2
    { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW2
    { 31, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW3
    { 31, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW3
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST
    { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST
    { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PCREL
    { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PCREL
    { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PCREL
    { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW3_PCREL
    { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW3_PCREL
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PCREL
    { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PCREL
    { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PCREL
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_GOT
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_GOT
    {  0, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW0_PLT_PCREL
    {  0, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW0_PLT_PCREL
    { 16, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW1_PLT_PCREL
    { 16, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW1_PLT_PCREL
    { 31, 12, 1, 16, 0}, // R_TILEGX_IMM16_X0_HW2_PLT_PCREL
    { 31, 43, 1, 16, 0}, // R_TILEGX_IMM16_X1_HW2_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_GOT
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_GOT
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_GOT
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_GOT
    { 31, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_GOT
    { 31, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_GOT
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_GD
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_GD
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_LE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IRELATIVE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0, 12, 0, 16, 0}, // R_TILEGX_IMM16_X0_HW0_TLS_IE
    {  0, 43, 0, 16, 0}, // R_TILEGX_IMM16_X1_HW0_TLS_IE
    {  0, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL
    {  0, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL
    { 16, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL
    { 16, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL
    { 31, 12, 1, 16, 1}, // R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL
    { 31, 43, 1, 16, 1}, // R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL
    {  0, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE
    {  0, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE
    { 16, 12, 0, 16, 1}, // R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE
    { 16, 43, 0, 16, 1}, // R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_INVALID
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF64
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPMOD32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_DTPOFF32
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_TPOFF32
    {  3, 31, 1, 27, 0}, // R_TILEGX_TLS_GD_CALL
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_GD_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_TLS_IE_LOAD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_X1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y0_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_IMM8_Y1_TLS_ADD
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTINHERIT
    {  0,  0, 0,  0, 0}, // R_TILEGX_GNU_VTENTRY
  };
  
  // Get the GOT section, creating it if necessary.
  
  template<int size, bool big_endian>
  Output_data_got<size, big_endian>*
  Target_tilegx<size, big_endian>::got_section(Symbol_table* symtab,
                                               Layout* layout)
  {
    if (this->got_ == NULL)
      {
        gold_assert(symtab != NULL && layout != NULL);
  
        // When using -z now, we can treat .got.plt as a relro section.
        // Without -z now, it is modified after program startup by lazy
        // PLT relocations.
        bool is_got_plt_relro = parameters->options().now();
        Output_section_order got_order = (is_got_plt_relro
                                          ? ORDER_RELRO
                                          : ORDER_RELRO_LAST);
        Output_section_order got_plt_order = (is_got_plt_relro
                                              ? ORDER_RELRO
                                              : ORDER_NON_RELRO_FIRST);
  
        this->got_ = new Output_data_got<size, big_endian>();
  
        layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                        (elfcpp::SHF_ALLOC
                                         | elfcpp::SHF_WRITE),
                                        this->got_, got_order, true);
  
        // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
        this->global_offset_table_ =
          symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
                                        Symbol_table::PREDEFINED,
                                        this->got_,
                                        0, 0, elfcpp::STT_OBJECT,
                                        elfcpp::STB_LOCAL,
                                        elfcpp::STV_HIDDEN, 0,
                                        false, false);
  
        if (parameters->options().shared()) {
          // we need to keep the address of .dynamic section in the
          // first got entry for .so
          this->tilegx_dynamic_ =
            symtab->define_in_output_data("_TILEGX_DYNAMIC_", NULL,
                                          Symbol_table::PREDEFINED,
                                          layout->dynamic_section(),
                                          0, 0, elfcpp::STT_OBJECT,
                                          elfcpp::STB_LOCAL,
                                          elfcpp::STV_HIDDEN, 0,
                                          false, false);
  
          this->got_->add_global(this->tilegx_dynamic_, GOT_TYPE_STANDARD);
        } else
          // for executable, just set the first entry to zero.
          this->got_->set_current_data_size(size / 8);
  
        this->got_plt_ = new Output_data_space(size / 8, "** GOT PLT");
        layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
                                        (elfcpp::SHF_ALLOC
                                         | elfcpp::SHF_WRITE),
                                        this->got_plt_, got_plt_order,
                                        is_got_plt_relro);
  
        // The first two entries are reserved.
        this->got_plt_->set_current_data_size
               (TILEGX_GOTPLT_RESERVE_COUNT * (size / 8));
  
        if (!is_got_plt_relro)
          {
            // Those bytes can go into the relro segment.
            layout->increase_relro(size / 8);
          }
  
  
        // If there are any IRELATIVE relocations, they get GOT entries
        // in .got.plt after the jump slot entries.
        this->got_irelative_
           = new Output_data_space(size / 8, "** GOT IRELATIVE PLT");
        layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
                                        (elfcpp::SHF_ALLOC
                                         | elfcpp::SHF_WRITE),
                                        this->got_irelative_,
                                        got_plt_order, is_got_plt_relro);
      }
  
    return this->got_;
  }
  
  // Get the dynamic reloc section, creating it if necessary.
  
  template<int size, bool big_endian>
  typename Target_tilegx<size, big_endian>::Reloc_section*
  Target_tilegx<size, big_endian>::rela_dyn_section(Layout* layout)
  {
    if (this->rela_dyn_ == NULL)
      {
        gold_assert(layout != NULL);
        this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
        layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
                                        elfcpp::SHF_ALLOC, this->rela_dyn_,
                                        ORDER_DYNAMIC_RELOCS, false);
      }
    return this->rela_dyn_;
  }
  
  // Get the section to use for IRELATIVE relocs, creating it if
  // necessary.  These go in .rela.dyn, but only after all other dynamic
  // relocations.  They need to follow the other dynamic relocations so
  // that they can refer to global variables initialized by those
  // relocs.
  
  template<int size, bool big_endian>
  typename Target_tilegx<size, big_endian>::Reloc_section*
  Target_tilegx<size, big_endian>::rela_irelative_section(Layout* layout)
  {
    if (this->rela_irelative_ == NULL)
      {
        // Make sure we have already created the dynamic reloc section.
        this->rela_dyn_section(layout);
        this->rela_irelative_ = new Reloc_section(false);
        layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
                                        elfcpp::SHF_ALLOC, this->rela_irelative_,
                                        ORDER_DYNAMIC_RELOCS, false);
        gold_assert(this->rela_dyn_->output_section()
                    == this->rela_irelative_->output_section());
      }
    return this->rela_irelative_;
  }
  
  // Initialize the PLT section.
  
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::init(Layout* layout)
  {
    this->rel_ = new Reloc_section(false);
    layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
                                    elfcpp::SHF_ALLOC, this->rel_,
                                    ORDER_DYNAMIC_PLT_RELOCS, false);
  }
  
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::do_adjust_output_section(
    Output_section* os)
  {
    os->set_entsize(this->get_plt_entry_size());
  }
  
  // Add an entry to the PLT.
  
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::add_entry(Symbol_table* symtab,
    Layout* layout, Symbol* gsym)
  {
    gold_assert(!gsym->has_plt_offset());
  
    unsigned int plt_index;
    off_t plt_offset;
    section_offset_type got_offset;
  
    unsigned int* pcount;
    unsigned int reserved;
    Output_data_space* got;
    if (gsym->type() == elfcpp::STT_GNU_IFUNC
        && gsym->can_use_relative_reloc(false))
      {
        pcount = &this->irelative_count_;
        reserved = 0;
        got = this->got_irelative_;
      }
    else
      {
        pcount = &this->count_;
        reserved = TILEGX_GOTPLT_RESERVE_COUNT;
        got = this->got_plt_;
      }
  
    if (!this->is_data_size_valid())
      {
        plt_index = *pcount;
  
        // TILEGX .plt section layout
        //
        //  ----
        //   plt_header
        //  ----
        //   plt stub
        //  ----
        //   ...
        //  ----
        //
        // TILEGX .got.plt section layout
        //
        //  ----
        //  reserv1
        //  ----
        //  reserv2
        //  ----
        //   entries for normal function
        //  ----
        //   ...
        //  ----
        //   entries for ifunc
        //  ----
        //   ...
        //  ----
        if (got == this->got_irelative_)
          plt_offset = plt_index * this->get_plt_entry_size();
        else
          plt_offset = (plt_index + 1) * this->get_plt_entry_size();
  
        ++*pcount;
  
        got_offset = (plt_index + reserved) * (size / 8);
        gold_assert(got_offset == got->current_data_size());
  
        // Every PLT entry needs a GOT entry which points back to the PLT
        // entry (this will be changed by the dynamic linker, normally
        // lazily when the function is called).
        got->set_current_data_size(got_offset + size / 8);
      }
    else
      {
        // FIXME: This is probably not correct for IRELATIVE relocs.
  
        // For incremental updates, find an available slot.
        plt_offset = this->free_list_.allocate(this->get_plt_entry_size(),
                                               this->get_plt_entry_size(), 0);
        if (plt_offset == -1)
          gold_fallback(_("out of patch space (PLT);"
                          " relink with --incremental-full"));
  
        // The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
        // can be calculated from the PLT index, adjusting for the three
        // reserved entries at the beginning of the GOT.
        plt_index = plt_offset / this->get_plt_entry_size() - 1;
        got_offset = (plt_index + reserved) * (size / 8);
      }
  
    gsym->set_plt_offset(plt_offset);
  
    // Every PLT entry needs a reloc.
    this->add_relocation(symtab, layout, gsym, got_offset);
  
    // Note that we don't need to save the symbol.  The contents of the
    // PLT are independent of which symbols are used.  The symbols only
    // appear in the relocations.
  }
  
  // Add an entry to the PLT for a local STT_GNU_IFUNC symbol.  Return
  // the PLT offset.
  
  template<int size, bool big_endian>
  unsigned int
  Output_data_plt_tilegx<size, big_endian>::add_local_ifunc_entry(
      Symbol_table* symtab,
      Layout* layout,
      Sized_relobj_file<size, big_endian>* relobj,
      unsigned int local_sym_index)
  {
    unsigned int plt_offset =
      this->irelative_count_ * this->get_plt_entry_size();
    ++this->irelative_count_;
  
    section_offset_type got_offset = this->got_irelative_->current_data_size();
  
    // Every PLT entry needs a GOT entry which points back to the PLT
    // entry.
    this->got_irelative_->set_current_data_size(got_offset + size / 8);
  
    // Every PLT entry needs a reloc.
    Reloc_section* rela = this->rela_irelative(symtab, layout);
    rela->add_symbolless_local_addend(relobj, local_sym_index,
                                      elfcpp::R_TILEGX_IRELATIVE,
                                      this->got_irelative_, got_offset, 0);
  
    return plt_offset;
  }
  
  // Add the relocation for a PLT entry.
  
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::add_relocation(Symbol_table* symtab,
                                               Layout* layout,
                                               Symbol* gsym,
                                               unsigned int got_offset)
  {
    if (gsym->type() == elfcpp::STT_GNU_IFUNC
        && gsym->can_use_relative_reloc(false))
      {
        Reloc_section* rela = this->rela_irelative(symtab, layout);
        rela->add_symbolless_global_addend(gsym, elfcpp::R_TILEGX_IRELATIVE,
                                           this->got_irelative_, got_offset, 0);
      }
    else
      {
        gsym->set_needs_dynsym_entry();
        this->rel_->add_global(gsym, elfcpp::R_TILEGX_JMP_SLOT, this->got_plt_,
                               got_offset, 0);
      }
  }
  
  // Return where the IRELATIVE relocations should go in the PLT.  These
  // follow the JUMP_SLOT and the TLSDESC relocations.
  
  template<int size, bool big_endian>
  typename Output_data_plt_tilegx<size, big_endian>::Reloc_section*
  Output_data_plt_tilegx<size, big_endian>::rela_irelative(Symbol_table* symtab,
                                                           Layout* layout)
  {
    if (this->irelative_rel_ == NULL)
      {
        // case we see any later on.
        this->irelative_rel_ = new Reloc_section(false);
        layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
                                        elfcpp::SHF_ALLOC, this->irelative_rel_,
                                        ORDER_DYNAMIC_PLT_RELOCS, false);
        gold_assert(this->irelative_rel_->output_section()
                    == this->rel_->output_section());
  
        if (parameters->doing_static_link())
          {
            // A statically linked executable will only have a .rela.plt
            // section to hold R_TILEGX_IRELATIVE relocs for
            // STT_GNU_IFUNC symbols.  The library will use these
            // symbols to locate the IRELATIVE relocs at program startup
            // time.
            symtab->define_in_output_data("__rela_iplt_start", NULL,
                                          Symbol_table::PREDEFINED,
                                          this->irelative_rel_, 0, 0,
                                          elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
                                          elfcpp::STV_HIDDEN, 0, false, true);
            symtab->define_in_output_data("__rela_iplt_end", NULL,
                                          Symbol_table::PREDEFINED,
                                          this->irelative_rel_, 0, 0,
                                          elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
                                          elfcpp::STV_HIDDEN, 0, true, true);
          }
      }
    return this->irelative_rel_;
  }
  
  // Return the PLT address to use for a global symbol.
  
  template<int size, bool big_endian>
  uint64_t
  Output_data_plt_tilegx<size, big_endian>::address_for_global(
    const Symbol* gsym)
  {
    uint64_t offset = 0;
    if (gsym->type() == elfcpp::STT_GNU_IFUNC
        && gsym->can_use_relative_reloc(false))
      offset = (this->count_ + 1) * this->get_plt_entry_size();
    return this->address() + offset + gsym->plt_offset();
  }
  
  // Return the PLT address to use for a local symbol.  These are always
  // IRELATIVE relocs.
  
  template<int size, bool big_endian>
  uint64_t
  Output_data_plt_tilegx<size, big_endian>::address_for_local(
      const Relobj* object,
      unsigned int r_sym)
  {
    return (this->address()
  	  + (this->count_ + 1) * this->get_plt_entry_size()
  	  + object->local_plt_offset(r_sym));
  }
  
  // Set the final size.
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::set_final_data_size()
  {
    unsigned int count = this->count_ + this->irelative_count_;
    this->set_data_size((count + 1) * this->get_plt_entry_size());
  }
  
  // The first entry in the PLT for an executable.
  template<>
  const unsigned char
  Output_data_plt_tilegx<64, false>::first_plt_entry[plt_entry_size] =
  {
    0x00, 0x30, 0x48, 0x51,
    0x6e, 0x43, 0xa0, 0x18, // { ld_add r28, r27, 8 }
    0x00, 0x30, 0xbc, 0x35,
    0x00, 0x40, 0xde, 0x9e, // { ld r27, r27 }
    0xff, 0xaf, 0x30, 0x40,
    0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
    // padding
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00
  };
  
  template<>
  const unsigned char
  Output_data_plt_tilegx<32, false>::first_plt_entry[plt_entry_size] =
  {
    0x00, 0x30, 0x48, 0x51,
    0x6e, 0x23, 0x58, 0x18, // { ld4s_add r28, r27, 4 }
    0x00, 0x30, 0xbc, 0x35,
    0x00, 0x40, 0xde, 0x9c, // { ld4s r27, r27 }
    0xff, 0xaf, 0x30, 0x40,
    0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
    // padding
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00
  };
  
  template<>
  const unsigned char
  Output_data_plt_tilegx<64, true>::first_plt_entry[plt_entry_size] =
  {
    0x00, 0x30, 0x48, 0x51,
    0x6e, 0x43, 0xa0, 0x18, // { ld_add r28, r27, 8 }
    0x00, 0x30, 0xbc, 0x35,
    0x00, 0x40, 0xde, 0x9e, // { ld r27, r27 }
    0xff, 0xaf, 0x30, 0x40,
    0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
    // padding
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00
  };
  
  template<>
  const unsigned char
  Output_data_plt_tilegx<32, true>::first_plt_entry[plt_entry_size] =
  {
    0x00, 0x30, 0x48, 0x51,
    0x6e, 0x23, 0x58, 0x18, // { ld4s_add r28, r27, 4 }
    0x00, 0x30, 0xbc, 0x35,
    0x00, 0x40, 0xde, 0x9c, // { ld4s r27, r27 }
    0xff, 0xaf, 0x30, 0x40,
    0x60, 0x73, 0x6a, 0x28, // { info 10 ; jr r27 }
    // padding
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00
  };
  
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::fill_first_plt_entry(
    unsigned char* pov)
  {
    memcpy(pov, first_plt_entry, plt_entry_size);
  }
  
  // Subsequent entries in the PLT for an executable.
  
  template<>
  const unsigned char
  Output_data_plt_tilegx<64, false>::plt_entry[plt_entry_size] =
  {
    0xdc, 0x0f, 0x00, 0x10,
    0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
    0xdb, 0x0f, 0x00, 0x10,
    0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
    0x9c, 0xc6, 0x0d, 0xd0,
    0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
    0x9b, 0xb6, 0xc5, 0xad,
    0xff, 0x57, 0xe0, 0x8e, // { add r27, r26, r27 ; info 10 ; ld r28, r28 }
    0xdd, 0x0f, 0x00, 0x70,
    0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
  
  };
  
  template<>
  const unsigned char
  Output_data_plt_tilegx<32, false>::plt_entry[plt_entry_size] =
  {
    0xdc, 0x0f, 0x00, 0x10,
    0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
    0xdb, 0x0f, 0x00, 0x10,
    0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
    0x9c, 0xc6, 0x0d, 0xd0,
    0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
    0x9b, 0xb6, 0xc5, 0xad,
    0xff, 0x57, 0xe0, 0x8c, // { add r27, r26, r27 ; info 10 ; ld4s r28, r28 }
    0xdd, 0x0f, 0x00, 0x70,
    0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
  };
  
  template<>
  const unsigned char
  Output_data_plt_tilegx<64, true>::plt_entry[plt_entry_size] =
  {
    0xdc, 0x0f, 0x00, 0x10,
    0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
    0xdb, 0x0f, 0x00, 0x10,
    0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
    0x9c, 0xc6, 0x0d, 0xd0,
    0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
    0x9b, 0xb6, 0xc5, 0xad,
    0xff, 0x57, 0xe0, 0x8e, // { add r27, r26, r27 ; info 10 ; ld r28, r28 }
    0xdd, 0x0f, 0x00, 0x70,
    0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
  
  };
  
  template<>
  const unsigned char
  Output_data_plt_tilegx<32, true>::plt_entry[plt_entry_size] =
  {
    0xdc, 0x0f, 0x00, 0x10,
    0x0d, 0xf0, 0x6a, 0x28, // { moveli r28, 0 ; lnk r26 }
    0xdb, 0x0f, 0x00, 0x10,
    0x8e, 0x03, 0x00, 0x38, // { moveli r27, 0 ; shl16insli r28, r28, 0 }
    0x9c, 0xc6, 0x0d, 0xd0,
    0x6d, 0x03, 0x00, 0x38, // { add r28, r26, r28 ; shl16insli r27, r27, 0 }
    0x9b, 0xb6, 0xc5, 0xad,
    0xff, 0x57, 0xe0, 0x8c, // { add r27, r26, r27 ; info 10 ; ld4s r28, r28 }
    0xdd, 0x0f, 0x00, 0x70,
    0x80, 0x73, 0x6a, 0x28, // { shl16insli r29, zero, 0 ; jr r28 }
  };
  
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::fill_plt_entry(
                   unsigned char* pov,
                   typename elfcpp::Elf_types<size>::Elf_Addr gotplt_base,
                   unsigned int got_offset,
                   typename elfcpp::Elf_types<size>::Elf_Addr plt_base,
                   unsigned int plt_offset, unsigned int plt_index)
  {
  
    const uint32_t TILEGX_IMM16_MASK = 0xFFFF;
    const uint32_t TILEGX_X0_IMM16_BITOFF = 12;
    const uint32_t TILEGX_X1_IMM16_BITOFF = 43;
  
    typedef typename elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::Valtype
      Valtype;
    memcpy(pov, plt_entry, plt_entry_size);
  
    // first bundle in plt stub - x0
    Valtype* wv = reinterpret_cast<Valtype*>(pov);
    Valtype val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
    Valtype reloc =
      ((gotplt_base + got_offset) - (plt_base + plt_offset + 8)) >> 16;
    elfcpp::Elf_Xword dst_mask =
      (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X0_IMM16_BITOFF;
    val &= ~dst_mask;
    reloc &= TILEGX_IMM16_MASK;
    elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
      val | (reloc<<TILEGX_X0_IMM16_BITOFF));
  
    // second bundle in plt stub - x1
    wv = reinterpret_cast<Valtype*>(pov + 8);
    val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
    reloc = (gotplt_base + got_offset) - (plt_base + plt_offset + 8);
    dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X1_IMM16_BITOFF;
    val &= ~dst_mask;
    reloc &= TILEGX_IMM16_MASK;
    elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
      val | (reloc<<TILEGX_X1_IMM16_BITOFF));
  
    // second bundle in plt stub - x0
    wv = reinterpret_cast<Valtype*>(pov + 8);
    val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
    reloc = (gotplt_base - (plt_base + plt_offset + 8)) >> 16;
    dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X0_IMM16_BITOFF;
    val &= ~dst_mask;
    reloc &= TILEGX_IMM16_MASK;
    elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
      val | (reloc<<TILEGX_X0_IMM16_BITOFF));
  
    // third bundle in plt stub - x1
    wv = reinterpret_cast<Valtype*>(pov + 16);
    val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
    reloc = gotplt_base - (plt_base + plt_offset + 8);
    dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X1_IMM16_BITOFF;
    val &= ~dst_mask;
    reloc &= TILEGX_IMM16_MASK;
    elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
      val | (reloc<<TILEGX_X1_IMM16_BITOFF));
  
    // fifth bundle in plt stub - carry plt_index x0
    wv = reinterpret_cast<Valtype*>(pov + 32);
    val = elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::readval(wv);
    dst_mask = (elfcpp::Elf_Xword)(TILEGX_IMM16_MASK) << TILEGX_X0_IMM16_BITOFF;
    val &= ~dst_mask;
    plt_index &= TILEGX_IMM16_MASK;
    elfcpp::Swap<TILEGX_INST_BUNDLE_SIZE, big_endian>::writeval(wv,
      val | (plt_index<<TILEGX_X0_IMM16_BITOFF));
  
  }
  
  // Write out the PLT.  This uses the hand-coded instructions above.
  
  template<int size, bool big_endian>
  void
  Output_data_plt_tilegx<size, big_endian>::do_write(Output_file* of)
  {
    const off_t offset = this->offset();
    const section_size_type oview_size =
      convert_to_section_size_type(this->data_size());
    unsigned char* const oview = of->get_output_view(offset, oview_size);
  
    const off_t got_file_offset = this->got_plt_->offset();
    gold_assert(parameters->incremental_update()
                || (got_file_offset + this->got_plt_->data_size()
                    == this->got_irelative_->offset()));
    const section_size_type got_size =
      convert_to_section_size_type(this->got_plt_->data_size()
                                   + this->got_irelative_->data_size());
    unsigned char* const got_view = of->get_output_view(got_file_offset,
                                                        got_size);
  
    unsigned char* pov = oview;
  
    // The base address of the .plt section.
    typename elfcpp::Elf_types<size>::Elf_Addr plt_address = this->address();
    typename elfcpp::Elf_types<size>::Elf_Addr got_address =
      this->got_plt_->address();
  
    this->fill_first_plt_entry(pov);
    pov += this->get_plt_entry_size();
  
    unsigned char* got_pov = got_view;
  
    // first entry of .got.plt are set to -1
    // second entry of .got.plt are set to 0
    memset(got_pov, 0xff, size / 8);
    got_pov += size / 8;
    memset(got_pov, 0x0, size / 8);
    got_pov += size / 8;
  
    unsigned int plt_offset = this->get_plt_entry_size();
    const unsigned int count = this->count_ + this->irelative_count_;
    unsigned int got_offset = (size / 8) * TILEGX_GOTPLT_RESERVE_COUNT;
    for (unsigned int plt_index = 0;
         plt_index < count;
         ++plt_index,
           pov += this->get_plt_entry_size(),
           got_pov += size / 8,
           plt_offset += this->get_plt_entry_size(),
           got_offset += size / 8)
      {
        // Set and adjust the PLT entry itself.
        this->fill_plt_entry(pov, got_address, got_offset,
                             plt_address, plt_offset, plt_index);
  
        // Initialize entry in .got.plt to plt start address
        elfcpp::Swap<size, big_endian>::writeval(got_pov, plt_address);
      }
  
    gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
    gold_assert(static_cast<section_size_type>(got_pov - got_view) == got_size);
  
    of->write_output_view(offset, oview_size, oview);
    of->write_output_view(got_file_offset, got_size, got_view);
  }
  
  // Create the PLT section.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::make_plt_section(Symbol_table* symtab,
                                                    Layout* layout)
  {
    if (this->plt_ == NULL)
      {
        // Create the GOT sections first.
        this->got_section(symtab, layout);
  
        // Ensure that .rela.dyn always appears before .rela.plt,
        // because on TILE-Gx, .rela.dyn needs to include .rela.plt
        // in it's range.
        this->rela_dyn_section(layout);
  
        this->plt_ = new Output_data_plt_tilegx<size, big_endian>(layout,
          TILEGX_INST_BUNDLE_SIZE, this->got_, this->got_plt_,
          this->got_irelative_);
  
        layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
                                        (elfcpp::SHF_ALLOC
                                         | elfcpp::SHF_EXECINSTR),
                                        this->plt_, ORDER_NON_RELRO_FIRST,
                                        false);
  
        // Make the sh_info field of .rela.plt point to .plt.
        Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
        rela_plt_os->set_info_section(this->plt_->output_section());
      }
  }
  
  // Create a PLT entry for a global symbol.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::make_plt_entry(Symbol_table* symtab,
                                                  Layout* layout, Symbol* gsym)
  {
    if (gsym->has_plt_offset())
      return;
  
    if (this->plt_ == NULL)
      this->make_plt_section(symtab, layout);
  
    this->plt_->add_entry(symtab, layout, gsym);
  }
  
  // Make a PLT entry for a local STT_GNU_IFUNC symbol.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::make_local_ifunc_plt_entry(
      Symbol_table* symtab, Layout* layout,
      Sized_relobj_file<size, big_endian>* relobj,
      unsigned int local_sym_index)
  {
    if (relobj->local_has_plt_offset(local_sym_index))
      return;
    if (this->plt_ == NULL)
      this->make_plt_section(symtab, layout);
    unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout,
                                                                relobj,
                                                                local_sym_index);
    relobj->set_local_plt_offset(local_sym_index, plt_offset);
  }
  
  // Return the number of entries in the PLT.
  
  template<int size, bool big_endian>
  unsigned int
  Target_tilegx<size, big_endian>::plt_entry_count() const
  {
    if (this->plt_ == NULL)
      return 0;
    return this->plt_->entry_count();
  }
  
  // Return the offset of the first non-reserved PLT entry.
  
  template<int size, bool big_endian>
  unsigned int
  Target_tilegx<size, big_endian>::first_plt_entry_offset() const
  {
    return this->plt_->first_plt_entry_offset();
  }
  
  // Return the size of each PLT entry.
  
  template<int size, bool big_endian>
  unsigned int
  Target_tilegx<size, big_endian>::plt_entry_size() const
  {
    return this->plt_->get_plt_entry_size();
  }
  
  // Create the GOT and PLT sections for an incremental update.
  
  template<int size, bool big_endian>
  Output_data_got_base*
  Target_tilegx<size, big_endian>::init_got_plt_for_update(Symbol_table* symtab,
                                         Layout* layout,
                                         unsigned int got_count,
                                         unsigned int plt_count)
  {
    gold_assert(this->got_ == NULL);
  
    this->got_ =
      new Output_data_got<size, big_endian>((got_count
                                             + TILEGX_GOT_RESERVE_COUNT)
                                            * (size / 8));
    layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                    (elfcpp::SHF_ALLOC
                                     | elfcpp::SHF_WRITE),
                                    this->got_, ORDER_RELRO_LAST,
                                    true);
  
    // Define _GLOBAL_OFFSET_TABLE_ at the start of the GOT.
    this->global_offset_table_ =
      symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
                                    Symbol_table::PREDEFINED,
                                    this->got_,
                                    0, 0, elfcpp::STT_OBJECT,
                                    elfcpp::STB_LOCAL,
                                    elfcpp::STV_HIDDEN, 0,
                                    false, false);
  
    if (parameters->options().shared()) {
      this->tilegx_dynamic_ =
              symtab->define_in_output_data("_TILEGX_DYNAMIC_", NULL,
                              Symbol_table::PREDEFINED,
                              layout->dynamic_section(),
                              0, 0, elfcpp::STT_OBJECT,
                              elfcpp::STB_LOCAL,
                              elfcpp::STV_HIDDEN, 0,
                              false, false);
  
      this->got_->add_global(this->tilegx_dynamic_, GOT_TYPE_STANDARD);
    } else
      this->got_->set_current_data_size(size / 8);
  
    // Add the two reserved entries.
    this->got_plt_
       = new Output_data_space((plt_count + TILEGX_GOTPLT_RESERVE_COUNT)
                                * (size / 8), size / 8, "** GOT PLT");
    layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
                                    (elfcpp::SHF_ALLOC
                                     | elfcpp::SHF_WRITE),
                                    this->got_plt_, ORDER_NON_RELRO_FIRST,
                                    false);
  
    // If there are any IRELATIVE relocations, they get GOT entries in
    // .got.plt after the jump slot.
    this->got_irelative_
       = new Output_data_space(0, size / 8, "** GOT IRELATIVE PLT");
    layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
                                    elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
                                    this->got_irelative_,
                                    ORDER_NON_RELRO_FIRST, false);
  
    // Create the PLT section.
    this->plt_ = new Output_data_plt_tilegx<size, big_endian>(layout,
      this->plt_entry_size(), this->got_, this->got_plt_, this->got_irelative_,
      plt_count);
  
    layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
                                    elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
                                    this->plt_, ORDER_PLT, false);
  
    // Make the sh_info field of .rela.plt point to .plt.
    Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
    rela_plt_os->set_info_section(this->plt_->output_section());
  
    // Create the rela_dyn section.
    this->rela_dyn_section(layout);
  
    return this->got_;
  }
  
  // Reserve a GOT entry for a local symbol, and regenerate any
  // necessary dynamic relocations.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::reserve_local_got_entry(
      unsigned int got_index,
      Sized_relobj<size, big_endian>* obj,
      unsigned int r_sym,
      unsigned int got_type)
  {
    unsigned int got_offset = (got_index + TILEGX_GOT_RESERVE_COUNT)
                              * (size / 8);
    Reloc_section* rela_dyn = this->rela_dyn_section(NULL);
  
    this->got_->reserve_local(got_index, obj, r_sym, got_type);
    switch (got_type)
      {
      case GOT_TYPE_STANDARD:
        if (parameters->options().output_is_position_independent())
          rela_dyn->add_local_relative(obj, r_sym, elfcpp::R_TILEGX_RELATIVE,
                                       this->got_, got_offset, 0, false);
        break;
      case GOT_TYPE_TLS_OFFSET:
        rela_dyn->add_local(obj, r_sym,
                            size == 32 ? elfcpp::R_TILEGX_TLS_DTPOFF32
                                         : elfcpp::R_TILEGX_TLS_DTPOFF64,
                            this->got_, got_offset, 0);
        break;
      case GOT_TYPE_TLS_PAIR:
        this->got_->reserve_slot(got_index + 1);
        rela_dyn->add_local(obj, r_sym,
                            size == 32 ? elfcpp::R_TILEGX_TLS_DTPMOD32
                                         : elfcpp::R_TILEGX_TLS_DTPMOD64,
                            this->got_, got_offset, 0);
        break;
      case GOT_TYPE_TLS_DESC:
        gold_fatal(_("TLS_DESC not yet supported for incremental linking"));
        break;
      default:
        gold_unreachable();
      }
  }
  
  // Reserve a GOT entry for a global symbol, and regenerate any
  // necessary dynamic relocations.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::reserve_global_got_entry(
    unsigned int got_index, Symbol* gsym, unsigned int got_type)
  {
    unsigned int got_offset = (got_index + TILEGX_GOT_RESERVE_COUNT)
                              * (size / 8);
    Reloc_section* rela_dyn = this->rela_dyn_section(NULL);
  
    this->got_->reserve_global(got_index, gsym, got_type);
    switch (got_type)
      {
      case GOT_TYPE_STANDARD:
        if (!gsym->final_value_is_known())
          {
            if (gsym->is_from_dynobj()
                || gsym->is_undefined()
                || gsym->is_preemptible()
                || gsym->type() == elfcpp::STT_GNU_IFUNC)
              rela_dyn->add_global(gsym, elfcpp::R_TILEGX_GLOB_DAT,
                                   this->got_, got_offset, 0);
            else
              rela_dyn->add_global_relative(gsym, elfcpp::R_TILEGX_RELATIVE,
                                            this->got_, got_offset, 0, false);
          }
        break;
      case GOT_TYPE_TLS_OFFSET:
        rela_dyn->add_global_relative(gsym,
                                      size == 32 ? elfcpp::R_TILEGX_TLS_TPOFF32
                                                 : elfcpp::R_TILEGX_TLS_TPOFF64,
                                      this->got_, got_offset, 0, false);
        break;
      case GOT_TYPE_TLS_PAIR:
        this->got_->reserve_slot(got_index + 1);
        rela_dyn->add_global_relative(gsym,
                                      size == 32 ? elfcpp::R_TILEGX_TLS_DTPMOD32
                                                 : elfcpp::R_TILEGX_TLS_DTPMOD64,
                                      this->got_, got_offset, 0, false);
        rela_dyn->add_global_relative(gsym,
                                      size == 32 ? elfcpp::R_TILEGX_TLS_DTPOFF32
                                                 : elfcpp::R_TILEGX_TLS_DTPOFF64,
                                      this->got_, got_offset + size / 8,
                                      0, false);
        break;
      case GOT_TYPE_TLS_DESC:
        gold_fatal(_("TLS_DESC not yet supported for TILEGX"));
        break;
      default:
        gold_unreachable();
      }
  }
  
  // Register an existing PLT entry for a global symbol.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::register_global_plt_entry(
    Symbol_table* symtab, Layout* layout, unsigned int plt_index, Symbol* gsym)
  {
    gold_assert(this->plt_ != NULL);
    gold_assert(!gsym->has_plt_offset());
  
    this->plt_->reserve_slot(plt_index);
  
    gsym->set_plt_offset((plt_index + 1) * this->plt_entry_size());
  
    unsigned int got_offset = (plt_index + 2) * (size / 8);
    this->plt_->add_relocation(symtab, layout, gsym, got_offset);
  }
  
  // Force a COPY relocation for a given symbol.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::emit_copy_reloc(
      Symbol_table* symtab, Symbol* sym, Output_section* os, off_t offset)
  {
    this->copy_relocs_.emit_copy_reloc(symtab,
                                       symtab->get_sized_symbol<size>(sym),
                                       os,
                                       offset,
                                       this->rela_dyn_section(NULL));
  }
  
  // Create a GOT entry for the TLS module index.
  
  template<int size, bool big_endian>
  unsigned int
  Target_tilegx<size, big_endian>::got_mod_index_entry(Symbol_table* symtab,
                                    Layout* layout,
                                    Sized_relobj_file<size, big_endian>* object)
  {
    if (this->got_mod_index_offset_ == -1U)
      {
        gold_assert(symtab != NULL && layout != NULL && object != NULL);
        Reloc_section* rela_dyn = this->rela_dyn_section(layout);
        Output_data_got<size, big_endian>* got
           = this->got_section(symtab, layout);
        unsigned int got_offset = got->add_constant(0);
        rela_dyn->add_local(object, 0,
                            size == 32 ? elfcpp::R_TILEGX_TLS_DTPMOD32
                                         : elfcpp::R_TILEGX_TLS_DTPMOD64, got,
                            got_offset, 0);
        got->add_constant(0);
        this->got_mod_index_offset_ = got_offset;
      }
    return this->got_mod_index_offset_;
  }
  
  // Optimize the TLS relocation type based on what we know about the
  // symbol.  IS_FINAL is true if the final address of this symbol is
  // known at link time.
  //
  // the transformation rules is described below:
  //
  //   compiler GD reference
  //    |
  //    V
  //     moveli      tmp, hw1_last_tls_gd(x)     X0/X1
  //     shl16insli  r0,  tmp, hw0_tls_gd(x)     X0/X1
  //     addi        r0, got, tls_add(x)         Y0/Y1/X0/X1
  //     jal         tls_gd_call(x)              X1
  //     addi        adr, r0,  tls_gd_add(x)     Y0/Y1/X0/X1
  //
  //     linker tranformation of GD insn sequence
  //      |
  //      V
  //      ==> GD:
  //       moveli      tmp, hw1_last_tls_gd(x)     X0/X1
  //       shl16insli  r0,  tmp, hw0_tls_gd(x)     X0/X1
  //       add         r0,  got, r0                Y0/Y1/X0/X1
  //       jal         plt(__tls_get_addr)         X1
  //       move        adr, r0                     Y0/Y1/X0/X1
  //      ==> IE:
  //       moveli      tmp, hw1_last_tls_ie(x)     X0/X1
  //       shl16insli  r0,  tmp, hw0_tls_ie(x)     X0/X1
  //       add         r0,  got, r0                Y0/Y1/X0/X1
  //       ld          r0,  r0                     X1
  //       add         adr, r0, tp                 Y0/Y1/X0/X1
  //      ==> LE:
  //       moveli      tmp, hw1_last_tls_le(x)     X0/X1
  //       shl16insli  r0,  tmp, hw0_tls_le(x)     X0/X1
  //       move        r0,  r0                     Y0/Y1/X0/X1
  //       move        r0,  r0                     Y0/Y1/X0/X1
  //       add         adr, r0, tp                 Y0/Y1/X0/X1
  //
  //
  //   compiler IE reference
  //    |
  //    V
  //     moveli      tmp, hw1_last_tls_ie(x)     X0/X1
  //     shl16insli  tmp, tmp, hw0_tls_ie(x)     X0/X1
  //     addi        tmp, got, tls_add(x)        Y0/Y1/X0/X1
  //     ld_tls      tmp, tmp, tls_ie_load(x)    X1
  //     add         adr, tmp, tp                Y0/Y1/X0/X1
  //
  //     linker transformation for IE insn sequence
  //      |
  //      V
  //      ==> IE:
  //       moveli      tmp, hw1_last_tls_ie(x)     X0/X1
  //       shl16insli  tmp, tmp, hw0_tls_ie(x)     X0/X1
  //       add         tmp, got, tmp               Y0/Y1/X0/X1
  //       ld          tmp, tmp                    X1
  //       add         adr, tmp, tp                Y0/Y1/X0/X1
  //      ==> LE:
  //       moveli      tmp, hw1_last_tls_le(x)     X0/X1
  //       shl16insli  tmp, tmp, hw0_tls_le(x)     X0/X1
  //       move        tmp, tmp                    Y0/Y1/X0/X1
  //       move        tmp, tmp                    Y0/Y1/X0/X1
  //
  //
  //   compiler LE reference
  //    |
  //    V
  //     moveli        tmp, hw1_last_tls_le(x)     X0/X1
  //     shl16insli    tmp, tmp, hw0_tls_le(x)     X0/X1
  //     add           adr, tmp, tp                Y0/Y1/X0/X1
  
  template<int size, bool big_endian>
  tls::Tls_optimization
  Target_tilegx<size, big_endian>::optimize_tls_reloc(bool is_final, int r_type)
  {
    // If we are generating a shared library, then we can't do anything
    // in the linker.
    if (parameters->options().shared())
      return tls::TLSOPT_NONE;
  
    switch (r_type)
      {
      // unique GD relocations
      case elfcpp::R_TILEGX_TLS_GD_CALL:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
        // These are General-Dynamic which permits fully general TLS
        // access.  Since we know that we are generating an executable,
        // we can convert this to Initial-Exec.  If we also know that
        // this is a local symbol, we can further switch to Local-Exec.
        if (is_final)
          return tls::TLSOPT_TO_LE;
        return tls::TLSOPT_TO_IE;
  
      // unique IE relocations
      case elfcpp::R_TILEGX_TLS_IE_LOAD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
        // These are Initial-Exec relocs which get the thread offset
        // from the GOT.  If we know that we are linking against the
        // local symbol, we can switch to Local-Exec, which links the
        // thread offset into the instruction.
        if (is_final)
          return tls::TLSOPT_TO_LE;
        return tls::TLSOPT_NONE;
  
      // could be created for both GD and IE
      // but they are expanded into the same
      // instruction in GD and IE.
      case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
        if (is_final)
          return tls::TLSOPT_TO_LE;
        return tls::TLSOPT_NONE;
  
      // unique LE relocations
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
        // When we already have Local-Exec, there is nothing further we
        // can do.
        return tls::TLSOPT_NONE;
  
      default:
        gold_unreachable();
      }
  }
  
  // Get the Reference_flags for a particular relocation.
  
  template<int size, bool big_endian>
  int
  Target_tilegx<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
  {
    switch (r_type)
      {
      case elfcpp::R_TILEGX_NONE:
      case elfcpp::R_TILEGX_GNU_VTINHERIT:
      case elfcpp::R_TILEGX_GNU_VTENTRY:
        // No symbol reference.
        return 0;
  
      case elfcpp::R_TILEGX_64:
      case elfcpp::R_TILEGX_32:
      case elfcpp::R_TILEGX_16:
      case elfcpp::R_TILEGX_8:
        return Symbol::ABSOLUTE_REF;
  
      case elfcpp::R_TILEGX_BROFF_X1:
      case elfcpp::R_TILEGX_64_PCREL:
      case elfcpp::R_TILEGX_32_PCREL:
      case elfcpp::R_TILEGX_16_PCREL:
      case elfcpp::R_TILEGX_8_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
        return Symbol::RELATIVE_REF;
  
      case elfcpp::R_TILEGX_JUMPOFF_X1:
      case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
        return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0:
      case elfcpp::R_TILEGX_IMM16_X1_HW0:
      case elfcpp::R_TILEGX_IMM16_X0_HW1:
      case elfcpp::R_TILEGX_IMM16_X1_HW1:
      case elfcpp::R_TILEGX_IMM16_X0_HW2:
      case elfcpp::R_TILEGX_IMM16_X1_HW2:
      case elfcpp::R_TILEGX_IMM16_X0_HW3:
      case elfcpp::R_TILEGX_IMM16_X1_HW3:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
        return Symbol::ABSOLUTE_REF;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
        // Absolute in GOT.
        return Symbol::ABSOLUTE_REF;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_TLS_DTPOFF64:
      case elfcpp::R_TILEGX_TLS_DTPMOD32:
      case elfcpp::R_TILEGX_TLS_DTPOFF32:
      case elfcpp::R_TILEGX_TLS_TPOFF32:
      case elfcpp::R_TILEGX_TLS_GD_CALL:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_TLS_IE_LOAD:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
        return Symbol::TLS_REF;
  
      case elfcpp::R_TILEGX_COPY:
      case elfcpp::R_TILEGX_GLOB_DAT:
      case elfcpp::R_TILEGX_JMP_SLOT:
      case elfcpp::R_TILEGX_RELATIVE:
      case elfcpp::R_TILEGX_TLS_TPOFF64:
      case elfcpp::R_TILEGX_TLS_DTPMOD64:
      default:
        // Not expected.  We will give an error later.
        return 0;
      }
  }
  
  // Report an unsupported relocation against a local symbol.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::Scan::unsupported_reloc_local(
       Sized_relobj_file<size, big_endian>* object,
       unsigned int r_type)
  {
    gold_error(_("%s: unsupported reloc %u against local symbol"),
               object->name().c_str(), r_type);
  }
  
  // We are about to emit a dynamic relocation of type R_TYPE.  If the
  // dynamic linker does not support it, issue an error.
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::Scan::check_non_pic(Relobj* object,
                                                       unsigned int r_type)
  {
    switch (r_type)
      {
        // These are the relocation types supported by glibc for tilegx
        // which should always work.
      case elfcpp::R_TILEGX_RELATIVE:
      case elfcpp::R_TILEGX_GLOB_DAT:
      case elfcpp::R_TILEGX_JMP_SLOT:
      case elfcpp::R_TILEGX_TLS_DTPMOD64:
      case elfcpp::R_TILEGX_TLS_DTPOFF64:
      case elfcpp::R_TILEGX_TLS_TPOFF64:
      case elfcpp::R_TILEGX_8:
      case elfcpp::R_TILEGX_16:
      case elfcpp::R_TILEGX_32:
      case elfcpp::R_TILEGX_64:
      case elfcpp::R_TILEGX_COPY:
      case elfcpp::R_TILEGX_IMM16_X0_HW0:
      case elfcpp::R_TILEGX_IMM16_X1_HW0:
      case elfcpp::R_TILEGX_IMM16_X0_HW1:
      case elfcpp::R_TILEGX_IMM16_X1_HW1:
      case elfcpp::R_TILEGX_IMM16_X0_HW2:
      case elfcpp::R_TILEGX_IMM16_X1_HW2:
      case elfcpp::R_TILEGX_IMM16_X0_HW3:
      case elfcpp::R_TILEGX_IMM16_X1_HW3:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
      case elfcpp::R_TILEGX_BROFF_X1:
      case elfcpp::R_TILEGX_JUMPOFF_X1:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
        return;
  
      default:
        // This prevents us from issuing more than one error per reloc
        // section.  But we can still wind up issuing more than one
        // error per object file.
        if (this->issued_non_pic_error_)
          return;
        gold_assert(parameters->options().output_is_position_independent());
        object->error(_("requires unsupported dynamic reloc %u; "
                        "recompile with -fPIC"),
                      r_type);
        this->issued_non_pic_error_ = true;
        return;
  
      case elfcpp::R_TILEGX_NONE:
        gold_unreachable();
      }
  }
  
  // Return whether we need to make a PLT entry for a relocation of the
  // given type against a STT_GNU_IFUNC symbol.
  
  template<int size, bool big_endian>
  bool
  Target_tilegx<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
       Sized_relobj_file<size, big_endian>* object, unsigned int r_type)
  {
    int flags = Scan::get_reference_flags(r_type);
    if (flags & Symbol::TLS_REF)
      gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
                 object->name().c_str(), r_type);
    return flags != 0;
  }
  
  // Scan a relocation for a local symbol.
  
  template<int size, bool big_endian>
  inline void
  Target_tilegx<size, big_endian>::Scan::local(Symbol_table* symtab,
                                   Layout* layout,
                                   Target_tilegx<size, big_endian>* target,
                                   Sized_relobj_file<size, big_endian>* object,
                                   unsigned int data_shndx,
                                   Output_section* output_section,
                                   const elfcpp::Rela<size, big_endian>& reloc,
                                   unsigned int r_type,
                                   const elfcpp::Sym<size, big_endian>& lsym,
                                   bool is_discarded)
  {
    if (is_discarded)
      return;
  
    // A local STT_GNU_IFUNC symbol may require a PLT entry.
    bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
    if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
      {
        unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
        target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
      }
  
    switch (r_type)
      {
      case elfcpp::R_TILEGX_NONE:
      case elfcpp::R_TILEGX_GNU_VTINHERIT:
      case elfcpp::R_TILEGX_GNU_VTENTRY:
        break;
  
      // If building a shared library (or a position-independent
      // executable), because the runtime address needs plus
      // the module base address, so generate a R_TILEGX_RELATIVE.
      case elfcpp::R_TILEGX_32:
      case elfcpp::R_TILEGX_64:
        if (parameters->options().output_is_position_independent())
          {
            unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
            Reloc_section* rela_dyn = target->rela_dyn_section(layout);
            rela_dyn->add_local_relative(object, r_sym,
                                         elfcpp::R_TILEGX_RELATIVE,
                                         output_section, data_shndx,
                                         reloc.get_r_offset(),
                                         reloc.get_r_addend(), is_ifunc);
          }
        break;
  
      // If building a shared library (or a position-independent
      // executable), we need to create a dynamic relocation for this
      // location.
      case elfcpp::R_TILEGX_8:
      case elfcpp::R_TILEGX_16:
      case elfcpp::R_TILEGX_IMM16_X0_HW0:
      case elfcpp::R_TILEGX_IMM16_X1_HW0:
      case elfcpp::R_TILEGX_IMM16_X0_HW1:
      case elfcpp::R_TILEGX_IMM16_X1_HW1:
      case elfcpp::R_TILEGX_IMM16_X0_HW2:
      case elfcpp::R_TILEGX_IMM16_X1_HW2:
      case elfcpp::R_TILEGX_IMM16_X0_HW3:
      case elfcpp::R_TILEGX_IMM16_X1_HW3:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
        if (parameters->options().output_is_position_independent())
          {
            this->check_non_pic(object, r_type);
  
            Reloc_section* rela_dyn = target->rela_dyn_section(layout);
            unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
            if (lsym.get_st_type() != elfcpp::STT_SECTION)
              rela_dyn->add_local(object, r_sym, r_type, output_section,
                                  data_shndx, reloc.get_r_offset(),
                                  reloc.get_r_addend());
            else
              {
                gold_assert(lsym.get_st_value() == 0);
                rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
                                                      output_section,
                                                      data_shndx,
                                                      reloc.get_r_offset(),
                                                      reloc.get_r_addend());
  
              }
          }
        break;
  
      // R_TILEGX_JUMPOFF_X1_PLT against local symbol
      // may happen for ifunc case.
      case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
      case elfcpp::R_TILEGX_JUMPOFF_X1:
      case elfcpp::R_TILEGX_64_PCREL:
      case elfcpp::R_TILEGX_32_PCREL:
      case elfcpp::R_TILEGX_16_PCREL:
      case elfcpp::R_TILEGX_8_PCREL:
      case elfcpp::R_TILEGX_BROFF_X1:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
        break;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
        {
          // The symbol requires a GOT entry.
          Output_data_got<size, big_endian>* got
             = target->got_section(symtab, layout);
          unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
  
          // For a STT_GNU_IFUNC symbol we want the PLT offset.  That
          // lets function pointers compare correctly with shared
          // libraries.  Otherwise we would need an IRELATIVE reloc.
          bool is_new;
          if (is_ifunc)
            is_new = got->add_local_plt(object, r_sym, GOT_TYPE_STANDARD);
          else
            is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD);
          if (is_new)
            {
              // tilegx dynamic linker will not update local got entry,
              // so, if we are generating a shared object, we need to add a
              // dynamic relocation for this symbol's GOT entry to inform
              // dynamic linker plus the load base explicitly.
              if (parameters->options().output_is_position_independent())
                {
                 unsigned int got_offset
                    = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
  
                  Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                  rela_dyn->add_local_relative(object, r_sym,
                                               r_type,
                                               got, got_offset, 0, is_ifunc);
                }
            }
        }
        break;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_TLS_GD_CALL:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_TLS_IE_LOAD:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
        {
           bool output_is_shared = parameters->options().shared();
           const tls::Tls_optimization opt_t =
            Target_tilegx<size, big_endian>::optimize_tls_reloc(
              !output_is_shared, r_type);
  
           switch (r_type)
             {
               case elfcpp::R_TILEGX_TLS_GD_CALL:
                 // FIXME: predefine __tls_get_addr
                 //
                 // R_TILEGX_TLS_GD_CALL implicitly reference __tls_get_addr,
                 // while all other target, x86/arm/mips/powerpc/sparc
                 // generate tls relocation against __tls_get_addr explicitly,
                 // so for TILEGX, we need the following hack.
                 if (opt_t == tls::TLSOPT_NONE) {
                   if (!target->tls_get_addr_sym_defined_) {
                     Symbol* sym = NULL;
                     options::parse_set(NULL, "__tls_get_addr",
                                       (gold::options::String_set*)
                                       &parameters->options().undefined());
                     symtab->add_undefined_symbols_from_command_line(layout);
                     target->tls_get_addr_sym_defined_ = true;
                     sym = symtab->lookup("__tls_get_addr");
                     sym->set_in_reg();
                   }
                   target->make_plt_entry(symtab, layout,
                                          symtab->lookup("__tls_get_addr"));
                 }
                 break;
  
               // only make effect when applying relocation
               case elfcpp::R_TILEGX_TLS_IE_LOAD:
               case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
               case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
               case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
               case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
               case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
               case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
               case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
               case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
                 break;
  
               // GD: requires two GOT entry for module index and offset
               // IE: requires one GOT entry for tp-relative offset
               // LE: shouldn't happen for global symbol
               case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
               case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
               case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
               case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
               case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
               case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
                 {
                   if (opt_t == tls::TLSOPT_NONE) {
                     Output_data_got<size, big_endian> *got
                        = target->got_section(symtab, layout);
                     unsigned int r_sym
                        = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                     unsigned int shndx = lsym.get_st_shndx();
                     bool is_ordinary;
                     shndx = object->adjust_sym_shndx(r_sym, shndx,
                                                      &is_ordinary);
                     if (!is_ordinary)
                       object->error(_("local symbol %u has bad shndx %u"),
                                     r_sym, shndx);
                     else
                       got->add_local_pair_with_rel(object, r_sym, shndx,
                                             GOT_TYPE_TLS_PAIR,
                                             target->rela_dyn_section(layout),
                                             size == 32
                                             ? elfcpp::R_TILEGX_TLS_DTPMOD32
                                             : elfcpp::R_TILEGX_TLS_DTPMOD64);
                    } else if (opt_t == tls::TLSOPT_TO_IE) {
                      Output_data_got<size, big_endian>* got
                         = target->got_section(symtab, layout);
                      Reloc_section* rela_dyn
                         = target->rela_dyn_section(layout);
                      unsigned int r_sym
                         = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                      unsigned int off = got->add_constant(0);
                      object->set_local_got_offset(r_sym,
                                                   GOT_TYPE_TLS_OFFSET,off);
                      rela_dyn->add_symbolless_local_addend(object, r_sym,
                                              size == 32
                                              ? elfcpp::R_TILEGX_TLS_TPOFF32
                                              : elfcpp::R_TILEGX_TLS_TPOFF64,
                                              got, off, 0);
                    } else if (opt_t != tls::TLSOPT_TO_LE)
                      // only TO_LE is allowed for local symbol
                      unsupported_reloc_local(object, r_type);
                 }
                 break;
  
               // IE
               case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
               case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
               case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
               case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
               case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
               case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
                 {
                   layout->set_has_static_tls();
                   if (opt_t == tls::TLSOPT_NONE) {
                     Output_data_got<size, big_endian>* got
                        = target->got_section(symtab, layout);
                     Reloc_section* rela_dyn
                        = target->rela_dyn_section(layout);
                     unsigned int r_sym
                        = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                     unsigned int off = got->add_constant(0);
                     object->set_local_got_offset(r_sym,
                                                  GOT_TYPE_TLS_OFFSET, off);
                     rela_dyn->add_symbolless_local_addend(object, r_sym,
                                              size == 32
                                              ? elfcpp::R_TILEGX_TLS_TPOFF32
                                              : elfcpp::R_TILEGX_TLS_TPOFF64,
                                              got, off, 0);
                   } else if (opt_t != tls::TLSOPT_TO_LE)
                     unsupported_reloc_local(object, r_type);
                 }
                 break;
  
               // LE
               case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
               case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
               case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
               case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
               case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
               case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
                 layout->set_has_static_tls();
                 if (parameters->options().shared()) {
                   // defer to dynamic linker
                   gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
                   unsigned int r_sym
                      = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                   Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                   rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
                                                    output_section, data_shndx,
                                                    reloc.get_r_offset(), 0);
                 }
                 break;
  
               default:
                 gold_unreachable();
             }
        }
        break;
  
      case elfcpp::R_TILEGX_COPY:
      case elfcpp::R_TILEGX_GLOB_DAT:
      case elfcpp::R_TILEGX_JMP_SLOT:
      case elfcpp::R_TILEGX_RELATIVE:
        // These are outstanding tls relocs, which are unexpected when linking
      case elfcpp::R_TILEGX_TLS_TPOFF32:
      case elfcpp::R_TILEGX_TLS_TPOFF64:
      case elfcpp::R_TILEGX_TLS_DTPMOD32:
      case elfcpp::R_TILEGX_TLS_DTPMOD64:
      case elfcpp::R_TILEGX_TLS_DTPOFF32:
      case elfcpp::R_TILEGX_TLS_DTPOFF64:
        gold_error(_("%s: unexpected reloc %u in object file"),
                   object->name().c_str(), r_type);
        break;
  
      default:
        gold_error(_("%s: unsupported reloc %u against local symbol"),
                   object->name().c_str(), r_type);
        break;
      }
  }
  
  
  // Report an unsupported relocation against a global symbol.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::Scan::unsupported_reloc_global(
      Sized_relobj_file<size, big_endian>* object,
      unsigned int r_type,
      Symbol* gsym)
  {
    gold_error(_("%s: unsupported reloc %u against global symbol %s"),
               object->name().c_str(), r_type, gsym->demangled_name().c_str());
  }
  
  // Returns true if this relocation type could be that of a function pointer.
  template<int size, bool big_endian>
  inline bool
  Target_tilegx<size, big_endian>::Scan::possible_function_pointer_reloc(
    unsigned int r_type)
  {
    switch (r_type)
      {
        case elfcpp::R_TILEGX_IMM16_X0_HW0:
        case elfcpp::R_TILEGX_IMM16_X1_HW0:
        case elfcpp::R_TILEGX_IMM16_X0_HW1:
        case elfcpp::R_TILEGX_IMM16_X1_HW1:
        case elfcpp::R_TILEGX_IMM16_X0_HW2:
        case elfcpp::R_TILEGX_IMM16_X1_HW2:
        case elfcpp::R_TILEGX_IMM16_X0_HW3:
        case elfcpp::R_TILEGX_IMM16_X1_HW3:
        case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
        case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
        case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
        case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
        case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
        case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
        case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
        case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
        case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
        case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
        case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
        case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
        case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
        case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
        case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
        case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
        case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
        case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
        case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
        case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
        case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
        case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
        case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
        case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
        case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
        case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
        {
          return true;
        }
      }
    return false;
  }
  
  // For safe ICF, scan a relocation for a local symbol to check if it
  // corresponds to a function pointer being taken.  In that case mark
  // the function whose pointer was taken as not foldable.
  
  template<int size, bool big_endian>
  inline bool
  Target_tilegx<size, big_endian>::Scan::local_reloc_may_be_function_pointer(
    Symbol_table* ,
    Layout* ,
    Target_tilegx<size, big_endian>* ,
    Sized_relobj_file<size, big_endian>* ,
    unsigned int ,
    Output_section* ,
    const elfcpp::Rela<size, big_endian>& ,
    unsigned int r_type,
    const elfcpp::Sym<size, big_endian>&)
  {
    return possible_function_pointer_reloc(r_type);
  }
  
  // For safe ICF, scan a relocation for a global symbol to check if it
  // corresponds to a function pointer being taken.  In that case mark
  // the function whose pointer was taken as not foldable.
  
  template<int size, bool big_endian>
  inline bool
  Target_tilegx<size, big_endian>::Scan::global_reloc_may_be_function_pointer(
    Symbol_table*,
    Layout* ,
    Target_tilegx<size, big_endian>* ,
    Sized_relobj_file<size, big_endian>* ,
    unsigned int ,
    Output_section* ,
    const elfcpp::Rela<size, big_endian>& ,
    unsigned int r_type,
    Symbol* gsym)
  {
    // GOT is not a function.
    if (strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
      return false;
  
    // When building a shared library, do not fold symbols whose visibility
    // is hidden, internal or protected.
    return ((parameters->options().shared()
             && (gsym->visibility() == elfcpp::STV_INTERNAL
                 || gsym->visibility() == elfcpp::STV_PROTECTED
                 || gsym->visibility() == elfcpp::STV_HIDDEN))
            || possible_function_pointer_reloc(r_type));
  }
  
  // Scan a relocation for a global symbol.
  
  template<int size, bool big_endian>
  inline void
  Target_tilegx<size, big_endian>::Scan::global(Symbol_table* symtab,
                              Layout* layout,
                              Target_tilegx<size, big_endian>* target,
                              Sized_relobj_file<size, big_endian>* object,
                              unsigned int data_shndx,
                              Output_section* output_section,
                              const elfcpp::Rela<size, big_endian>& reloc,
                              unsigned int r_type,
                              Symbol* gsym)
  {
    // A reference to _GLOBAL_OFFSET_TABLE_ implies that we need a got
    // section.  We check here to avoid creating a dynamic reloc against
    // _GLOBAL_OFFSET_TABLE_.
    if (!target->has_got_section()
        && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
      target->got_section(symtab, layout);
  
    // A STT_GNU_IFUNC symbol may require a PLT entry.
    if (gsym->type() == elfcpp::STT_GNU_IFUNC
        && this->reloc_needs_plt_for_ifunc(object, r_type))
      target->make_plt_entry(symtab, layout, gsym);
  
    switch (r_type)
      {
      case elfcpp::R_TILEGX_NONE:
      case elfcpp::R_TILEGX_GNU_VTINHERIT:
      case elfcpp::R_TILEGX_GNU_VTENTRY:
        break;
  
      case elfcpp::R_TILEGX_DEST_IMM8_X1:
      case elfcpp::R_TILEGX_IMM16_X0_HW0:
      case elfcpp::R_TILEGX_IMM16_X1_HW0:
      case elfcpp::R_TILEGX_IMM16_X0_HW1:
      case elfcpp::R_TILEGX_IMM16_X1_HW1:
      case elfcpp::R_TILEGX_IMM16_X0_HW2:
      case elfcpp::R_TILEGX_IMM16_X1_HW2:
      case elfcpp::R_TILEGX_IMM16_X0_HW3:
      case elfcpp::R_TILEGX_IMM16_X1_HW3:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
      case elfcpp::R_TILEGX_64:
      case elfcpp::R_TILEGX_32:
      case elfcpp::R_TILEGX_16:
      case elfcpp::R_TILEGX_8:
        {
          // Make a PLT entry if necessary.
          if (gsym->needs_plt_entry())
            {
              target->make_plt_entry(symtab, layout, gsym);
              // Since this is not a PC-relative relocation, we may be
              // taking the address of a function. In that case we need to
              // set the entry in the dynamic symbol table to the address of
              // the PLT entry.
              if (gsym->is_from_dynobj() && !parameters->options().shared())
                gsym->set_needs_dynsym_value();
            }
          // Make a dynamic relocation if necessary.
          if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
            {
  	    if (!parameters->options().output_is_position_independent()
  		&& gsym->may_need_copy_reloc())
                {
                  target->copy_reloc(symtab, layout, object,
                                     data_shndx, output_section, gsym, reloc);
                }
              else if (((size == 64 && r_type == elfcpp::R_TILEGX_64)
                        || (size == 32 && r_type == elfcpp::R_TILEGX_32))
                       && gsym->type() == elfcpp::STT_GNU_IFUNC
                       && gsym->can_use_relative_reloc(false)
                       && !gsym->is_from_dynobj()
                       && !gsym->is_undefined()
                       && !gsym->is_preemptible())
                {
                  // Use an IRELATIVE reloc for a locally defined
                  // STT_GNU_IFUNC symbol.  This makes a function
                  // address in a PIE executable match the address in a
                  // shared library that it links against.
                  Reloc_section* rela_dyn =
                    target->rela_irelative_section(layout);
                  unsigned int r_type = elfcpp::R_TILEGX_IRELATIVE;
                  rela_dyn->add_symbolless_global_addend(gsym, r_type,
                                                     output_section, object,
                                                     data_shndx,
                                                     reloc.get_r_offset(),
                                                     reloc.get_r_addend());
                } else if ((r_type == elfcpp::R_TILEGX_64
                            || r_type == elfcpp::R_TILEGX_32)
                           && gsym->can_use_relative_reloc(false))
                {
                  Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                  rela_dyn->add_global_relative(gsym, elfcpp::R_TILEGX_RELATIVE,
                                                output_section, object,
                                                data_shndx,
                                                reloc.get_r_offset(),
                                                reloc.get_r_addend(), false);
                }
              else
                {
                  this->check_non_pic(object, r_type);
                  Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                  rela_dyn->add_global(gsym, r_type, output_section, object,
                                       data_shndx, reloc.get_r_offset(),
                                       reloc.get_r_addend());
                }
            }
        }
        break;
  
      case elfcpp::R_TILEGX_BROFF_X1:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
      case elfcpp::R_TILEGX_64_PCREL:
      case elfcpp::R_TILEGX_32_PCREL:
      case elfcpp::R_TILEGX_16_PCREL:
      case elfcpp::R_TILEGX_8_PCREL:
        {
          // Make a PLT entry if necessary.
          if (gsym->needs_plt_entry())
            target->make_plt_entry(symtab, layout, gsym);
          // Make a dynamic relocation if necessary.
          if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
            {
  	    if (parameters->options().output_is_executable()
  		&& gsym->may_need_copy_reloc())
                {
                  target->copy_reloc(symtab, layout, object,
                                     data_shndx, output_section, gsym, reloc);
                }
              else
                {
                  this->check_non_pic(object, r_type);
                  Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                  rela_dyn->add_global(gsym, r_type, output_section, object,
                                       data_shndx, reloc.get_r_offset(),
                                       reloc.get_r_addend());
                }
            }
        }
        break;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
        {
          // The symbol requires a GOT entry.
          Output_data_got<size, big_endian>* got
             = target->got_section(symtab, layout);
          if (gsym->final_value_is_known())
            {
              // For a STT_GNU_IFUNC symbol we want the PLT address.
              if (gsym->type() == elfcpp::STT_GNU_IFUNC)
                got->add_global_plt(gsym, GOT_TYPE_STANDARD);
              else
                got->add_global(gsym, GOT_TYPE_STANDARD);
            }
          else
            {
              // If this symbol is not fully resolved, we need to add a
              // dynamic relocation for it.
              Reloc_section* rela_dyn = target->rela_dyn_section(layout);
  
              // Use a GLOB_DAT rather than a RELATIVE reloc if:
              //
              // 1) The symbol may be defined in some other module.
              //
              // 2) We are building a shared library and this is a
              // protected symbol; using GLOB_DAT means that the dynamic
              // linker can use the address of the PLT in the main
              // executable when appropriate so that function address
              // comparisons work.
              //
              // 3) This is a STT_GNU_IFUNC symbol in position dependent
              // code, again so that function address comparisons work.
              if (gsym->is_from_dynobj()
                  || gsym->is_undefined()
                  || gsym->is_preemptible()
                  || (gsym->visibility() == elfcpp::STV_PROTECTED
                      && parameters->options().shared())
                  || (gsym->type() == elfcpp::STT_GNU_IFUNC
                      && parameters->options().output_is_position_independent()))
                got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
                                         elfcpp::R_TILEGX_GLOB_DAT);
              else
                {
                  // For a STT_GNU_IFUNC symbol we want to write the PLT
                  // offset into the GOT, so that function pointer
                  // comparisons work correctly.
                  bool is_new;
                  if (gsym->type() != elfcpp::STT_GNU_IFUNC)
                    is_new = got->add_global(gsym, GOT_TYPE_STANDARD);
                  else
                    {
                      is_new = got->add_global_plt(gsym, GOT_TYPE_STANDARD);
                      // Tell the dynamic linker to use the PLT address
                      // when resolving relocations.
                      if (gsym->is_from_dynobj()
                          && !parameters->options().shared())
                        gsym->set_needs_dynsym_value();
                    }
                  if (is_new)
                    {
                      unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD);
                      rela_dyn->add_global_relative(gsym,
                                                    r_type,
                                                    got, got_off, 0, false);
                    }
                }
            }
        }
        break;
  
      // a minor difference here for R_TILEGX_JUMPOFF_X1
      // between bfd linker and gold linker for gold, when
      // R_TILEGX_JUMPOFF_X1 against global symbol, we
      // turn it into JUMPOFF_X1_PLT, otherwise the distance
      // to the symbol function may overflow at runtime.
      case elfcpp::R_TILEGX_JUMPOFF_X1:
  
      case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
        // If the symbol is fully resolved, this is just a PC32 reloc.
        // Otherwise we need a PLT entry.
        if (gsym->final_value_is_known())
          break;
        // If building a shared library, we can also skip the PLT entry
        // if the symbol is defined in the output file and is protected
        // or hidden.
        if (gsym->is_defined()
            && !gsym->is_from_dynobj()
            && !gsym->is_preemptible())
          break;
        target->make_plt_entry(symtab, layout, gsym);
        break;
  
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_TLS_GD_CALL:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_TLS_IE_LOAD:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
        {
           const bool is_final = gsym->final_value_is_known();
           const tls::Tls_optimization opt_t =
            Target_tilegx<size, big_endian>::optimize_tls_reloc(is_final,
                                                                r_type);
  
           switch (r_type)
             {
                // only expand to plt against __tls_get_addr in GD model
                case elfcpp::R_TILEGX_TLS_GD_CALL:
                  if (opt_t == tls::TLSOPT_NONE) {
                    // FIXME:  it's better '__tls_get_addr' referenced explicitly
                    if (!target->tls_get_addr_sym_defined_) {
                      Symbol* sym = NULL;
                      options::parse_set(NULL, "__tls_get_addr",
                                         (gold::options::String_set*)
                                         &parameters->options().undefined());
                      symtab->add_undefined_symbols_from_command_line(layout);
                      target->tls_get_addr_sym_defined_ = true;
                      sym = symtab->lookup("__tls_get_addr");
                      sym->set_in_reg();
                    }
                    target->make_plt_entry(symtab, layout,
                                           symtab->lookup("__tls_get_addr"));
                  }
                  break;
  
                // only make effect when applying relocation
                case elfcpp::R_TILEGX_TLS_IE_LOAD:
                case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
                case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
                case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
                case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
                case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
                case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
                case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
                case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
                  break;
  
                // GD: requires two GOT entry for module index and offset
                // IE: requires one GOT entry for tp-relative offset
                // LE: shouldn't happen for global symbol
                case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
                case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
                case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
                case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
                case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
                case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
                  {
                    if (opt_t == tls::TLSOPT_NONE) {
                        Output_data_got<size, big_endian>* got
                          = target->got_section(symtab, layout);
                        got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
                                               target->rela_dyn_section(layout),
                                               size == 32
                                             ? elfcpp::R_TILEGX_TLS_DTPMOD32
                                             : elfcpp::R_TILEGX_TLS_DTPMOD64,
                                               size == 32
                                             ? elfcpp::R_TILEGX_TLS_DTPOFF32
                                             : elfcpp::R_TILEGX_TLS_DTPOFF64);
                    } else if (opt_t == tls::TLSOPT_TO_IE) {
                      // Create a GOT entry for the tp-relative offset.
                      Output_data_got<size, big_endian>* got
                         = target->got_section(symtab, layout);
                      got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
                                             target->rela_dyn_section(layout),
                                             size == 32
                                             ? elfcpp::R_TILEGX_TLS_TPOFF32
                                             : elfcpp::R_TILEGX_TLS_TPOFF64);
                    } else if (opt_t != tls::TLSOPT_TO_LE)
                      // exteranl symbol should not be optimized to TO_LE
                      unsupported_reloc_global(object, r_type, gsym);
                  }
                  break;
  
                // IE
                case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
                case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
                case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
                case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
                case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
                case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
                  {
                      layout->set_has_static_tls();
                    if (opt_t == tls::TLSOPT_NONE) {
                      // Create a GOT entry for the tp-relative offset.
                      Output_data_got<size, big_endian>* got
                         = target->got_section(symtab, layout);
                      got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
                                             target->rela_dyn_section(layout),
                                             size == 32
                                             ? elfcpp::R_TILEGX_TLS_TPOFF32
                                             : elfcpp::R_TILEGX_TLS_TPOFF64);
                    } else if (opt_t != tls::TLSOPT_TO_LE)
                      unsupported_reloc_global(object, r_type, gsym);
                  }
                  break;
  
                // LE
                case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
                case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
                case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
                case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
                case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
                case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
                    layout->set_has_static_tls();
                  if (parameters->options().shared()) {
                    // defer to dynamic linker
                    Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                    rela_dyn->add_symbolless_global_addend(gsym, r_type,
                                                        output_section, object,
                                                        data_shndx,
                                                        reloc.get_r_offset(), 0);
                    }
                  break;
  
                default:
                  gold_unreachable();
             }
        }
        break;
  
      // below are outstanding relocs
      // should not existed in static linking stage
      case elfcpp::R_TILEGX_COPY:
      case elfcpp::R_TILEGX_GLOB_DAT:
      case elfcpp::R_TILEGX_JMP_SLOT:
      case elfcpp::R_TILEGX_RELATIVE:
      case elfcpp::R_TILEGX_TLS_TPOFF32:
      case elfcpp::R_TILEGX_TLS_TPOFF64:
      case elfcpp::R_TILEGX_TLS_DTPMOD32:
      case elfcpp::R_TILEGX_TLS_DTPMOD64:
      case elfcpp::R_TILEGX_TLS_DTPOFF32:
      case elfcpp::R_TILEGX_TLS_DTPOFF64:
        gold_error(_("%s: unexpected reloc %u in object file"),
                   object->name().c_str(), r_type);
        break;
  
      default:
        gold_error(_("%s: unsupported reloc %u against global symbol %s"),
                   object->name().c_str(), r_type,
                   gsym->demangled_name().c_str());
        break;
      }
  }
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::gc_process_relocs(Symbol_table* symtab,
                                    Layout* layout,
                                    Sized_relobj_file<size, big_endian>* object,
                                    unsigned int data_shndx,
                                    unsigned int sh_type,
                                    const unsigned char* prelocs,
                                    size_t reloc_count,
                                    Output_section* output_section,
                                    bool needs_special_offset_handling,
                                    size_t local_symbol_count,
                                    const unsigned char* plocal_symbols)
  {
    typedef Target_tilegx<size, big_endian> Tilegx;
    typedef typename Target_tilegx<size, big_endian>::Scan Scan;
    typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
        Classify_reloc;
  
    if (sh_type == elfcpp::SHT_REL)
      {
        return;
      }
  
     gold::gc_process_relocs<size, big_endian, Tilegx, Scan, Classify_reloc>(
       symtab,
       layout,
       this,
       object,
       data_shndx,
       prelocs,
       reloc_count,
       output_section,
       needs_special_offset_handling,
       local_symbol_count,
       plocal_symbols);
  }
  // Scan relocations for a section.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::scan_relocs(Symbol_table* symtab,
                                   Layout* layout,
                                   Sized_relobj_file<size, big_endian>* object,
                                   unsigned int data_shndx,
                                   unsigned int sh_type,
                                   const unsigned char* prelocs,
                                   size_t reloc_count,
                                   Output_section* output_section,
                                   bool needs_special_offset_handling,
                                   size_t local_symbol_count,
                                   const unsigned char* plocal_symbols)
  {
    typedef Target_tilegx<size, big_endian> Tilegx;
    typedef typename Target_tilegx<size, big_endian>::Scan Scan;
    typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
        Classify_reloc;
  
    if (sh_type == elfcpp::SHT_REL)
      {
        gold_error(_("%s: unsupported REL reloc section"),
                   object->name().c_str());
        return;
      }
  
    gold::scan_relocs<size, big_endian, Tilegx, Scan, Classify_reloc>(
      symtab,
      layout,
      this,
      object,
      data_shndx,
      prelocs,
      reloc_count,
      output_section,
      needs_special_offset_handling,
      local_symbol_count,
      plocal_symbols);
  }
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::do_define_standard_symbols(
      Symbol_table* symtab,
      Layout* layout)
  {
    Output_section* feedback_section = layout->find_output_section(".feedback");
  
    if (feedback_section != NULL)
      {
        symtab->define_in_output_data("__feedback_section_end",
                      NULL,
                      Symbol_table::PREDEFINED,
                      feedback_section,
                      0,
                      0,
                      elfcpp::STT_NOTYPE,
                      elfcpp::STB_GLOBAL,
                      elfcpp::STV_HIDDEN,
                      0,
                      true, // offset_is_from_end
                      false);
      }
  }
  
  // Finalize the sections.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::do_finalize_sections(
      Layout* layout,
      const Input_objects*,
      Symbol_table* symtab)
  {
    const Reloc_section* rel_plt = (this->plt_ == NULL
                                    ? NULL
                                    : this->plt_->rela_plt());
    layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
                                    this->rela_dyn_, true, true);
  
    // Emit any relocs we saved in an attempt to avoid generating COPY
    // relocs.
    if (this->copy_relocs_.any_saved_relocs())
      this->copy_relocs_.emit(this->rela_dyn_section(layout));
  
    // Set the size of the _GLOBAL_OFFSET_TABLE_ symbol to the size of
    // the .got section.
    Symbol* sym = this->global_offset_table_;
    if (sym != NULL)
      {
        uint64_t data_size = this->got_->current_data_size();
        symtab->get_sized_symbol<size>(sym)->set_symsize(data_size);
  
        // If the .got section is more than 0x8000 bytes, we add
        // 0x8000 to the value of _GLOBAL_OFFSET_TABLE_, so that 16
        // bit relocations have a greater chance of working.
        if (data_size >= 0x8000)
          symtab->get_sized_symbol<size>(sym)->set_value(
            symtab->get_sized_symbol<size>(sym)->value() + 0x8000);
      }
  
    if (parameters->doing_static_link()
        && (this->plt_ == NULL || !this->plt_->has_irelative_section()))
      {
        // If linking statically, make sure that the __rela_iplt symbols
        // were defined if necessary, even if we didn't create a PLT.
        static const Define_symbol_in_segment syms[] =
          {
            {
              "__rela_iplt_start",        // name
              elfcpp::PT_LOAD,            // segment_type
              elfcpp::PF_W,               // segment_flags_set
              elfcpp::PF(0),              // segment_flags_clear
              0,                          // value
              0,                          // size
              elfcpp::STT_NOTYPE,         // type
              elfcpp::STB_GLOBAL,         // binding
              elfcpp::STV_HIDDEN,         // visibility
              0,                          // nonvis
              Symbol::SEGMENT_START,      // offset_from_base
              true                        // only_if_ref
            },
            {
              "__rela_iplt_end",          // name
              elfcpp::PT_LOAD,            // segment_type
              elfcpp::PF_W,               // segment_flags_set
              elfcpp::PF(0),              // segment_flags_clear
              0,                          // value
              0,                          // size
              elfcpp::STT_NOTYPE,         // type
              elfcpp::STB_GLOBAL,         // binding
              elfcpp::STV_HIDDEN,         // visibility
              0,                          // nonvis
              Symbol::SEGMENT_START,      // offset_from_base
              true                        // only_if_ref
            }
          };
  
        symtab->define_symbols(layout, 2, syms,
                               layout->script_options()->saw_sections_clause());
      }
  }
  
  // Perform a relocation.
  
  template<int size, bool big_endian>
  inline bool
  Target_tilegx<size, big_endian>::Relocate::relocate(
      const Relocate_info<size, big_endian>* relinfo,
      unsigned int,
      Target_tilegx<size, big_endian>* target,
      Output_section*,
      size_t relnum,
      const unsigned char* preloc,
      const Sized_symbol<size>* gsym,
      const Symbol_value<size>* psymval,
      unsigned char* view,
      typename elfcpp::Elf_types<size>::Elf_Addr address,
      section_size_type)
  {
    if (view == NULL)
      return true;
  
    typedef Tilegx_relocate_functions<size, big_endian> TilegxReloc;
    typename TilegxReloc::Tilegx_howto r_howto;
  
    const elfcpp::Rela<size, big_endian> rela(preloc);
    unsigned int r_type = elfcpp::elf_r_type<size>(rela.get_r_info());
    const Sized_relobj_file<size, big_endian>* object = relinfo->object;
  
    // Pick the value to use for symbols defined in the PLT.
    Symbol_value<size> symval;
    if (gsym != NULL
        && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
      {
        symval.set_output_value(target->plt_address_for_global(gsym));
        psymval = &symval;
      }
    else if (gsym == NULL && psymval->is_ifunc_symbol())
      {
        unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
        if (object->local_has_plt_offset(r_sym))
          {
            symval.set_output_value(target->plt_address_for_local(object, r_sym));
            psymval = &symval;
          }
      }
  
    elfcpp::Elf_Xword addend = rela.get_r_addend();
  
    // Get the GOT offset if needed.
    // For tilegx, the GOT pointer points to the start of the GOT section.
    bool have_got_offset = false;
    int got_offset = 0;
    int got_base = target->got_ != NULL
                   ? target->got_->current_data_size() >= 0x8000 ? 0x8000 : 0
                   : 0;
    unsigned int got_type = GOT_TYPE_STANDARD;
    bool always_apply_relocation = false;
    switch (r_type)
      {
      case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
        if (gsym != NULL)
          {
            gold_assert(gsym->has_got_offset(got_type));
            got_offset = gsym->got_offset(got_type) - got_base;
          }
        else
          {
            unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
            gold_assert(object->local_has_got_offset(r_sym, got_type));
            got_offset =
              object->local_got_offset(r_sym, got_type) - got_base;
          }
        have_got_offset = true;
        break;
  
      default:
        break;
      }
  
    r_howto = TilegxReloc::howto[r_type];
    switch (r_type)
      {
      case elfcpp::R_TILEGX_NONE:
      case elfcpp::R_TILEGX_GNU_VTINHERIT:
      case elfcpp::R_TILEGX_GNU_VTENTRY:
        break;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_GOT:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_GOT:
        gold_assert(have_got_offset);
        symval.set_output_value(got_offset);
        psymval = &symval;
        always_apply_relocation = true;
        addend = 0;
        // Fall through.
  
      // when under PIC mode, these relocations are deferred to rtld
      case elfcpp::R_TILEGX_IMM16_X0_HW0:
      case elfcpp::R_TILEGX_IMM16_X1_HW0:
      case elfcpp::R_TILEGX_IMM16_X0_HW1:
      case elfcpp::R_TILEGX_IMM16_X1_HW1:
      case elfcpp::R_TILEGX_IMM16_X0_HW2:
      case elfcpp::R_TILEGX_IMM16_X1_HW2:
      case elfcpp::R_TILEGX_IMM16_X0_HW3:
      case elfcpp::R_TILEGX_IMM16_X1_HW3:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST:
        if (always_apply_relocation
            || !parameters->options().output_is_position_independent())
          TilegxReloc::imm_x_general(view, object, psymval, addend, r_howto);
        break;
  
      case elfcpp::R_TILEGX_JUMPOFF_X1:
      case elfcpp::R_TILEGX_JUMPOFF_X1_PLT:
        gold_assert(gsym == NULL
                    || gsym->has_plt_offset()
                    || gsym->final_value_is_known()
                    || (gsym->is_defined()
                        && !gsym->is_from_dynobj()
                        && !gsym->is_preemptible()));
        TilegxReloc::imm_x_pcrel_general(view, object, psymval, addend,
                                         address, r_howto);
        break;
  
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW3_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL:
      case elfcpp::R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
        TilegxReloc::imm_x_pcrel_general(view, object, psymval, addend,
                                         address, r_howto);
        break;
  
      case elfcpp::R_TILEGX_BROFF_X1:
      case elfcpp::R_TILEGX_DEST_IMM8_X1:
        TilegxReloc::imm_x_two_part_general(view, object, psymval,
                                            addend, address, r_type);
        break;
  
  
      // below are general relocation types, which can be
      // handled by target-independent handlers
      case elfcpp::R_TILEGX_64:
        TilegxReloc::abs64(view, object, psymval, addend);
        break;
  
      case elfcpp::R_TILEGX_64_PCREL:
        TilegxReloc::pc_abs64(view, object, psymval, addend, address);
        break;
  
      case elfcpp::R_TILEGX_32:
        TilegxReloc::abs32(view, object, psymval, addend);
        break;
  
      case elfcpp::R_TILEGX_32_PCREL:
        TilegxReloc::pc_abs32(view, object, psymval, addend, address);
        break;
  
      case elfcpp::R_TILEGX_16:
        TilegxReloc::abs16(view, object, psymval, addend);
        break;
  
      case elfcpp::R_TILEGX_16_PCREL:
        TilegxReloc::pc_abs16(view, object, psymval, addend, address);
        break;
  
      case elfcpp::R_TILEGX_8:
        Relocate_functions<size, big_endian>::rela8(view, object,
                                                    psymval, addend);
        break;
  
      case elfcpp::R_TILEGX_8_PCREL:
        Relocate_functions<size, big_endian>::pcrela8(view, object,
                                                      psymval, addend, address);
        break;
  
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
      case elfcpp::R_TILEGX_TLS_GD_CALL:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
      case elfcpp::R_TILEGX_TLS_IE_LOAD:
      case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
      case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
        {
          const bool is_final = (gsym == NULL
                                 ? !parameters->options().shared()
                                 : gsym->final_value_is_known());
          tls::Tls_optimization opt_t =
            Target_tilegx<size, big_endian>::optimize_tls_reloc(is_final,
                                                                r_type);
  
          switch (r_type)
            {
  
              case elfcpp::R_TILEGX_TLS_GD_CALL:
                {
                  if (opt_t == tls::TLSOPT_NONE) {
                    Symbol *tls_sym = relinfo->symtab->lookup("__tls_get_addr");
                    symval.set_output_value(
                      target->plt_address_for_global(tls_sym));
                    psymval = &symval;
                    TilegxReloc::imm_x_pcrel_general(view, object, psymval,
                                                     addend, address, r_howto);
                  }
                  else if (opt_t == tls::TLSOPT_TO_IE
                           || opt_t == tls::TLSOPT_TO_LE)
                    TilegxReloc::tls_relax(view, r_type, opt_t);
                }
                break;
  
              // XX_TLS_GD is the same as normal X_GOT relocation
              // except allocating a got entry pair,
              case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
              case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
              case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
              case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
              case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
              case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
                if (opt_t == tls::TLSOPT_NONE) {
                  got_type = GOT_TYPE_TLS_PAIR;
                  have_got_offset = true;
                } else if (opt_t == tls::TLSOPT_TO_IE) {
                  got_type = GOT_TYPE_TLS_OFFSET;
                  have_got_offset = true;
                }
                goto do_update_value;
              // XX_TLS_IE is the same as normal X_GOT relocation
              // except allocating one additional runtime relocation
              case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
              case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
              case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
              case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
              case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
              case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
                if (opt_t == tls::TLSOPT_NONE) {
                  got_type = GOT_TYPE_TLS_OFFSET;
                  have_got_offset = true;
                }
  	      // Fall through.
              do_update_value:
                if (have_got_offset) {
                  if (gsym != NULL) {
                    gold_assert(gsym->has_got_offset(got_type));
                    got_offset = gsym->got_offset(got_type) - got_base;
                  } else {
                    unsigned int r_sym
                       = elfcpp::elf_r_sym<size>(rela.get_r_info());
                    gold_assert(object->local_has_got_offset(r_sym, got_type));
                    got_offset =
                      object->local_got_offset(r_sym, got_type) - got_base;
                  }
                }
  
                if (opt_t == tls::TLSOPT_NONE
                    || opt_t == tls::TLSOPT_TO_IE) {
                  // for both GD/IE, these relocations
                  // actually calculate got offset, so
                  // there behavior are the same
                  gold_assert(have_got_offset);
                  symval.set_output_value(got_offset);
                  psymval = &symval;
                  addend = 0;
                  TilegxReloc::imm_x_general(view, object, psymval,
                                             addend, r_howto);
                  break;
                } // else if (opt_t == tls::TLSOPT_TO_LE)
                  //   both GD/IE are turned into LE, which
                  //   is absolute relocation.
                  // Fall through.
  
              // LE
              //
              // tp
              // |
              // V
              //  t_var1 | t_var2 | t_var3 | ...
              //  --------------------------------------------------
              //
              //  so offset to tp should be negative, we get offset
              //  from the following formular for LE
              //
              //    t_var1_off = t_var1_sym_value - tls_section_start
              //
              case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
              case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
              case elfcpp::R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE:
              case elfcpp::R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE:
              case elfcpp::R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE:
              case elfcpp::R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE:
                {
                  Output_segment *tls_segment = relinfo->layout->tls_segment();
                  if (tls_segment == NULL) {
                    gold_assert(parameters->errors()->error_count() > 0
                                || issue_undefined_symbol_error(gsym));
                    return false;
                  }
  
                  typename elfcpp::Elf_types<size>::Elf_Addr value
                    = psymval->value(relinfo->object, 0);
                  symval.set_output_value(value);
                  psymval = &symval;
                  TilegxReloc::imm_x_general(view, object, psymval,
                                             addend, r_howto);
                }
                break;
  
              // tls relaxation
              case elfcpp::R_TILEGX_TLS_IE_LOAD:
              case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
              case elfcpp::R_TILEGX_IMM8_X1_TLS_ADD:
              case elfcpp::R_TILEGX_IMM8_Y0_TLS_ADD:
              case elfcpp::R_TILEGX_IMM8_Y1_TLS_ADD:
              case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
              case elfcpp::R_TILEGX_IMM8_X1_TLS_GD_ADD:
              case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
              case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
                TilegxReloc::tls_relax(view, r_type, opt_t);
                break;
  
              default:
                gold_unreachable();
            }
        }
        break;
  
      // below are outstanding relocs
      // should not existed in static linking stage
      case elfcpp::R_TILEGX_COPY:
      case elfcpp::R_TILEGX_GLOB_DAT:
      case elfcpp::R_TILEGX_JMP_SLOT:
      case elfcpp::R_TILEGX_RELATIVE:
      case elfcpp::R_TILEGX_TLS_TPOFF32:
      case elfcpp::R_TILEGX_TLS_TPOFF64:
      case elfcpp::R_TILEGX_TLS_DTPMOD32:
      case elfcpp::R_TILEGX_TLS_DTPMOD64:
      case elfcpp::R_TILEGX_TLS_DTPOFF32:
      case elfcpp::R_TILEGX_TLS_DTPOFF64:
        gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                               _("unexpected reloc %u in object file"),
                               r_type);
        break;
  
      default:
        gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                               _("unsupported reloc %u"),
                               r_type);
        break;
      }
  
    return true;
  }
  
  // Relocate section data.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::relocate_section(
      const Relocate_info<size, big_endian>* relinfo,
      unsigned int sh_type,
      const unsigned char* prelocs,
      size_t reloc_count,
      Output_section* output_section,
      bool needs_special_offset_handling,
      unsigned char* view,
      typename elfcpp::Elf_types<size>::Elf_Addr address,
      section_size_type view_size,
      const Reloc_symbol_changes* reloc_symbol_changes)
  {
    typedef Target_tilegx<size, big_endian> Tilegx;
    typedef typename Target_tilegx<size, big_endian>::Relocate Tilegx_relocate;
    typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
        Classify_reloc;
  
    gold_assert(sh_type == elfcpp::SHT_RELA);
  
    gold::relocate_section<size, big_endian, Tilegx, Tilegx_relocate,
  			 gold::Default_comdat_behavior, Classify_reloc>(
      relinfo,
      this,
      prelocs,
      reloc_count,
      output_section,
      needs_special_offset_handling,
      view,
      address,
      view_size,
      reloc_symbol_changes);
  }
  
  // Apply an incremental relocation.  Incremental relocations always refer
  // to global symbols.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::apply_relocation(
      const Relocate_info<size, big_endian>* relinfo,
      typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
      unsigned int r_type,
      typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
      const Symbol* gsym,
      unsigned char* view,
      typename elfcpp::Elf_types<size>::Elf_Addr address,
      section_size_type view_size)
  {
    gold::apply_relocation<size, big_endian, Target_tilegx<size, big_endian>,
                           typename Target_tilegx<size, big_endian>::Relocate>(
      relinfo,
      this,
      r_offset,
      r_type,
      r_addend,
      gsym,
      view,
      address,
      view_size);
  }
  
  // Scan the relocs during a relocatable link.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::scan_relocatable_relocs(
      Symbol_table* symtab,
      Layout* layout,
      Sized_relobj_file<size, big_endian>* object,
      unsigned int data_shndx,
      unsigned int sh_type,
      const unsigned char* prelocs,
      size_t reloc_count,
      Output_section* output_section,
      bool needs_special_offset_handling,
      size_t local_symbol_count,
      const unsigned char* plocal_symbols,
      Relocatable_relocs* rr)
  {
    typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
        Classify_reloc;
    typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
        Scan_relocatable_relocs;
  
    gold_assert(sh_type == elfcpp::SHT_RELA);
  
    gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
      symtab,
      layout,
      object,
      data_shndx,
      prelocs,
      reloc_count,
      output_section,
      needs_special_offset_handling,
      local_symbol_count,
      plocal_symbols,
      rr);
  }
  
  // Scan the relocs for --emit-relocs.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::emit_relocs_scan(
      Symbol_table* symtab,
      Layout* layout,
      Sized_relobj_file<size, big_endian>* object,
      unsigned int data_shndx,
      unsigned int sh_type,
      const unsigned char* prelocs,
      size_t reloc_count,
      Output_section* output_section,
      bool needs_special_offset_handling,
      size_t local_symbol_count,
      const unsigned char* plocal_syms,
      Relocatable_relocs* rr)
  {
    typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
        Classify_reloc;
    typedef gold::Default_emit_relocs_strategy<Classify_reloc>
        Emit_relocs_strategy;
  
    gold_assert(sh_type == elfcpp::SHT_RELA);
  
    gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
      symtab,
      layout,
      object,
      data_shndx,
      prelocs,
      reloc_count,
      output_section,
      needs_special_offset_handling,
      local_symbol_count,
      plocal_syms,
      rr);
  }
  
  // Relocate a section during a relocatable link.
  
  template<int size, bool big_endian>
  void
  Target_tilegx<size, big_endian>::relocate_relocs(
      const Relocate_info<size, big_endian>* relinfo,
      unsigned int sh_type,
      const unsigned char* prelocs,
      size_t reloc_count,
      Output_section* output_section,
      typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
      unsigned char* view,
      typename elfcpp::Elf_types<size>::Elf_Addr view_address,
      section_size_type view_size,
      unsigned char* reloc_view,
      section_size_type reloc_view_size)
  {
    typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
        Classify_reloc;
  
    gold_assert(sh_type == elfcpp::SHT_RELA);
  
    gold::relocate_relocs<size, big_endian, Classify_reloc>(
      relinfo,
      prelocs,
      reloc_count,
      output_section,
      offset_in_output_section,
      view,
      view_address,
      view_size,
      reloc_view,
      reloc_view_size);
  }
  
  // Return the value to use for a dynamic which requires special
  // treatment.  This is how we support equality comparisons of function
  // pointers across shared library boundaries, as described in the
  // processor specific ABI supplement.
  
  template<int size, bool big_endian>
  uint64_t
  Target_tilegx<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
  {
    gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
    return this->plt_address_for_global(gsym);
  }
  
  // Return the value to use for the base of a DW_EH_PE_datarel offset
  // in an FDE.  Solaris and SVR4 use DW_EH_PE_datarel because their
  // assembler can not write out the difference between two labels in
  // different sections, so instead of using a pc-relative value they
  // use an offset from the GOT.
  
  template<int size, bool big_endian>
  uint64_t
  Target_tilegx<size, big_endian>::do_ehframe_datarel_base() const
  {
    gold_assert(this->global_offset_table_ != NULL);
    Symbol* sym = this->global_offset_table_;
    Sized_symbol<size>* ssym = static_cast<Sized_symbol<size>*>(sym);
    return ssym->value();
  }
  
  // The selector for tilegx object files.
  
  template<int size, bool big_endian>
  class Target_selector_tilegx : public Target_selector
  {
  public:
    Target_selector_tilegx()
      : Target_selector(elfcpp::EM_TILEGX, size, big_endian,
                        (size == 64
                         ? (big_endian ? "elf64-tilegx-be" : "elf64-tilegx-le")
                            : (big_endian ? "elf32-tilegx-be"
                                             : "elf32-tilegx-le")),
                        (size == 64
                         ? (big_endian ? "elf64tilegx_be" : "elf64tilegx")
                            : (big_endian ? "elf32tilegx_be" : "elf32tilegx")))
    { }
  
    Target*
    do_instantiate_target()
    { return new Target_tilegx<size, big_endian>(); }
  
  };
  
  Target_selector_tilegx<64, false> target_selector_tilegx64_le;
  Target_selector_tilegx<32, false> target_selector_tilegx32_le;
  Target_selector_tilegx<64, true> target_selector_tilegx64_be;
  Target_selector_tilegx<32, true> target_selector_tilegx32_be;
  } // End anonymous namespace.
  