// s390.cc -- s390 target support for gold.

// Copyright (C) 2015-2024 Free Software Foundation, Inc.
// Written by Marcin Koƛcielnicki <[email protected]>.

// 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 "s390.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"

namespace
{

using namespace gold;

// A class to handle the .got.plt section.

template<int size>
class Output_data_got_plt_s390 : public Output_section_data_build
{
public:
 Output_data_got_plt_s390(Layout* layout)
   : Output_section_data_build(size/8),
     layout_(layout)
 { }

 Output_data_got_plt_s390(Layout* layout, off_t data_size)
   : Output_section_data_build(data_size, size/8),
     layout_(layout)
 { }

protected:
 // Write out the PLT data.
 void
 do_write(Output_file*);

 // Write to a map file.
 void
 do_print_to_mapfile(Mapfile* mapfile) const
 { mapfile->print_output_data(this, "** GOT PLT"); }

private:
 // A pointer to the Layout class, so that we can find the .dynamic
 // section when we write out the GOT PLT section.
 Layout* layout_;
};

// A class to handle the PLT data.

template<int size>
class Output_data_plt_s390 : public Output_section_data
{
public:
 typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, true>
   Reloc_section;

 Output_data_plt_s390(Layout* layout,
                        Output_data_got<size, true>* got,
                        Output_data_got_plt_s390<size>* got_plt,
                        Output_data_space* got_irelative)
   : Output_section_data(4), 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_s390(Layout* layout,
                        Output_data_got<size, true>* got,
                        Output_data_got_plt_s390<size>* got_plt,
                        Output_data_space* got_irelative,
                        unsigned int plt_count)
   : Output_section_data((plt_count + 1) * plt_entry_size,
                         4, 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, true>*, 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 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) * plt_entry_size,
                           (plt_index + 2) * 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);

 // Add .eh_frame information for the PLT.
 void
 add_eh_frame(Layout* layout)
 {
         (void)layout;
   layout->add_eh_frame_for_plt(this,
                                plt_eh_frame_cie,
                                plt_eh_frame_cie_size,
                                plt_eh_frame_fde,
                                plt_eh_frame_fde_size);
 }

protected:
 // Fill in the first PLT entry.
 void
 fill_first_plt_entry(unsigned char* pov,
                      typename elfcpp::Elf_types<size>::Elf_Addr got_address,
                      typename elfcpp::Elf_types<size>::Elf_Addr plt_address);

 // Fill in a normal PLT entry.  Returns the offset into the entry that
 // should be the initial GOT slot value.
 unsigned int
 fill_plt_entry(unsigned char* pov,
                typename elfcpp::Elf_types<size>::Elf_Addr got_address,
                typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
                unsigned int got_offset,
                unsigned int plt_offset,
                unsigned int plt_rel_offset);

 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, true>* got_;
 // The .got.plt section.
 Output_data_got_plt_s390<size>* 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 = 0x20;
 // The first entry in the PLT.
 static const unsigned char first_plt_entry_32_abs[plt_entry_size];
 static const unsigned char first_plt_entry_32_pic[plt_entry_size];
 static const unsigned char first_plt_entry_64[plt_entry_size];
 // Other entries in the PLT for an executable.
 static const unsigned char plt_entry_32_abs[plt_entry_size];
 static const unsigned char plt_entry_32_pic12[plt_entry_size];
 static const unsigned char plt_entry_32_pic16[plt_entry_size];
 static const unsigned char plt_entry_32_pic[plt_entry_size];
 static const unsigned char plt_entry_64[plt_entry_size];

 // The .eh_frame unwind information for the PLT.
 static const int plt_eh_frame_cie_size = 12;
 static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
 static const int plt_eh_frame_fde_size = 12;
 static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
};


template<int size>
class Target_s390 : public Sized_target<size, true>
{
public:
 typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, true> Reloc_section;

 Target_s390()
   : Sized_target<size, true>(&s390_info),
     got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
     global_offset_table_(NULL), rela_dyn_(NULL),
     rela_irelative_(NULL), copy_relocs_(elfcpp::R_390_COPY),
     got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
     layout_(NULL)
 { }

 // Scan the relocations to look for symbol adjustments.
 void
 gc_process_relocs(Symbol_table* symtab,
                   Layout* layout,
                   Sized_relobj_file<size, true>* 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, true>* 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, true>*,
                  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, true>* 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, true>* 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);

 // Return a string used to fill a code section with nops.
 std::string
 do_code_fill(section_size_type length) const;

 // Emit relocations for a section.
 void
 relocate_relocs(
     const Relocate_info<size, true>*,
     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_offset") == 0; }

 // Return the PLT address to use for a global symbol.
 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); }

 // Return the offset to use for the GOT_INDX'th got entry which is
 // for a local tls symbol specified by OBJECT, SYMNDX.
 int64_t
 do_tls_offset_for_local(const Relobj* object,
                         unsigned int symndx,
                         Output_data_got_base* got,
                         unsigned int got_indx,
                         uint64_t addend) const;

 // Return the offset to use for the GOT_INDX'th got entry which is
 // for global tls symbol GSYM.
 int64_t
 do_tls_offset_for_global(Symbol* gsym,
                          Output_data_got_base* got,
                          unsigned int got_indx,
                          uint64_t addend) const;

 // 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.
 bool
 do_can_check_for_function_pointers() const
 { return true; }

 // Return whether SYM is call to a non-split function.
 bool
 do_is_call_to_non_split(const Symbol* sym, const unsigned char* preloc,
                         const unsigned char* view,
                         section_size_type view_size) const;

 // Adjust -fsplit-stack code which calls non-split-stack code.
 void
 do_calls_non_split(Relobj* object, unsigned int shndx,
                    section_offset_type fnoffset, section_size_type fnsize,
                    const unsigned char* prelocs, size_t reloc_count,
                    unsigned char* view, section_size_type view_size,
                    std::string* from, std::string* to) const;

 // 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, true>* 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, true>* 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_s390* target,
         Sized_relobj_file<size, true>* object,
         unsigned int data_shndx,
         Output_section* output_section,
         const elfcpp::Rela<size, true>& reloc, unsigned int r_type,
         const elfcpp::Sym<size, true>& lsym,
         bool is_discarded);

   inline void
   global(Symbol_table* symtab, Layout* layout, Target_s390* target,
          Sized_relobj_file<size, true>* object,
          unsigned int data_shndx,
          Output_section* output_section,
          const elfcpp::Rela<size, true>& reloc, unsigned int r_type,
          Symbol* gsym);

   inline bool
   local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
                                       Target_s390* target,
                                       Sized_relobj_file<size, true>* object,
                                       unsigned int data_shndx,
                                       Output_section* output_section,
                                       const elfcpp::Rela<size, true>& reloc,
                                       unsigned int r_type,
                                       const elfcpp::Sym<size, true>& lsym);

   inline bool
   global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
                                        Target_s390* target,
                                        Sized_relobj_file<size, true>* object,
                                        unsigned int data_shndx,
                                        Output_section* output_section,
                                        const elfcpp::Rela<size, true>& reloc,
                                        unsigned int r_type,
                                        Symbol* gsym);

 private:
   static void
   unsupported_reloc_local(Sized_relobj_file<size, true>*,
                           unsigned int r_type);

   static void
   unsupported_reloc_global(Sized_relobj_file<size, true>*,
                            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, true>*,
                             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:
   // Do a relocation.  Return false if the caller should not issue
   // any warnings about this relocation.
   inline bool
   relocate(const Relocate_info<size, true>*, unsigned int,
            Target_s390*, 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);

  private:
   // Do a TLS relocation.
   inline typename elfcpp::Elf_types<size>::Elf_Addr
   relocate_tls(const Relocate_info<size, true>*, Target_s390*,
                size_t relnum, const elfcpp::Rela<size, true>&,
                unsigned int r_type, const Sized_symbol<size>*,
                const Symbol_value<size>*,
                unsigned char*, section_size_type);

   // Do a TLS General-Dynamic to Initial-Exec transition.
   inline void
   tls_gd_to_ie(const Relocate_info<size, true>*, size_t relnum,
                const elfcpp::Rela<size, true>&,
                unsigned char* view,
                section_size_type view_size);

   // Do a TLS General-Dynamic to Local-Exec transition.
   inline void
   tls_gd_to_le(const Relocate_info<size, true>*, size_t relnum,
                const elfcpp::Rela<size, true>&,
                unsigned char* view,
                section_size_type view_size);

   // Do a TLS Local-Dynamic to Local-Exec transition.
   inline void
   tls_ld_to_le(const Relocate_info<size, true>*, size_t relnum,
                const elfcpp::Rela<size, true>&,
                unsigned char* view,
                section_size_type view_size);

   // Do a TLS Initial-Exec to Local-Exec transition.
   static inline void
   tls_ie_to_le(const Relocate_info<size, true>*, size_t relnum,
                const elfcpp::Rela<size, true>&,
                unsigned char* view,
                section_size_type view_size);
 };

 // 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.
 const Output_data_got<size, true>*
 got_section() const
 {
   gold_assert(this->got_ != NULL);
   return this->got_;
 }

 // Get the GOT section, creating it if necessary.
 Output_data_got<size, true>*
 got_section(Symbol_table*, Layout*);

 typename elfcpp::Elf_types<size>::Elf_Addr
 got_address() const
 {
   gold_assert(this->got_ != NULL);
   return this->got_plt_->address();
 }

 typename elfcpp::Elf_types<size>::Elf_Addr
 got_main_offset() const
 {
   gold_assert(this->got_ != NULL);
   return this->got_->address() - this->got_address();
 }

 // 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, true>* 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, true>* object);

 // Get the PLT section.
 Output_data_plt_s390<size>*
 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, true>* object,
            unsigned int shndx, Output_section* output_section,
            Symbol* sym, const elfcpp::Rela<size, true>& 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));
 }

 // A function for targets to call.  Return whether BYTES/LEN matches
 // VIEW/VIEW_SIZE at OFFSET.  Like the one in Target, but takes
 // an unsigned char * parameter.
 bool
 match_view_u(const unsigned char* view, section_size_type view_size,
    section_offset_type offset, const unsigned char* bytes, size_t len) const
   {
     return this->match_view(view, view_size, offset,
                             reinterpret_cast<const char*>(bytes), len);
   }

 // Information about this specific target which we pass to the
 // general Target structure.
 static Target::Target_info s390_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
 };

 // The GOT section.
 Output_data_got<size, true>* got_;
 // The PLT section.
 Output_data_plt_s390<size>* plt_;
 // The GOT PLT section.
 Output_data_got_plt_s390<size>* got_plt_;
 // The GOT section for IRELATIVE relocations.
 Output_data_space* got_irelative_;
 // The _GLOBAL_OFFSET_TABLE_ symbol.
 Symbol* global_offset_table_;
 // 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, true> copy_relocs_;
 // Offset of the GOT entry for the TLS module index.
 unsigned int got_mod_index_offset_;
 // True if the _TLS_MODULE_BASE_ symbol has been defined.
 bool tls_base_symbol_defined_;
 // For use in do_tls_offset_for_*
 Layout *layout_;

 // Code sequences for -fsplit-stack matching.
 static const unsigned char ss_code_bras_8[];
 static const unsigned char ss_code_l_basr[];
 static const unsigned char ss_code_a_basr[];
 static const unsigned char ss_code_larl[];
 static const unsigned char ss_code_brasl[];
 static const unsigned char ss_code_jg[];
 static const unsigned char ss_code_jgl[];

 // Variable code sequence matchers for -fsplit-stack.
 bool ss_match_st_r14(unsigned char* view,
                      section_size_type view_size,
                      section_offset_type *offset) const;
 bool ss_match_l_r14(unsigned char* view,
                     section_size_type view_size,
                     section_offset_type *offset) const;
 bool ss_match_mcount(unsigned char* view,
                      section_size_type view_size,
                      section_offset_type *offset) const;
 bool ss_match_ear(unsigned char* view,
                   section_size_type view_size,
                   section_offset_type *offset) const;
 bool ss_match_c(unsigned char* view,
                 section_size_type view_size,
                 section_offset_type *offset) const;
 bool ss_match_l(unsigned char* view,
                 section_size_type view_size,
                 section_offset_type *offset,
                 int *guard_reg) const;
 bool ss_match_ahi(unsigned char* view,
                   section_size_type view_size,
                   section_offset_type *offset,
                   int guard_reg,
                   uint32_t *arg) const;
 bool ss_match_alfi(unsigned char* view,
                    section_size_type view_size,
                    section_offset_type *offset,
                    int guard_reg,
                    uint32_t *arg) const;
 bool ss_match_cr(unsigned char* view,
                  section_size_type view_size,
                  section_offset_type *offset,
                  int guard_reg) const;
};

template<>
Target::Target_info Target_s390<32>::s390_info =
{
 32,                   // size
 true,                 // is_big_endian
 elfcpp::EM_S390,      // machine_code
 false,                // has_make_symbol
 false,                // has_resolve
 true,                 // has_code_fill
 true,                 // is_default_stack_executable
 true,                 // can_icf_inline_merge_sections
 '\0',                 // wrap_char
 "/lib/ld.so.1",       // dynamic_linker
 0x00400000,           // default_text_segment_address
 4 * 1024,             // abi_pagesize (overridable by -z max-page-size)
 4 * 1024,             // 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<>
Target::Target_info Target_s390<64>::s390_info =
{
 64,                   // size
 true,                 // is_big_endian
 elfcpp::EM_S390,      // machine_code
 false,                // has_make_symbol
 false,                // has_resolve
 true,                 // has_code_fill
 true,                 // is_default_stack_executable
 true,                 // can_icf_inline_merge_sections
 '\0',                 // wrap_char
 "/lib/ld64.so.1",     // dynamic_linker
 0x80000000ll,         // default_text_segment_address
 4 * 1024,             // abi_pagesize (overridable by -z max-page-size)
 4 * 1024,             // 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
 64,                   // hash_entry_size
 elfcpp::SHT_PROGBITS, // unwind_section_type
};

template<int size>
class S390_relocate_functions
{
public:
 enum Overflow_check
 {
   CHECK_NONE,
   CHECK_SIGNED,
   CHECK_UNSIGNED,
   CHECK_BITFIELD,
   CHECK_LOW_INSN,
   CHECK_HIGH_INSN
 };

 enum Status
 {
   STATUS_OK,
   STATUS_OVERFLOW
 };

private:
 typedef S390_relocate_functions<size> This;
 typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;

 template<int valsize>
 static inline bool
 has_overflow_signed(Address value)
 {
   // limit = 1 << (valsize - 1) without shift count exceeding size of type
   Address limit = static_cast<Address>(1) << ((valsize - 1) >> 1);
   limit <<= ((valsize - 1) >> 1);
   limit <<= ((valsize - 1) - 2 * ((valsize - 1) >> 1));
   return value + limit > (limit << 1) - 1;
 }

 template<int valsize>
 static inline bool
 has_overflow_unsigned(Address value)
 {
   Address limit = static_cast<Address>(1) << ((valsize - 1) >> 1);
   limit <<= ((valsize - 1) >> 1);
   limit <<= ((valsize - 1) - 2 * ((valsize - 1) >> 1));
   return value > (limit << 1) - 1;
 }

 template<int fieldsize>
 static inline void
 rela(unsigned char* view, Address mask, Address value)
 {
   typedef typename elfcpp::Swap<fieldsize, true>::Valtype Valtype;
   Valtype* wv = reinterpret_cast<Valtype*>(view);
   Valtype val = elfcpp::Swap<fieldsize, true>::readval(view);
   val &= ~mask;
   value &= mask;
   elfcpp::Swap<fieldsize, true>::writeval(wv, val | value);
 }

public:
 // R_390_12, R_390_GOT12, R_390_GOTPLT12, R_390_GOTIE12
 static inline Status
 rela12(unsigned char* view, Address value)
 {
   if (This::template has_overflow_unsigned<12>(value))
     return STATUS_OVERFLOW;
   This::template rela<16>(view, 0x0fff, value);
   return STATUS_OK;
 }

 // R_390_16, R_390_GOT16, R_390_GOTPLT16, R_390_GOTOFF16, R_390_PLTOFF16
 static inline Status
 rela16(unsigned char* view, Address value)
 {
   if (This::template has_overflow_signed<16>(value))
     return STATUS_OVERFLOW;
   This::template rela<16>(view, 0xffff, value);
   return STATUS_OK;
 }

 // R_390_20, R_390_GOT20, R_390_GOTPLT20, R_390_GOTIE20
 static inline Status
 rela20(unsigned char* view, Address value)
 {
   if (This::template has_overflow_signed<20>(value))
     return STATUS_OVERFLOW;
   This::template rela<16>(view, 0x0fff, value);
   This::template rela<16>(view + 2, 0xff00, value >> (12 - 8));
   return STATUS_OK;
 }

 // R_390_PC12DBL, R_390_PLT12DBL
 static inline Status
 pcrela12dbl(unsigned char* view, Address value, Address address)
 {
   value -= address;
   if ((value & 1) != 0)
     return STATUS_OVERFLOW;
   if (This::template has_overflow_signed<13>(value))
     return STATUS_OVERFLOW;
   value >>= 1;
   This::template rela<16>(view, 0x0fff, value);
   return STATUS_OK;
 }

 // R_390_PC16DBL, R_390_PLT16DBL
 static inline Status
 pcrela16dbl(unsigned char* view, Address value, Address address)
 {
   value -= address;
   if ((value & 1) != 0)
     return STATUS_OVERFLOW;
   if (This::template has_overflow_signed<17>(value))
     return STATUS_OVERFLOW;
   value >>= 1;
   This::template rela<16>(view, 0xffff, value);
   return STATUS_OK;
 }

 // R_390_PC24DBL, R_390_PLT24DBL
 static inline Status
 pcrela24dbl(unsigned char* view, Address value, Address address)
 {
   value -= address;
   if ((value & 1) != 0)
     return STATUS_OVERFLOW;
   if (This::template has_overflow_signed<25>(value))
     return STATUS_OVERFLOW;
   value >>= 1;
   // Swap doesn't take 24-bit fields well...
   This::template rela<8>(view, 0xff, value >> 16);
   This::template rela<16>(view + 1, 0xffff, value);
   return STATUS_OK;
 }

 // R_390_PC32DBL, R_390_PLT32DBL, R_390_GOTPCDBL, R_390_GOTENT, R_390_GOTPLTENT
 static inline Status
 pcrela32dbl(unsigned char* view, Address value, Address address)
 {
   Address reloc = value - address;
   if ((reloc & 1) != 0)
     {
       gold_warning(_("R_390_PC32DBL target misaligned at %llx"), (long long)address);
       // Wait for a fix for https://sourceware.org/bugzilla/show_bug.cgi?id=18960
       // return STATUS_OVERFLOW;
     }
   if (This::template has_overflow_signed<33>(reloc))
     return STATUS_OVERFLOW;
   reloc >>= 1;
   if (value < address && size == 32)
     reloc |= 0x80000000;
   This::template rela<32>(view, 0xffffffff, reloc);
   return STATUS_OK;
 }

};

// Initialize the PLT section.

template<int size>
void
Output_data_plt_s390<size>::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>
void
Output_data_plt_s390<size>::do_adjust_output_section(Output_section* os)
{
 os->set_entsize(plt_entry_size);
}

// Add an entry to the PLT.

template<int size>
void
Output_data_plt_s390<size>::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 offset;
 unsigned int reserved;
 Output_section_data_build* got;
 if (gsym->type() == elfcpp::STT_GNU_IFUNC
     && gsym->can_use_relative_reloc(false))
   {
     pcount = &this->irelative_count_;
     offset = 0;
     reserved = 0;
     got = this->got_irelative_;
   }
 else
   {
     pcount = &this->count_;
     offset = 1;
     reserved = 3;
     got = this->got_plt_;
   }

 if (!this->is_data_size_valid())
   {
     // Note that when setting the PLT offset for a non-IRELATIVE
     // entry we skip the initial reserved PLT entry.
     plt_index = *pcount + offset;
     plt_offset = plt_index * plt_entry_size;

     ++*pcount;

     got_offset = (plt_index - offset + 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(plt_entry_size,
                                            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 / plt_entry_size - 1;
     got_offset = (plt_index - offset + 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>
unsigned int
Output_data_plt_s390<size>::add_local_ifunc_entry(
   Symbol_table* symtab,
   Layout* layout,
   Sized_relobj_file<size, true>* relobj,
   unsigned int local_sym_index)
{
 unsigned int plt_offset = this->irelative_count_ * 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_390_IRELATIVE,
                                   this->got_irelative_, got_offset, 0);

 return plt_offset;
}

// Add the relocation for a PLT entry.

template<int size>
void
Output_data_plt_s390<size>::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_390_IRELATIVE,
                                        this->got_irelative_, got_offset, 0);
   }
 else
   {
     gsym->set_needs_dynsym_entry();
     this->rel_->add_global(gsym, elfcpp::R_390_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>
typename Output_data_plt_s390<size>::Reloc_section*
Output_data_plt_s390<size>::rela_irelative(Symbol_table* symtab,
                                            Layout* layout)
{
 if (this->irelative_rel_ == NULL)
   {
     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_390_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>
uint64_t
Output_data_plt_s390<size>::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) * 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>
uint64_t
Output_data_plt_s390<size>::address_for_local(const Relobj* object,
                                               unsigned int r_sym)
{
 return (this->address()
         + (this->count_ + 1) * plt_entry_size
         + object->local_plt_offset(r_sym));
}

// Set the final size.
template<int size>
void
Output_data_plt_s390<size>::set_final_data_size()
{
 unsigned int count = this->count_ + this->irelative_count_;
 this->set_data_size((count + 1) * plt_entry_size);
}

template<int size>
const unsigned char
Output_data_plt_s390<size>::first_plt_entry_32_abs[plt_entry_size] =
{
 0x50, 0x10, 0xf0, 0x1c, // st %r1, 28(%r15)
 0x0d, 0x10, // basr %r1, %r0
 0x58, 0x10, 0x10, 0x12, // l %r1, 18(%r1)
 0xd2, 0x03, 0xf0, 0x18, 0x10, 0x04, // mvc 24(4,%r15), 4(%r1)
 0x58, 0x10, 0x10, 0x08, // l %r1, 8(%r1)
 0x07, 0xf1, // br %r1
 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // _GLOBAL_OFFSET_TABLE_ (to fill)
 0x00, 0x00, 0x00, 0x00, // padding
};

template<int size>
const unsigned char
Output_data_plt_s390<size>::first_plt_entry_32_pic[plt_entry_size] =
{
 0x50, 0x10, 0xf0, 0x1c, // st %r1, 28(%r15)
 0x58, 0x10, 0xc0, 0x04, // l %r1, 4(%r12)
 0x50, 0x10, 0xf0, 0x18, // st %r1, 24(%r15)
 0x58, 0x10, 0xc0, 0x08, // l %r1, 8(%r12)
 0x07, 0xf1, // br %r1
 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // padding
};

template<int size>
const unsigned char
Output_data_plt_s390<size>::first_plt_entry_64[plt_entry_size] =
{
 0xe3, 0x10, 0xf0, 0x38, 0x00, 0x24, // stg %r1, 56(%r15)
 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1, _GLOBAL_OFFSET_TABLE_ (to fill)
 0xd2, 0x07, 0xf0, 0x30, 0x10, 0x08, // mvc 48(8,%r15), 8(%r1)
 0xe3, 0x10, 0x10, 0x10, 0x00, 0x04, // lg %r1, 16(%r1)
 0x07, 0xf1, // br %r1
 0x07, 0x00, // nopr
 0x07, 0x00, // nopr
 0x07, 0x00, // nopr
};

template<int size>
void
Output_data_plt_s390<size>::fill_first_plt_entry(
   unsigned char* pov,
   typename elfcpp::Elf_types<size>::Elf_Addr got_address,
   typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
{
 if (size == 64)
   {
     memcpy(pov, first_plt_entry_64, plt_entry_size);
     S390_relocate_functions<size>::pcrela32dbl(pov + 8, got_address, (plt_address + 6));
   }
 else if (!parameters->options().output_is_position_independent())
   {
     memcpy(pov, first_plt_entry_32_abs, plt_entry_size);
     elfcpp::Swap<32, true>::writeval(pov + 24, got_address);
   }
 else
   {
     memcpy(pov, first_plt_entry_32_pic, plt_entry_size);
   }
}

template<int size>
const unsigned char
Output_data_plt_s390<size>::plt_entry_32_abs[plt_entry_size] =
{
 // first part
 0x0d, 0x10, // basr %r1, %r0
 0x58, 0x10, 0x10, 0x16, // l %r1, 22(%r1)
 0x58, 0x10, 0x10, 0x00, // l %r1, 0(%r1)
 0x07, 0xf1, // br %r1
 // second part
 0x0d, 0x10, // basr %r1, %r0
 0x58, 0x10, 0x10, 0x0e, // l %r1, 14(%r1)
 0xa7, 0xf4, 0x00, 0x00, // j first_plt_entry (to fill)
 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // _GLOBAL_OFFSET_TABLE_+sym@gotplt (to fill)
 0x00, 0x00, 0x00, 0x00, // offset of relocation in .rela.plt (to fill)
};

template<int size>
const unsigned char
Output_data_plt_s390<size>::plt_entry_32_pic12[plt_entry_size] =
{
 // first part
 0x58, 0x10, 0xc0, 0x00, // l %r1, sym@gotplt(%r12) (to fill)
 0x07, 0xf1, // br %r1
 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // padding
 // second part
 0x0d, 0x10, // basr %r1, %r0
 0x58, 0x10, 0x10, 0x0e, // l %r1, 14(%r1)
 0xa7, 0xf4, 0x00, 0x00, // j first_plt_entry (to fill)
 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // offset of relocation in .rela.plt (to fill)
};

template<int size>
const unsigned char
Output_data_plt_s390<size>::plt_entry_32_pic16[plt_entry_size] =
{
 // first part
 0xa7, 0x18, 0x00, 0x00, // lhi %r1, sym@gotplt (to fill)
 0x58, 0x11, 0xc0, 0x00, // l %r1, 0(%r1, %r12)
 0x07, 0xf1, // br %r1
 0x00, 0x00, // padding
 // second part
 0x0d, 0x10, // basr %r1, %r0
 0x58, 0x10, 0x10, 0x0e, // l %r1, 14(%r1)
 0xa7, 0xf4, 0x00, 0x00, // j first_plt_entry (to fill)
 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // offset of relocation in .rela.plt (to fill)
};

template<int size>
const unsigned char
Output_data_plt_s390<size>::plt_entry_32_pic[plt_entry_size] =
{
 // first part
 0x0d, 0x10, // basr %r1, %r0
 0x58, 0x10, 0x10, 0x16, // l %r1, 22(%r1)
 0x58, 0x11, 0xc0, 0x00, // l %r1, 0(%r1, %r12)
 0x07, 0xf1, // br %r1
 // second part
 0x0d, 0x10, // basr %r1, %r0
 0x58, 0x10, 0x10, 0x0e, // l %r1, 14(%r1)
 0xa7, 0xf4, 0x00, 0x00, // j first_plt_entry (to fill)
 0x00, 0x00, // padding
 0x00, 0x00, 0x00, 0x00, // sym@gotplt (to fill)
 0x00, 0x00, 0x00, 0x00, // offset of relocation in .rela.plt (to fill)
};

template<int size>
const unsigned char
Output_data_plt_s390<size>::plt_entry_64[plt_entry_size] =
{
 // first part
 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1, _GLOBAL_OFFSET_TABLE_+off (to fill)
 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, // lg %r1, 0(%r1)
 0x07, 0xf1, // br %r1
 // second part
 0x0d, 0x10, // basr %r1, %r0
 0xe3, 0x10, 0x10, 0x0c, 0x00, 0x14, // lgf %r1, 12(%r1)
 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, // jg first_plt_entry (to fill)
 0x00, 0x00, 0x00, 0x00, // offset of relocation in .rela.plt (to fill)
};

template<int size>
unsigned int
Output_data_plt_s390<size>::fill_plt_entry(
   unsigned char* pov,
   typename elfcpp::Elf_types<size>::Elf_Addr got_address,
   typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
   unsigned int got_offset,
   unsigned int plt_offset,
   unsigned int plt_rel_offset)
{
 if (size == 64)
 {
   memcpy(pov, plt_entry_64, plt_entry_size);
   S390_relocate_functions<size>::pcrela32dbl(pov + 2, got_address + got_offset, plt_address + plt_offset);
   S390_relocate_functions<size>::pcrela32dbl(pov + 24, plt_address, plt_address + plt_offset + 22);
 }
 else
 {
   if (!parameters->options().output_is_position_independent())
     {
       memcpy(pov, plt_entry_32_abs, plt_entry_size);
       elfcpp::Swap<32, true>::writeval(pov + 24, got_address + got_offset);
     }
   else
     {
       if (got_offset < 0x1000)
         {
           memcpy(pov, plt_entry_32_pic12, plt_entry_size);
           S390_relocate_functions<size>::rela12(pov + 2, got_offset);
         }
       else if (got_offset < 0x8000)
         {
           memcpy(pov, plt_entry_32_pic16, plt_entry_size);
           S390_relocate_functions<size>::rela16(pov + 2, got_offset);
         }
       else
         {
           memcpy(pov, plt_entry_32_pic, plt_entry_size);
           elfcpp::Swap<32, true>::writeval(pov + 24, got_offset);
         }
     }
   typename elfcpp::Elf_types<size>::Elf_Addr target = plt_address;
   if (plt_offset >= 0x10000)
     {
       // Would overflow pcrela16dbl - aim at the farthest previous jump
       // we can reach.
       if (plt_offset > 0x10000)
         {
           // Use the full range of pcrel16dbl.
           target = plt_address + plt_offset - 0x10000 + 18;
         }
       else
         {
           // if plt_offset is exactly 0x10000, the above would aim at 18th byte
           // of first_plt_entry, which doesn't have the jump back like the others.
           // Aim at the next entry instead.
           target = plt_address + plt_offset - 0xffe0 + 18;
         }
     }
   S390_relocate_functions<size>::pcrela16dbl(pov + 20, target, plt_address + plt_offset + 18);
 }
 elfcpp::Swap<32, true>::writeval(pov + 28, plt_rel_offset);
 if (size == 64)
   return 14;
 else
   return 12;
}

// The .eh_frame unwind information for the PLT.

template<>
const unsigned char
Output_data_plt_s390<32>::plt_eh_frame_cie[plt_eh_frame_cie_size] =
{
 1,                            // CIE version.
 'z',                          // Augmentation: augmentation size included.
 'R',                          // Augmentation: FDE encoding included.
 '\0',                         // End of augmentation string.
 1,                            // Code alignment factor.
 0x7c,                         // Data alignment factor.
 14,                           // Return address column.
 1,                            // Augmentation size.
 (elfcpp::DW_EH_PE_pcrel       // FDE encoding.
  | elfcpp::DW_EH_PE_sdata4),
 elfcpp::DW_CFA_def_cfa, 15, 0x60,     // DW_CFA_def_cfa: r15 ofs 0x60.
};

template<>
const unsigned char
Output_data_plt_s390<64>::plt_eh_frame_cie[plt_eh_frame_cie_size] =
{
 1,                            // CIE version.
 'z',                          // Augmentation: augmentation size included.
 'R',                          // Augmentation: FDE encoding included.
 '\0',                         // End of augmentation string.
 1,                            // Code alignment factor.
 0x78,                         // Data alignment factor.
 14,                           // Return address column.
 1,                            // Augmentation size.
 (elfcpp::DW_EH_PE_pcrel       // FDE encoding.
  | elfcpp::DW_EH_PE_sdata4),
 elfcpp::DW_CFA_def_cfa, 15, 0xa0,     // DW_CFA_def_cfa: r15 ofs 0xa0.
};

template<int size>
const unsigned char
Output_data_plt_s390<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
{
 0, 0, 0, 0,                           // Replaced with offset to .plt.
 0, 0, 0, 0,                           // Replaced with size of .plt.
 0,                                    // Augmentation size.
 elfcpp::DW_CFA_nop,
 elfcpp::DW_CFA_nop,
 elfcpp::DW_CFA_nop
};

// Write out the PLT.  This uses the hand-coded instructions above,
// and adjusts them as needed.

template<int size>
void
Output_data_plt_s390<size>::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();
 // The base address of the PLT portion of the .got section,
 // which is where the GOT pointer will point, and where the
 // three reserved GOT entries are located.
 typename elfcpp::Elf_types<size>::Elf_Addr got_address
   = this->got_plt_->address();

 this->fill_first_plt_entry(pov, got_address, plt_address);
 pov += this->get_plt_entry_size();

 unsigned char* got_pov = got_view;

 const int rel_size = elfcpp::Elf_sizes<size>::rela_size;

 unsigned int plt_offset = this->get_plt_entry_size();
 unsigned int plt_rel_offset = 0;
 unsigned int got_offset = 3 * size / 8;
 const unsigned int count = this->count_ + this->irelative_count_;
 // The first three entries in the GOT are reserved, and are written
 // by Output_data_got_plt_s390::do_write.
 got_pov += 3 * size / 8;

 for (unsigned int plt_index = 0;
      plt_index < count;
      ++plt_index,
        pov += plt_entry_size,
        got_pov += size / 8,
        plt_offset += plt_entry_size,
        plt_rel_offset += rel_size,
        got_offset += size / 8)
   {
     // Set and adjust the PLT entry itself.
     unsigned int lazy_offset = this->fill_plt_entry(pov,
                                                     got_address, plt_address,
                                                     got_offset, plt_offset,
                                                     plt_rel_offset);

     // Set the entry in the GOT.
     elfcpp::Swap<size, true>::writeval(got_pov,
                                       plt_address + plt_offset + lazy_offset);
   }

 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);
}

// Get the GOT section, creating it if necessary.

template<int size>
Output_data_got<size, true>*
Target_s390<size>::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 as a relro section.
     // Without -z now, it is modified after program startup by lazy
     // PLT relocations.
     bool is_got_relro = parameters->options().now();
     Output_section_order got_order = (is_got_relro
                                       ? ORDER_RELRO_LAST
                                       : ORDER_DATA);

     // The old GNU linker creates a .got.plt section.  We just
     // create another set of data in the .got section.  Note that we
     // always create a PLT if we create a GOT, although the PLT
     // might be empty.
     this->got_plt_ = new Output_data_got_plt_s390<size>(layout);
     layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                     (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
                                     this->got_plt_, got_order, is_got_relro);

     // The first three entries are reserved.
     this->got_plt_->set_current_data_size(3 * 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", elfcpp::SHT_PROGBITS,
                                     (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
                                     this->got_irelative_,
                                     got_order, is_got_relro);

     // Unlike some targets (.e.g x86), S/390 does not use separate .got and
     // .got.plt sections in output.  The output .got section contains both
     // PLT and non-PLT GOT entries.
     this->got_ = new Output_data_got<size, true>();

     layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                     (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
                                     this->got_, got_order, is_got_relro);

     // 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_plt_,
                                     0, 0, elfcpp::STT_OBJECT,
                                     elfcpp::STB_LOCAL,
                                     elfcpp::STV_HIDDEN, 0,
                                     false, false);

   }
 return this->got_;
}

// Get the dynamic reloc section, creating it if necessary.

template<int size>
typename Target_s390<size>::Reloc_section*
Target_s390<size>::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>
typename Target_s390<size>::Reloc_section*
Target_s390<size>::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_;
}

// Write the first three reserved words of the .got.plt section.
// The remainder of the section is written while writing the PLT
// in Output_data_plt_s390::do_write.

template<int size>
void
Output_data_got_plt_s390<size>::do_write(Output_file* of)
{
 // The first entry in the GOT is the address of the .dynamic section
 // aka the PT_DYNAMIC segment.  The next two entries are reserved.
 // We saved space for them when we created the section in
 // Target_x86_64::got_section.
 const off_t got_file_offset = this->offset();
 gold_assert(this->data_size() >= 3 * size / 8);
 unsigned char* const got_view =
     of->get_output_view(got_file_offset, 3 * size / 8);
 Output_section* dynamic = this->layout_->dynamic_section();
 uint64_t dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
 elfcpp::Swap<size, true>::writeval(got_view, dynamic_addr);
 memset(got_view + size / 8, 0, 2 * size / 8);
 of->write_output_view(got_file_offset, 3 * size / 8, got_view);
}

// Create the PLT section.

template<int size>
void
Target_s390<size>::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  This is
     // necessary due to how, on 32-bit S/390 and some other targets,
     // .rela.dyn needs to include .rela.plt in it's range.
     this->rela_dyn_section(layout);

     this->plt_ = new Output_data_plt_s390<size>(layout,
                     this->got_, this->got_plt_, this->got_irelative_);

     // Add unwind information if requested.
     if (parameters->options().ld_generated_unwind_info())
       this->plt_->add_eh_frame(layout);

     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 a PLT entry for a global symbol.

template<int size>
void
Target_s390<size>::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>
void
Target_s390<size>::make_local_ifunc_plt_entry(
   Symbol_table* symtab, Layout* layout,
   Sized_relobj_file<size, true>* 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>
unsigned int
Target_s390<size>::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>
unsigned int
Target_s390<size>::first_plt_entry_offset() const
{
 return this->plt_->first_plt_entry_offset();
}

// Return the size of each PLT entry.

template<int size>
unsigned int
Target_s390<size>::plt_entry_size() const
{
 return this->plt_->get_plt_entry_size();
}

// Create the GOT and PLT sections for an incremental update.

template<int size>
Output_data_got_base*
Target_s390<size>::init_got_plt_for_update(Symbol_table* symtab,
                                      Layout* layout,
                                      unsigned int got_count,
                                      unsigned int plt_count)
{
 gold_assert(this->got_ == NULL);

 // Add the three reserved entries.
 this->got_plt_ = new Output_data_got_plt_s390<size>(layout, (plt_count + 3) * size / 8);
 layout->add_output_section_data(".got", 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 entries.
 this->got_irelative_ = new Output_data_space(0, size / 8, "** GOT IRELATIVE PLT");
 layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                 elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
                                 this->got_irelative_,
                                 ORDER_NON_RELRO_FIRST, false);

 this->got_ = new Output_data_got<size, true>(got_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 PLT.
 this->global_offset_table_ =
   symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
                                 Symbol_table::PREDEFINED,
                                 this->got_plt_,
                                 0, 0, elfcpp::STT_OBJECT,
                                 elfcpp::STB_LOCAL,
                                 elfcpp::STV_HIDDEN, 0,
                                 false, false);

 // Create the PLT section.
 this->plt_ = new Output_data_plt_s390<size>(layout,
                 this->got_, this->got_plt_, this->got_irelative_, plt_count);

 // Add unwind information if requested.
 if (parameters->options().ld_generated_unwind_info())
   this->plt_->add_eh_frame(layout);

 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>
void
Target_s390<size>::reserve_local_got_entry(
   unsigned int got_index,
   Sized_relobj<size, true>* obj,
   unsigned int r_sym,
   unsigned int got_type)
{
 unsigned int got_offset = got_index * 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_390_RELATIVE,
                                    this->got_, got_offset, 0, false);
     break;
   case GOT_TYPE_TLS_OFFSET:
     rela_dyn->add_local(obj, r_sym, elfcpp::R_390_TLS_TPOFF,
                         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, elfcpp::R_390_TLS_DTPMOD,
                         this->got_, got_offset, 0);
     break;
   default:
     gold_unreachable();
   }
}

// Reserve a GOT entry for a global symbol, and regenerate any
// necessary dynamic relocations.

template<int size>
void
Target_s390<size>::reserve_global_got_entry(unsigned int got_index,
                                             Symbol* gsym,
                                             unsigned int got_type)
{
 unsigned int got_offset = got_index * 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_390_GLOB_DAT,
                                this->got_, got_offset, 0);
         else
           rela_dyn->add_global_relative(gsym, elfcpp::R_390_RELATIVE,
                                         this->got_, got_offset, 0, false);
       }
     break;
   case GOT_TYPE_TLS_OFFSET:
     rela_dyn->add_global_relative(gsym, elfcpp::R_390_TLS_TPOFF,
                                   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, elfcpp::R_390_TLS_DTPMOD,
                                   this->got_, got_offset, 0, false);
     rela_dyn->add_global_relative(gsym, elfcpp::R_390_TLS_DTPOFF,
                                   this->got_, got_offset + size / 8, 0, false);
     break;
   default:
     gold_unreachable();
   }
}

// Register an existing PLT entry for a global symbol.

template<int size>
void
Target_s390<size>::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 + 3) * size / 8;
 this->plt_->add_relocation(symtab, layout, gsym, got_offset);
}

// Force a COPY relocation for a given symbol.

template<int size>
void
Target_s390<size>::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>
unsigned int
Target_s390<size>::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
                                        Sized_relobj_file<size, true>* 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, true>* got = this->got_section(symtab, layout);
     unsigned int got_offset = got->add_constant(0);
     rela_dyn->add_local(object, 0, elfcpp::R_390_TLS_DTPMOD, 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.

template<int size>
tls::Tls_optimization
Target_s390<size>::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)
   {
   case elfcpp::R_390_TLS_GD32:
   case elfcpp::R_390_TLS_GD64:
   case elfcpp::R_390_TLS_GDCALL:
     // 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;

   case elfcpp::R_390_TLS_LDM32:
   case elfcpp::R_390_TLS_LDM64:
   case elfcpp::R_390_TLS_LDO32:
   case elfcpp::R_390_TLS_LDO64:
   case elfcpp::R_390_TLS_LDCALL:
     // This is Local-Dynamic, which refers to a local symbol in the
     // dynamic TLS block.  Since we know that we generating an
     // executable, we can switch to Local-Exec.
     return tls::TLSOPT_TO_LE;

   case elfcpp::R_390_TLS_IE32:
   case elfcpp::R_390_TLS_IE64:
   case elfcpp::R_390_TLS_GOTIE32:
   case elfcpp::R_390_TLS_GOTIE64:
   case elfcpp::R_390_TLS_LOAD:
     // 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;

   case elfcpp::R_390_TLS_GOTIE12:
   case elfcpp::R_390_TLS_IEENT:
   case elfcpp::R_390_TLS_GOTIE20:
     // These are Initial-Exec, but cannot be optimized.
     return tls::TLSOPT_NONE;

   case elfcpp::R_390_TLS_LE32:
   case elfcpp::R_390_TLS_LE64:
     // 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>
int
Target_s390<size>::Scan::get_reference_flags(unsigned int r_type)
{
 switch (r_type)
   {
   case elfcpp::R_390_NONE:
   case elfcpp::R_390_GNU_VTINHERIT:
   case elfcpp::R_390_GNU_VTENTRY:
   case elfcpp::R_390_GOTPC:
   case elfcpp::R_390_GOTPCDBL:
     // No symbol reference.
     return 0;

   case elfcpp::R_390_64:
   case elfcpp::R_390_32:
   case elfcpp::R_390_20:
   case elfcpp::R_390_16:
   case elfcpp::R_390_12:
   case elfcpp::R_390_8:
     return Symbol::ABSOLUTE_REF;

   case elfcpp::R_390_PC12DBL:
   case elfcpp::R_390_PC16:
   case elfcpp::R_390_PC16DBL:
   case elfcpp::R_390_PC24DBL:
   case elfcpp::R_390_PC32:
   case elfcpp::R_390_PC32DBL:
   case elfcpp::R_390_PC64:
   case elfcpp::R_390_GOTOFF16:
   case elfcpp::R_390_GOTOFF32:
   case elfcpp::R_390_GOTOFF64:
     return Symbol::RELATIVE_REF;

   case elfcpp::R_390_PLT12DBL:
   case elfcpp::R_390_PLT16DBL:
   case elfcpp::R_390_PLT24DBL:
   case elfcpp::R_390_PLT32:
   case elfcpp::R_390_PLT32DBL:
   case elfcpp::R_390_PLT64:
   case elfcpp::R_390_PLTOFF16:
   case elfcpp::R_390_PLTOFF32:
   case elfcpp::R_390_PLTOFF64:
     return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;

   case elfcpp::R_390_GOT12:
   case elfcpp::R_390_GOT16:
   case elfcpp::R_390_GOT20:
   case elfcpp::R_390_GOT32:
   case elfcpp::R_390_GOT64:
   case elfcpp::R_390_GOTENT:
   case elfcpp::R_390_GOTPLT12:
   case elfcpp::R_390_GOTPLT16:
   case elfcpp::R_390_GOTPLT20:
   case elfcpp::R_390_GOTPLT32:
   case elfcpp::R_390_GOTPLT64:
   case elfcpp::R_390_GOTPLTENT:
     // Absolute in GOT.
     return Symbol::ABSOLUTE_REF;

   case elfcpp::R_390_TLS_GD32:          // Global-dynamic
   case elfcpp::R_390_TLS_GD64:
   case elfcpp::R_390_TLS_GDCALL:
   case elfcpp::R_390_TLS_LDM32:         // Local-dynamic
   case elfcpp::R_390_TLS_LDM64:
   case elfcpp::R_390_TLS_LDO32:
   case elfcpp::R_390_TLS_LDO64:
   case elfcpp::R_390_TLS_LDCALL:
   case elfcpp::R_390_TLS_IE32:          // Initial-exec
   case elfcpp::R_390_TLS_IE64:
   case elfcpp::R_390_TLS_IEENT:
   case elfcpp::R_390_TLS_GOTIE12:
   case elfcpp::R_390_TLS_GOTIE20:
   case elfcpp::R_390_TLS_GOTIE32:
   case elfcpp::R_390_TLS_GOTIE64:
   case elfcpp::R_390_TLS_LOAD:
   case elfcpp::R_390_TLS_LE32:          // Local-exec
   case elfcpp::R_390_TLS_LE64:
     return Symbol::TLS_REF;

   case elfcpp::R_390_COPY:
   case elfcpp::R_390_GLOB_DAT:
   case elfcpp::R_390_JMP_SLOT:
   case elfcpp::R_390_RELATIVE:
   case elfcpp::R_390_IRELATIVE:
   case elfcpp::R_390_TLS_TPOFF:
   case elfcpp::R_390_TLS_DTPOFF:
   case elfcpp::R_390_TLS_DTPMOD:
   default:
     // Not expected.  We will give an error later.
     return 0;
   }
}

// Report an unsupported relocation against a local symbol.

template<int size>
void
Target_s390<size>::Scan::unsupported_reloc_local(
    Sized_relobj_file<size, true>* 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>
void
Target_s390<size>::Scan::check_non_pic(Relobj* object, unsigned int r_type)
{
 gold_assert(r_type != elfcpp::R_390_NONE);

 if (size == 64)
   {
     switch (r_type)
       {
         // These are the relocation types supported by glibc for s390 64-bit.
       case elfcpp::R_390_RELATIVE:
       case elfcpp::R_390_IRELATIVE:
       case elfcpp::R_390_COPY:
       case elfcpp::R_390_GLOB_DAT:
       case elfcpp::R_390_JMP_SLOT:
       case elfcpp::R_390_TLS_DTPMOD:
       case elfcpp::R_390_TLS_DTPOFF:
       case elfcpp::R_390_TLS_TPOFF:
       case elfcpp::R_390_8:
       case elfcpp::R_390_16:
       case elfcpp::R_390_32:
       case elfcpp::R_390_64:
       case elfcpp::R_390_PC16:
       case elfcpp::R_390_PC16DBL:
       case elfcpp::R_390_PC32:
       case elfcpp::R_390_PC32DBL:
       case elfcpp::R_390_PC64:
         return;

       default:
         break;
       }
   }
 else
   {
     switch (r_type)
       {
         // These are the relocation types supported by glibc for s390 32-bit.
       case elfcpp::R_390_RELATIVE:
       case elfcpp::R_390_IRELATIVE:
       case elfcpp::R_390_COPY:
       case elfcpp::R_390_GLOB_DAT:
       case elfcpp::R_390_JMP_SLOT:
       case elfcpp::R_390_TLS_DTPMOD:
       case elfcpp::R_390_TLS_DTPOFF:
       case elfcpp::R_390_TLS_TPOFF:
       case elfcpp::R_390_8:
       case elfcpp::R_390_16:
       case elfcpp::R_390_32:
       case elfcpp::R_390_PC16:
       case elfcpp::R_390_PC16DBL:
       case elfcpp::R_390_PC32:
       case elfcpp::R_390_PC32DBL:
         return;

       default:
         break;
       }
   }

 // 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; "
                 "recompile with -fPIC"));
 this->issued_non_pic_error_ = true;
 return;
}

// 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
Target_s390<size>::Scan::reloc_needs_plt_for_ifunc(
    Sized_relobj_file<size, true>* 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>
inline void
Target_s390<size>::Scan::local(Symbol_table* symtab,
                                Layout* layout,
                                Target_s390<size>* target,
                                Sized_relobj_file<size, true>* object,
                                unsigned int data_shndx,
                                Output_section* output_section,
                                const elfcpp::Rela<size, true>& reloc,
                                unsigned int r_type,
                                const elfcpp::Sym<size, true>& 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_390_NONE:
   case elfcpp::R_390_GNU_VTINHERIT:
   case elfcpp::R_390_GNU_VTENTRY:
     break;

   case elfcpp::R_390_64:
     // If building a shared library (or a position-independent
     // executable), we need to create a dynamic relocation for this
     // location.  The relocation applied at link time will apply the
     // link-time value, so we flag the location with an
     // R_390_RELATIVE relocation so the dynamic loader can
     // relocate it easily.
     if (parameters->options().output_is_position_independent() && size == 64)
       {
         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_390_RELATIVE,
                                      output_section, data_shndx,
                                      reloc.get_r_offset(),
                                      reloc.get_r_addend(), is_ifunc);
       }
     break;

   case elfcpp::R_390_32:
   case elfcpp::R_390_20:
   case elfcpp::R_390_16:
   case elfcpp::R_390_12:
   case elfcpp::R_390_8:
     if (parameters->options().output_is_position_independent())
       {
         if (size == 32 && r_type == elfcpp::R_390_32)
           {
             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_390_RELATIVE,
                                          output_section, data_shndx,
                                          reloc.get_r_offset(),
                                          reloc.get_r_addend(), is_ifunc);
             break;
           }

         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);
             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(_("section symbol %u has bad shndx %u"),
                             r_sym, shndx);
             else
               rela_dyn->add_local_section(object, shndx,
                                           r_type, output_section,
                                           data_shndx, reloc.get_r_offset(),
                                           reloc.get_r_addend());
           }
       }
     break;

   case elfcpp::R_390_PC12DBL:
   case elfcpp::R_390_PC16:
   case elfcpp::R_390_PC16DBL:
   case elfcpp::R_390_PC24DBL:
   case elfcpp::R_390_PC32:
   case elfcpp::R_390_PC32DBL:
   case elfcpp::R_390_PC64:
     break;

   case elfcpp::R_390_PLT12DBL:
   case elfcpp::R_390_PLT16DBL:
   case elfcpp::R_390_PLT24DBL:
   case elfcpp::R_390_PLT32:
   case elfcpp::R_390_PLT32DBL:
   case elfcpp::R_390_PLT64:
     // Since we know this is a local symbol, we can handle this as a
     // PC32 reloc.
     break;

   case elfcpp::R_390_GOTPC:
   case elfcpp::R_390_GOTPCDBL:
   case elfcpp::R_390_GOTOFF16:
   case elfcpp::R_390_GOTOFF32:
   case elfcpp::R_390_GOTOFF64:
   case elfcpp::R_390_PLTOFF16:
   case elfcpp::R_390_PLTOFF32:
   case elfcpp::R_390_PLTOFF64:
     // We need a GOT section.
     target->got_section(symtab, layout);
     // For PLTOFF*, we'd normally want a PLT section, but since we
     // know this is a local symbol, no PLT is needed.
     break;

   case elfcpp::R_390_GOT12:
   case elfcpp::R_390_GOT16:
   case elfcpp::R_390_GOT20:
   case elfcpp::R_390_GOT32:
   case elfcpp::R_390_GOT64:
   case elfcpp::R_390_GOTENT:
   case elfcpp::R_390_GOTPLT12:
   case elfcpp::R_390_GOTPLT16:
   case elfcpp::R_390_GOTPLT20:
   case elfcpp::R_390_GOTPLT32:
   case elfcpp::R_390_GOTPLT64:
   case elfcpp::R_390_GOTPLTENT:
     {
       // The symbol requires a GOT section.
       Output_data_got<size, true>* got = target->got_section(symtab, layout);

       // The symbol requires a GOT entry.
       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)
         {
           // If we are generating a shared object, we need to add a
           // dynamic relocation for this symbol's GOT entry.
           if (parameters->options().output_is_position_independent())
             {
               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
               unsigned int got_offset =
                 object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
               rela_dyn->add_local_relative(object, r_sym,
                                            elfcpp::R_390_RELATIVE,
                                            got, got_offset, 0, is_ifunc);
             }
         }
       // For GOTPLT*, we'd normally want a PLT section, but since
       // we know this is a local symbol, no PLT is needed.
     }
     break;

   case elfcpp::R_390_COPY:
   case elfcpp::R_390_GLOB_DAT:
   case elfcpp::R_390_JMP_SLOT:
   case elfcpp::R_390_RELATIVE:
   case elfcpp::R_390_IRELATIVE:
     // These are outstanding tls relocs, which are unexpected when linking
   case elfcpp::R_390_TLS_TPOFF:
   case elfcpp::R_390_TLS_DTPOFF:
   case elfcpp::R_390_TLS_DTPMOD:
     gold_error(_("%s: unexpected reloc %u in object file"),
                object->name().c_str(), r_type);
     break;

     // These are initial tls relocs, which are expected when linking
   case elfcpp::R_390_TLS_GD32:          // Global-dynamic
   case elfcpp::R_390_TLS_GD64:
   case elfcpp::R_390_TLS_GDCALL:
   case elfcpp::R_390_TLS_LDM32:         // Local-dynamic
   case elfcpp::R_390_TLS_LDM64:
   case elfcpp::R_390_TLS_LDO32:
   case elfcpp::R_390_TLS_LDO64:
   case elfcpp::R_390_TLS_LDCALL:
   case elfcpp::R_390_TLS_IE32:          // Initial-exec
   case elfcpp::R_390_TLS_IE64:
   case elfcpp::R_390_TLS_IEENT:
   case elfcpp::R_390_TLS_GOTIE12:
   case elfcpp::R_390_TLS_GOTIE20:
   case elfcpp::R_390_TLS_GOTIE32:
   case elfcpp::R_390_TLS_GOTIE64:
   case elfcpp::R_390_TLS_LOAD:
   case elfcpp::R_390_TLS_LE32:          // Local-exec
   case elfcpp::R_390_TLS_LE64:
     {
       bool output_is_shared = parameters->options().shared();
       const tls::Tls_optimization optimized_type
           = Target_s390<size>::optimize_tls_reloc(!output_is_shared,
                                                     r_type);
       switch (r_type)
         {
         case elfcpp::R_390_TLS_GD32:       // General-dynamic
         case elfcpp::R_390_TLS_GD64:
         case elfcpp::R_390_TLS_GDCALL:
           if (optimized_type == tls::TLSOPT_NONE)
             {
               // Create a pair of GOT entries for the module index and
               // dtv-relative offset.
               Output_data_got<size, true>* 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),
                                              elfcpp::R_390_TLS_DTPMOD);
             }
           else if (optimized_type != tls::TLSOPT_TO_LE)
             unsupported_reloc_local(object, r_type);
           break;

         case elfcpp::R_390_TLS_LDM32:       // Local-dynamic
         case elfcpp::R_390_TLS_LDM64:
         case elfcpp::R_390_TLS_LDCALL:
           if (optimized_type == tls::TLSOPT_NONE)
             {
               // Create a GOT entry for the module index.
               target->got_mod_index_entry(symtab, layout, object);
             }
           else if (optimized_type != tls::TLSOPT_TO_LE)
             unsupported_reloc_local(object, r_type);
           break;

         case elfcpp::R_390_TLS_LDO32:
         case elfcpp::R_390_TLS_LDO64:
           break;

         case elfcpp::R_390_TLS_IE32:    // Initial-exec
         case elfcpp::R_390_TLS_IE64:
           // These two involve an absolute address
           if (parameters->options().shared()
               && optimized_type == tls::TLSOPT_NONE)
             {
               if ((size == 32 && r_type == elfcpp::R_390_TLS_IE32) ||
                   (size == 64 && r_type == elfcpp::R_390_TLS_IE64))
                 {
                   // We need to create a dynamic relocation.
                   Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                   unsigned int r_sym =
                       elfcpp::elf_r_sym<size>(reloc.get_r_info());
                   rela_dyn->add_local_relative(object, r_sym,
                                               elfcpp::R_390_RELATIVE,
                                               output_section, data_shndx,
                                               reloc.get_r_offset(),
                                               reloc.get_r_addend(), false);
                 }
               else
                 {
                   unsupported_reloc_local(object, r_type);
                 }
             }
           // Fall through.
         case elfcpp::R_390_TLS_IEENT:
         case elfcpp::R_390_TLS_GOTIE12:
         case elfcpp::R_390_TLS_GOTIE20:
         case elfcpp::R_390_TLS_GOTIE32:
         case elfcpp::R_390_TLS_GOTIE64:
         case elfcpp::R_390_TLS_LOAD:
           layout->set_has_static_tls();
           if (optimized_type == tls::TLSOPT_NONE)
             {
               if (!output_is_shared)
                 {
                   // We're making an executable, and the symbol is local, but
                   // we cannot optimize to LE.  Make a const GOT entry instead.
                   Output_data_got<size, true>* got
                       = target->got_section(symtab, layout);
                   unsigned int r_sym
                       = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                   got->add_local_plt(object, r_sym, GOT_TYPE_TLS_OFFSET);
                 }
               else
               {
                 // Create a GOT entry for the tp-relative offset.
                 Output_data_got<size, true>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym
                     = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                 got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
                                         target->rela_dyn_section(layout),
                                         elfcpp::R_390_TLS_TPOFF);
               }
             }
           else if (optimized_type != tls::TLSOPT_TO_LE)
             unsupported_reloc_local(object, r_type);
           break;

         case elfcpp::R_390_TLS_LE32:     // Local-exec
         case elfcpp::R_390_TLS_LE64:
           layout->set_has_static_tls();
           if (output_is_shared)
           {
             // We need to create a dynamic relocation.
             if ((size == 32 && r_type == elfcpp::R_390_TLS_LE32) ||
                 (size == 64 && r_type == elfcpp::R_390_TLS_LE64))
               {
                 Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                 unsigned int r_sym
                     = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                 gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
                 rela_dyn->add_local(object, r_sym, elfcpp::R_390_TLS_TPOFF,
                                     output_section, data_shndx,
                                     reloc.get_r_offset(),
                                     reloc.get_r_addend());
               }
             else
               {
                 unsupported_reloc_local(object, r_type);
               }
           }
           break;

         default:
           gold_unreachable();
         }
     }
     break;

   default:
     gold_error(_("%s: unsupported reloc %u against local symbol"),
                object->name().c_str(), r_type);
     break;
   }
}

// Scan a relocation for a global symbol.

template<int size>
inline void
Target_s390<size>::Scan::global(Symbol_table* symtab,
                           Layout* layout,
                           Target_s390<size>* target,
                           Sized_relobj_file<size, true>* object,
                           unsigned int data_shndx,
                           Output_section* output_section,
                           const elfcpp::Rela<size, true>& reloc,
                           unsigned int r_type,
                           Symbol* gsym)
{
 // 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_390_NONE:
   case elfcpp::R_390_GNU_VTINHERIT:
   case elfcpp::R_390_GNU_VTENTRY:
     break;

   case elfcpp::R_390_64:
   case elfcpp::R_390_32:
   case elfcpp::R_390_20:
   case elfcpp::R_390_16:
   case elfcpp::R_390_12:
   case elfcpp::R_390_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_390_64)
                     || (size == 32 && r_type == elfcpp::R_390_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_390_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 (((size == 64 && r_type == elfcpp::R_390_64)
                     || (size == 32 && r_type == elfcpp::R_390_32))
                    && gsym->can_use_relative_reloc(false))
             {
               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
               rela_dyn->add_global_relative(gsym, elfcpp::R_390_RELATIVE,
                                             output_section, object,
                                             data_shndx,
                                             reloc.get_r_offset(),
                                             reloc.get_r_addend(), false);
             }
           else
             {
               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_390_PC12DBL:
   case elfcpp::R_390_PC16:
   case elfcpp::R_390_PC16DBL:
   case elfcpp::R_390_PC24DBL:
   case elfcpp::R_390_PC32:
   case elfcpp::R_390_PC32DBL:
   case elfcpp::R_390_PC64:
     {
       // Make a PLT entry if necessary.
       if (gsym->needs_plt_entry())
         {
           target->make_plt_entry(symtab, layout, gsym);
           // larl is often used to take address of a function.  Aim the
           // symbol at 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_executable()
               && gsym->may_need_copy_reloc())
             {
               target->copy_reloc(symtab, layout, object,
                                  data_shndx, output_section, gsym, reloc);
             }
           else
             {
               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_390_PLT12DBL:
   case elfcpp::R_390_PLT16DBL:
   case elfcpp::R_390_PLT24DBL:
   case elfcpp::R_390_PLT32:
   case elfcpp::R_390_PLT32DBL:
   case elfcpp::R_390_PLT64:
     // 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_390_GOTPC:
   case elfcpp::R_390_GOTPCDBL:
   case elfcpp::R_390_GOTOFF16:
   case elfcpp::R_390_GOTOFF32:
   case elfcpp::R_390_GOTOFF64:
   case elfcpp::R_390_PLTOFF16:
   case elfcpp::R_390_PLTOFF32:
   case elfcpp::R_390_PLTOFF64:
     // We need a GOT section.
     target->got_section(symtab, layout);
     // For PLTOFF*, we also need a PLT entry (but only if the
     // symbol is not fully resolved).
     if ((r_type == elfcpp::R_390_PLTOFF16
          || r_type == elfcpp::R_390_PLTOFF32
          || r_type == elfcpp::R_390_PLTOFF64)
         && !gsym->final_value_is_known())
       target->make_plt_entry(symtab, layout, gsym);
     break;

   case elfcpp::R_390_GOT12:
   case elfcpp::R_390_GOT16:
   case elfcpp::R_390_GOT20:
   case elfcpp::R_390_GOT32:
   case elfcpp::R_390_GOT64:
   case elfcpp::R_390_GOTENT:
   case elfcpp::R_390_GOTPLT12:
   case elfcpp::R_390_GOTPLT16:
   case elfcpp::R_390_GOTPLT20:
   case elfcpp::R_390_GOTPLT32:
   case elfcpp::R_390_GOTPLT64:
   case elfcpp::R_390_GOTPLTENT:
     {
       // The symbol requires a GOT entry.
       Output_data_got<size, true>* 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_390_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,
                                                 elfcpp::R_390_RELATIVE,
                                                 got, got_off, 0, false);
                 }
             }
         }
     }
     break;

   case elfcpp::R_390_COPY:
   case elfcpp::R_390_GLOB_DAT:
   case elfcpp::R_390_JMP_SLOT:
   case elfcpp::R_390_RELATIVE:
   case elfcpp::R_390_IRELATIVE:
     // These are outstanding tls relocs, which are unexpected when linking
   case elfcpp::R_390_TLS_TPOFF:
   case elfcpp::R_390_TLS_DTPOFF:
   case elfcpp::R_390_TLS_DTPMOD:
     gold_error(_("%s: unexpected reloc %u in object file"),
                object->name().c_str(), r_type);
     break;

     // These are initial tls relocs, which are expected for global()
   case elfcpp::R_390_TLS_GD32:          // Global-dynamic
   case elfcpp::R_390_TLS_GD64:
   case elfcpp::R_390_TLS_GDCALL:
   case elfcpp::R_390_TLS_LDM32:         // Local-dynamic
   case elfcpp::R_390_TLS_LDM64:
   case elfcpp::R_390_TLS_LDO32:
   case elfcpp::R_390_TLS_LDO64:
   case elfcpp::R_390_TLS_LDCALL:
   case elfcpp::R_390_TLS_IE32:          // Initial-exec
   case elfcpp::R_390_TLS_IE64:
   case elfcpp::R_390_TLS_IEENT:
   case elfcpp::R_390_TLS_GOTIE12:
   case elfcpp::R_390_TLS_GOTIE20:
   case elfcpp::R_390_TLS_GOTIE32:
   case elfcpp::R_390_TLS_GOTIE64:
   case elfcpp::R_390_TLS_LOAD:
   case elfcpp::R_390_TLS_LE32:          // Local-exec
   case elfcpp::R_390_TLS_LE64:
     {
       // For the optimizable Initial-Exec model, we can treat undef symbols
       // as final when building an executable.
       const bool is_final = (gsym->final_value_is_known() ||
                              ((r_type == elfcpp::R_390_TLS_IE32 ||
                                r_type == elfcpp::R_390_TLS_IE64 ||
                                r_type == elfcpp::R_390_TLS_GOTIE32 ||
                                r_type == elfcpp::R_390_TLS_GOTIE64) &&
                               gsym->is_undefined() &&
                               parameters->options().output_is_executable()));
       const tls::Tls_optimization optimized_type
           = Target_s390<size>::optimize_tls_reloc(is_final, r_type);
       switch (r_type)
         {
         case elfcpp::R_390_TLS_GD32:       // General-dynamic
         case elfcpp::R_390_TLS_GD64:
         case elfcpp::R_390_TLS_GDCALL:
           if (optimized_type == tls::TLSOPT_NONE)
             {
               // Create a pair of GOT entries for the module index and
               // dtv-relative offset.
               Output_data_got<size, true>* got
                   = target->got_section(symtab, layout);
               got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
                                             target->rela_dyn_section(layout),
                                             elfcpp::R_390_TLS_DTPMOD,
                                             elfcpp::R_390_TLS_DTPOFF);
             }
           else if (optimized_type == tls::TLSOPT_TO_IE)
             {
               // Create a GOT entry for the tp-relative offset.
               Output_data_got<size, true>* got
                   = target->got_section(symtab, layout);
               got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
                                        target->rela_dyn_section(layout),
                                        elfcpp::R_390_TLS_TPOFF);
             }
           else if (optimized_type != tls::TLSOPT_TO_LE)
             unsupported_reloc_global(object, r_type, gsym);
           break;

         case elfcpp::R_390_TLS_LDM32:       // Local-dynamic
         case elfcpp::R_390_TLS_LDM64:
         case elfcpp::R_390_TLS_LDCALL:
           if (optimized_type == tls::TLSOPT_NONE)
             {
               // Create a GOT entry for the module index.
               target->got_mod_index_entry(symtab, layout, object);
             }
           else if (optimized_type != tls::TLSOPT_TO_LE)
             unsupported_reloc_global(object, r_type, gsym);
           break;

         case elfcpp::R_390_TLS_LDO32:
         case elfcpp::R_390_TLS_LDO64:
           break;

         case elfcpp::R_390_TLS_IE32:    // Initial-exec
         case elfcpp::R_390_TLS_IE64:
           // These two involve an absolute address
           if (parameters->options().shared())
             {
               if ((size == 32 && r_type == elfcpp::R_390_TLS_IE32) ||
                   (size == 64 && r_type == elfcpp::R_390_TLS_IE64))
                 {
                   // We need to create a dynamic relocation.
                   Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                   rela_dyn->add_global_relative(gsym, elfcpp::R_390_RELATIVE,
                                                 output_section, object,
                                                 data_shndx,
                                                 reloc.get_r_offset(),
                                                 reloc.get_r_addend(), false);
                 }
               else
                 {
                   unsupported_reloc_global(object, r_type, gsym);
                 }
             }
           // Fall through.
         case elfcpp::R_390_TLS_IEENT:
         case elfcpp::R_390_TLS_GOTIE12:
         case elfcpp::R_390_TLS_GOTIE20:
         case elfcpp::R_390_TLS_GOTIE32:
         case elfcpp::R_390_TLS_GOTIE64:
         case elfcpp::R_390_TLS_LOAD:
           layout->set_has_static_tls();
           if (optimized_type == tls::TLSOPT_NONE)
             {
               if (is_final && !parameters->options().shared())
                 {
                   // We're making an executable, and the symbol is local, but
                   // we cannot optimize to LE.  Make a const GOT entry instead.
                   Output_data_got<size, true>* got
                       = target->got_section(symtab, layout);
                   got->add_global_plt(gsym, GOT_TYPE_TLS_OFFSET);
                 }
               else
                 {
                   // Create a GOT entry for the tp-relative offset.
                   Output_data_got<size, true>* got
                       = target->got_section(symtab, layout);
                   got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
                                            target->rela_dyn_section(layout),
                                            elfcpp::R_390_TLS_TPOFF);
                 }
             }
           else if (optimized_type != tls::TLSOPT_TO_LE)
             unsupported_reloc_global(object, r_type, gsym);
           break;

         case elfcpp::R_390_TLS_LE32:     // Local-exec
         case elfcpp::R_390_TLS_LE64:
           layout->set_has_static_tls();
           if (parameters->options().shared())
             {
               // We need to create a dynamic relocation.
               if ((size == 32 && r_type == elfcpp::R_390_TLS_LE32) ||
                   (size == 64 && r_type == elfcpp::R_390_TLS_LE64))
                 {
                   Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                   rela_dyn->add_global(gsym, elfcpp::R_390_TLS_TPOFF,
                                        output_section, object,
                                        data_shndx, reloc.get_r_offset(),
                                        reloc.get_r_addend());
                 }
               else
                 {
                   unsupported_reloc_global(object, r_type, gsym);
                 }
             }
           break;

         default:
           gold_unreachable();
         }
     }
     break;

   default:
     gold_error(_("%s: unsupported reloc %u against global symbol %s"),
                object->name().c_str(), r_type,
                gsym->demangled_name().c_str());
     break;
   }
}


// Report an unsupported relocation against a global symbol.

template<int size>
void
Target_s390<size>::Scan::unsupported_reloc_global(
   Sized_relobj_file<size, true>* 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>
inline bool
Target_s390<size>::Scan::possible_function_pointer_reloc(unsigned int r_type)
{
 switch (r_type)
   {
   case elfcpp::R_390_32:
   case elfcpp::R_390_64:
   case elfcpp::R_390_PC32DBL: // could be used by larl insn
   case elfcpp::R_390_GOT12:
   case elfcpp::R_390_GOT16:
   case elfcpp::R_390_GOT20:
   case elfcpp::R_390_GOT32:
   case elfcpp::R_390_GOT64:
   case elfcpp::R_390_GOTENT:
   case elfcpp::R_390_GOTOFF16:
   case elfcpp::R_390_GOTOFF32:
   case elfcpp::R_390_GOTOFF64:
     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>
inline bool
Target_s390<size>::Scan::local_reloc_may_be_function_pointer(
 Symbol_table* ,
 Layout* ,
 Target_s390<size>* ,
 Sized_relobj_file<size, true>* ,
 unsigned int ,
 Output_section* ,
 const elfcpp::Rela<size, true>& ,
 unsigned int r_type,
 const elfcpp::Sym<size, true>&)
{
 // When building a shared library, do not fold any local symbols.
 return (parameters->options().shared()
         || 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>
inline bool
Target_s390<size>::Scan::global_reloc_may_be_function_pointer(
 Symbol_table*,
 Layout* ,
 Target_s390<size>* ,
 Sized_relobj_file<size, true>* ,
 unsigned int ,
 Output_section* ,
 const elfcpp::Rela<size, true>& ,
 unsigned int r_type,
 Symbol* gsym)
{
 // 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));
}

template<int size>
void
Target_s390<size>::gc_process_relocs(Symbol_table* symtab,
                                      Layout* layout,
                                      Sized_relobj_file<size, true>* 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 gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
     Classify_reloc;

 if (sh_type == elfcpp::SHT_REL)
   return;

 gold::gc_process_relocs<size, true, Target_s390<size>, Scan, Classify_reloc>(
   symtab,
   layout,
   this,
   object,
   data_shndx,
   prelocs,
   reloc_count,
   output_section,
   needs_special_offset_handling,
   local_symbol_count,
   plocal_symbols);
}

// Perform a relocation.

template<int size>
inline bool
Target_s390<size>::Relocate::relocate(
   const Relocate_info<size, true>* relinfo,
   unsigned int,
   Target_s390<size>* 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 view_size)
{
 if (view == NULL)
   return true;

 const elfcpp::Rela<size, true> rela(preloc);
 unsigned int r_type = elfcpp::elf_r_type<size>(rela.get_r_info());
 const Sized_relobj_file<size, true>* 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;
       }
   }

 const elfcpp::Elf_Xword addend = rela.get_r_addend();

 typename elfcpp::Elf_types<size>::Elf_Addr value = 0;

 switch (r_type)
   {
   case elfcpp::R_390_PLT64:
   case elfcpp::R_390_PLT32:
   case elfcpp::R_390_PLT32DBL:
   case elfcpp::R_390_PLT24DBL:
   case elfcpp::R_390_PLT16DBL:
   case elfcpp::R_390_PLT12DBL:
     gold_assert(gsym == NULL
                 || gsym->has_plt_offset()
                 || gsym->final_value_is_known()
                 || (gsym->is_defined()
                     && !gsym->is_from_dynobj()
                     && !gsym->is_preemptible()));
     // Fall through.
   case elfcpp::R_390_8:
   case elfcpp::R_390_12:
   case elfcpp::R_390_16:
   case elfcpp::R_390_20:
   case elfcpp::R_390_32:
   case elfcpp::R_390_64:
   case elfcpp::R_390_PC16:
   case elfcpp::R_390_PC32:
   case elfcpp::R_390_PC64:
   case elfcpp::R_390_PC32DBL:
   case elfcpp::R_390_PC24DBL:
   case elfcpp::R_390_PC16DBL:
   case elfcpp::R_390_PC12DBL:
     value = psymval->value(object, addend);
     break;

   case elfcpp::R_390_GOTPC:
   case elfcpp::R_390_GOTPCDBL:
     gold_assert(gsym != NULL);
     value = target->got_address() + addend;
     break;

   case elfcpp::R_390_PLTOFF64:
   case elfcpp::R_390_PLTOFF32:
   case elfcpp::R_390_PLTOFF16:
     gold_assert(gsym == NULL
                 || gsym->has_plt_offset()
                 || gsym->final_value_is_known());
     // Fall through.
   case elfcpp::R_390_GOTOFF64:
   case elfcpp::R_390_GOTOFF32:
   case elfcpp::R_390_GOTOFF16:
     value = (psymval->value(object, addend)
              - target->got_address());
     break;

   case elfcpp::R_390_GOT12:
   case elfcpp::R_390_GOT16:
   case elfcpp::R_390_GOT20:
   case elfcpp::R_390_GOT32:
   case elfcpp::R_390_GOT64:
   case elfcpp::R_390_GOTENT:
   case elfcpp::R_390_GOTPLT12:
   case elfcpp::R_390_GOTPLT16:
   case elfcpp::R_390_GOTPLT20:
   case elfcpp::R_390_GOTPLT32:
   case elfcpp::R_390_GOTPLT64:
   case elfcpp::R_390_GOTPLTENT:
     {
       unsigned int got_offset = 0;
       if (gsym != NULL)
         {
           gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
           got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
         }
       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_STANDARD));
           got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
         }
       value = got_offset + target->got_main_offset() + addend;
     }
     break;

     // These are initial tls relocs, which are expected when linking
   case elfcpp::R_390_TLS_LOAD:
   case elfcpp::R_390_TLS_GDCALL:          // Global-dynamic
   case elfcpp::R_390_TLS_GD32:
   case elfcpp::R_390_TLS_GD64:
   case elfcpp::R_390_TLS_LDCALL:          // Local-dynamic
   case elfcpp::R_390_TLS_LDM32:
   case elfcpp::R_390_TLS_LDM64:
   case elfcpp::R_390_TLS_LDO32:
   case elfcpp::R_390_TLS_LDO64:
   case elfcpp::R_390_TLS_GOTIE12:         // Initial-exec
   case elfcpp::R_390_TLS_GOTIE20:
   case elfcpp::R_390_TLS_GOTIE32:
   case elfcpp::R_390_TLS_GOTIE64:
   case elfcpp::R_390_TLS_IE32:
   case elfcpp::R_390_TLS_IE64:
   case elfcpp::R_390_TLS_IEENT:
   case elfcpp::R_390_TLS_LE32:            // Local-exec
   case elfcpp::R_390_TLS_LE64:
     value = this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
                        view, view_size);
     break;

   default:
     break;
   }

 typename S390_relocate_functions<size>::Status status
     = S390_relocate_functions<size>::STATUS_OK;

 switch (r_type)
   {
   case elfcpp::R_390_NONE:
   case elfcpp::R_390_GNU_VTINHERIT:
   case elfcpp::R_390_GNU_VTENTRY:
   case elfcpp::R_390_TLS_GDCALL:
   case elfcpp::R_390_TLS_LDCALL:
   case elfcpp::R_390_TLS_LOAD:
     break;

   case elfcpp::R_390_64:
   case elfcpp::R_390_GOT64:
   case elfcpp::R_390_GOTPLT64:
   case elfcpp::R_390_PLTOFF64:
   case elfcpp::R_390_GOTOFF64:
   case elfcpp::R_390_TLS_GD64:
   case elfcpp::R_390_TLS_LDM64:
   case elfcpp::R_390_TLS_LDO64:
   case elfcpp::R_390_TLS_GOTIE64:
   case elfcpp::R_390_TLS_IE64:
   case elfcpp::R_390_TLS_LE64:
     Relocate_functions<size, true>::rela64(view, value, 0);
     break;

   case elfcpp::R_390_32:
   case elfcpp::R_390_GOT32:
   case elfcpp::R_390_GOTPLT32:
   case elfcpp::R_390_PLTOFF32:
   case elfcpp::R_390_GOTOFF32:
   case elfcpp::R_390_TLS_GD32:
   case elfcpp::R_390_TLS_LDM32:
   case elfcpp::R_390_TLS_LDO32:
   case elfcpp::R_390_TLS_GOTIE32:
   case elfcpp::R_390_TLS_IE32:
   case elfcpp::R_390_TLS_LE32:
     Relocate_functions<size, true>::rela32(view, value, 0);
     break;

   case elfcpp::R_390_20:
   case elfcpp::R_390_GOT20:
   case elfcpp::R_390_GOTPLT20:
   case elfcpp::R_390_TLS_GOTIE20:
     status = S390_relocate_functions<size>::rela20(view, value);
     break;

   case elfcpp::R_390_16:
   case elfcpp::R_390_GOT16:
   case elfcpp::R_390_GOTPLT16:
   case elfcpp::R_390_PLTOFF16:
   case elfcpp::R_390_GOTOFF16:
     status = S390_relocate_functions<size>::rela16(view, value);
     break;

   case elfcpp::R_390_12:
   case elfcpp::R_390_GOT12:
   case elfcpp::R_390_GOTPLT12:
   case elfcpp::R_390_TLS_GOTIE12:
     status = S390_relocate_functions<size>::rela12(view, value);
     break;

   case elfcpp::R_390_8:
     Relocate_functions<size, true>::rela8(view, value, 0);
     break;

   case elfcpp::R_390_PC16:
     Relocate_functions<size, true>::pcrela16(view, value, 0,
                                              address);
     break;

   case elfcpp::R_390_PLT64:
   case elfcpp::R_390_PC64:
     Relocate_functions<size, true>::pcrela64(view, value, 0, address);
     break;

   case elfcpp::R_390_PLT32:
   case elfcpp::R_390_PC32:
   case elfcpp::R_390_GOTPC:
     Relocate_functions<size, true>::pcrela32(view, value, 0, address);
     break;

   case elfcpp::R_390_PLT32DBL:
   case elfcpp::R_390_PC32DBL:
   case elfcpp::R_390_GOTPCDBL:
     status = S390_relocate_functions<size>::pcrela32dbl(view, value, address);
     break;

   case elfcpp::R_390_PLT24DBL:
   case elfcpp::R_390_PC24DBL:
     status = S390_relocate_functions<size>::pcrela24dbl(view, value, address);
     break;

   case elfcpp::R_390_PLT16DBL:
   case elfcpp::R_390_PC16DBL:
     status = S390_relocate_functions<size>::pcrela16dbl(view, value, address);
     break;

   case elfcpp::R_390_PLT12DBL:
   case elfcpp::R_390_PC12DBL:
     status = S390_relocate_functions<size>::pcrela12dbl(view, value, address);
     break;

   case elfcpp::R_390_GOTENT:
   case elfcpp::R_390_GOTPLTENT:
   case elfcpp::R_390_TLS_IEENT:
     value += target->got_address();
     status = S390_relocate_functions<size>::pcrela32dbl(view, value, address);
     break;

   case elfcpp::R_390_COPY:
   case elfcpp::R_390_GLOB_DAT:
   case elfcpp::R_390_JMP_SLOT:
   case elfcpp::R_390_RELATIVE:
   case elfcpp::R_390_IRELATIVE:
     // These are outstanding tls relocs, which are unexpected when linking
   case elfcpp::R_390_TLS_TPOFF:
   case elfcpp::R_390_TLS_DTPMOD:
   case elfcpp::R_390_TLS_DTPOFF:
     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;
   }

 if (status != S390_relocate_functions<size>::STATUS_OK)
   {
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("relocation overflow"));
   }

 return true;
}

// Perform a TLS relocation.

template<int size>
inline typename elfcpp::Elf_types<size>::Elf_Addr
Target_s390<size>::Relocate::relocate_tls(
   const Relocate_info<size, true>* relinfo,
   Target_s390<size>* target,
   size_t relnum,
   const elfcpp::Rela<size, true>& rela,
   unsigned int r_type,
   const Sized_symbol<size>* gsym,
   const Symbol_value<size>* psymval,
   unsigned char* view,
   section_size_type view_size)
{
 Output_segment* tls_segment = relinfo->layout->tls_segment();

 const Sized_relobj_file<size, true>* object = relinfo->object;
 const elfcpp::Elf_Xword addend = rela.get_r_addend();
 elfcpp::Shdr<size, true> data_shdr(relinfo->data_shdr);
 bool is_allocatable = (data_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0;

 typename elfcpp::Elf_types<size>::Elf_Addr value
     = psymval->value(relinfo->object, addend);

 const bool is_final = (gsym == NULL
                        ? !parameters->options().shared()
                        : gsym->final_value_is_known());
 tls::Tls_optimization optimized_type
     = Target_s390<size>::optimize_tls_reloc(is_final, r_type);
 switch (r_type)
   {
   case elfcpp::R_390_TLS_GDCALL:            // Global-dynamic marker
     if (optimized_type == tls::TLSOPT_TO_LE)
       {
         if (tls_segment == NULL)
           {
             gold_assert(parameters->errors()->error_count() > 0
                         || issue_undefined_symbol_error(gsym));
             return 0;
           }
         this->tls_gd_to_le(relinfo, relnum, rela, view, view_size);
         break;
       }
     else
       {
         if (optimized_type == tls::TLSOPT_TO_IE)
           {
             this->tls_gd_to_ie(relinfo, relnum, rela, view, view_size);
             break;
           }
         else if (optimized_type == tls::TLSOPT_NONE)
           {
             break;
           }
       }
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("unsupported reloc %u"), r_type);
     break;

   case elfcpp::R_390_TLS_GD32:            // Global-dynamic
   case elfcpp::R_390_TLS_GD64:
     if (optimized_type == tls::TLSOPT_TO_LE)
       {
         if (tls_segment == NULL)
           {
             gold_assert(parameters->errors()->error_count() > 0
                         || issue_undefined_symbol_error(gsym));
             return 0;
           }
         return value - tls_segment->memsz();
       }
     else
       {
         unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
                                  ? GOT_TYPE_TLS_OFFSET
                                  : GOT_TYPE_TLS_PAIR);
         if (gsym != NULL)
           {
             gold_assert(gsym->has_got_offset(got_type));
             return (gsym->got_offset(got_type)
                     + target->got_main_offset()
                     + addend);
           }
         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));
             return (object->local_got_offset(r_sym, got_type)
                     + target->got_main_offset()
                     + addend);
           }
       }
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("unsupported reloc %u"), r_type);
     break;

   case elfcpp::R_390_TLS_LDCALL:            // Local-dynamic marker
     // This is a marker relocation. If the sequence is being turned to LE,
     // we modify the instruction, otherwise the instruction is untouched.
     if (optimized_type == tls::TLSOPT_TO_LE)
       {
         if (tls_segment == NULL)
           {
             gold_assert(parameters->errors()->error_count() > 0
                         || issue_undefined_symbol_error(gsym));
             return 0;
           }
         this->tls_ld_to_le(relinfo, relnum, rela, view, view_size);
         break;
       }
     else if (optimized_type == tls::TLSOPT_NONE)
       {
         break;
       }
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("unsupported reloc %u"), r_type);
     break;

   case elfcpp::R_390_TLS_LDM32:            // Local-dynamic module
   case elfcpp::R_390_TLS_LDM64:
     if (optimized_type == tls::TLSOPT_TO_LE)
       {
         if (tls_segment == NULL)
           {
             gold_assert(parameters->errors()->error_count() > 0
                         || issue_undefined_symbol_error(gsym));
             return 0;
           }
         // Doesn't matter what we fill it with - it's going to be unused.
         return 0;
       }
     else if (optimized_type == tls::TLSOPT_NONE)
       {
         // Relocate the field with the offset of the GOT entry for
         // the module index.
         return (target->got_mod_index_entry(NULL, NULL, NULL)
                 + addend
                 + target->got_main_offset());
       }
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("unsupported reloc %u"), r_type);
     break;

   case elfcpp::R_390_TLS_LDO32:         // Local-dynamic offset
   case elfcpp::R_390_TLS_LDO64:
     // This relocation type is used in debugging information.
     // In that case we need to not optimize the value.  If the
     // section is not allocatable, then we assume we should not
     // optimize this reloc.
     if (optimized_type == tls::TLSOPT_TO_LE && is_allocatable)
       {
         if (tls_segment == NULL)
           {
             gold_assert(parameters->errors()->error_count() > 0
                         || issue_undefined_symbol_error(gsym));
             return 0;
           }
         value -= tls_segment->memsz();
       }
     return value;

   case elfcpp::R_390_TLS_LOAD:         // Initial-exec marker
     // This is a marker relocation. If the sequence is being turned to LE,
     // we modify the instruction, otherwise the instruction is untouched.
     if (gsym != NULL
         && gsym->is_undefined()
         && parameters->options().output_is_executable())
       {
         Target_s390<size>::Relocate::tls_ie_to_le(relinfo, relnum,
                                                     rela, view,
                                                     view_size);
         break;
       }
     else if (optimized_type == tls::TLSOPT_TO_LE)
       {
         if (tls_segment == NULL)
           {
             gold_assert(parameters->errors()->error_count() > 0
                         || issue_undefined_symbol_error(gsym));
             return 0;
           }
         Target_s390<size>::Relocate::tls_ie_to_le(relinfo, relnum,
                                                     rela, view,
                                                     view_size);
         break;
       }
     else if (optimized_type == tls::TLSOPT_NONE)
       {
         break;
       }
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("unsupported reloc type %u"),
                            r_type);
     break;

   case elfcpp::R_390_TLS_GOTIE12:       // Initial-exec, not optimizable
   case elfcpp::R_390_TLS_GOTIE20:
   case elfcpp::R_390_TLS_IEENT:
   case elfcpp::R_390_TLS_GOTIE32:       // Initial-exec, optimizable
   case elfcpp::R_390_TLS_GOTIE64:
   case elfcpp::R_390_TLS_IE32:
   case elfcpp::R_390_TLS_IE64:
     if (gsym != NULL
         && gsym->is_undefined()
         && parameters->options().output_is_executable()
         // These three cannot be optimized to LE, no matter what
         && r_type != elfcpp::R_390_TLS_GOTIE12
         && r_type != elfcpp::R_390_TLS_GOTIE20
         && r_type != elfcpp::R_390_TLS_IEENT)
       {
         return value;
       }
     else if (optimized_type == tls::TLSOPT_TO_LE)
       {
         if (tls_segment == NULL)
           {
             gold_assert(parameters->errors()->error_count() > 0
                         || issue_undefined_symbol_error(gsym));
             return 0;
           }
         return value - tls_segment->memsz();
       }
     else if (optimized_type == tls::TLSOPT_NONE)
       {
         // Relocate the field with the offset of the GOT entry for
         // the tp-relative offset of the symbol.
         unsigned int got_offset;
         if (gsym != NULL)
           {
             gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
             got_offset = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
           }
         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_TLS_OFFSET));
             got_offset = object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
           }
         got_offset += target->got_main_offset();
         if (r_type == elfcpp::R_390_TLS_IE32
             || r_type == elfcpp::R_390_TLS_IE64)
           return target->got_address() + got_offset + addend;
         else
           return got_offset + addend;
       }
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("unsupported reloc type %u"),
                            r_type);
     break;

   case elfcpp::R_390_TLS_LE32:          // Local-exec
   case elfcpp::R_390_TLS_LE64:
     if (tls_segment == NULL)
       {
         gold_assert(parameters->errors()->error_count() > 0
                     || issue_undefined_symbol_error(gsym));
         return 0;
       }
     return value - tls_segment->memsz();
   }
 return 0;
}

// Do a relocation in which we convert a TLS General-Dynamic to an
// Initial-Exec.

template<int size>
inline void
Target_s390<size>::Relocate::tls_gd_to_ie(
   const Relocate_info<size, true>* relinfo,
   size_t relnum,
   const elfcpp::Rela<size, true>& rela,
   unsigned char* view,
   section_size_type view_size)
{
 tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
 if (view[0] == 0x4d)
   {
     // bas, don't care about details
     // Change to l %r2, 0(%r2, %r12)
     view[0] = 0x58;
     view[1] = 0x22;
     view[2] = 0xc0;
     view[3] = 0x00;
     return;
   }
 else if (view[0] == 0xc0)
   {
     tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 6);
     // brasl %r14, __tls_get_offset@plt
     if (view[1] == 0xe5)
       {
         // Change to l/lg %r2, 0(%r2, %r12)
         // There was a PLT32DBL reloc at the last 4 bytes, overwrite its result.
         if (size == 32)
           {
             // l
             view[0] = 0x58;
             view[1] = 0x22;
             view[2] = 0xc0;
             view[3] = 0x00;
             // nop
             view[4] = 0x07;
             view[5] = 0x07;
           }
         else
           {
             // lg
             view[0] = 0xe3;
             view[1] = 0x22;
             view[2] = 0xc0;
             view[3] = 0;
             view[4] = 0;
             view[5] = 0x04;
           }
         return;
       }
   }
 gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                        _("unsupported op for GD to IE"));
}

// Do a relocation in which we convert a TLS General-Dynamic to a
// Local-Exec.

template<int size>
inline void
Target_s390<size>::Relocate::tls_gd_to_le(
   const Relocate_info<size, true>* relinfo,
   size_t relnum,
   const elfcpp::Rela<size, true>& rela,
   unsigned char* view,
   section_size_type view_size)
{
 tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
 if (view[0] == 0x0d)
   {
     // basr, change to nop
     view[0] = 0x07;
     view[1] = 0x07;
   }
 else if (view[0] == 0x4d)
   {
     tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
     // bas, don't care about details, change to nop
     view[0] = 0x47;
     view[1] = 0;
     view[2] = 0;
     view[3] = 0;
     return;
   }
 else if (view[0] == 0xc0)
   {
     tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 6);
     // brasl %r14, __tls_get_offset@plt
     if (view[1] == 0xe5)
       {
         // Change to nop jump. There was a PLT32DBL reloc at the last
         // 4 bytes, overwrite its result.
         view[1] = 0x04;
         view[2] = 0;
         view[3] = 0;
         view[4] = 0;
         view[5] = 0;
         return;
       }
   }
 gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                        _("unsupported op for GD to LE"));
}

template<int size>
inline void
Target_s390<size>::Relocate::tls_ld_to_le(
   const Relocate_info<size, true>* relinfo,
   size_t relnum,
   const elfcpp::Rela<size, true>& rela,
   unsigned char* view,
   section_size_type view_size)
{
 tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);

 if (view[0] == 0x0d)
   {
     // basr, change to nop
     view[0] = 0x07;
     view[1] = 0x07;
   }
 else if (view[0] == 0x4d)
   {
     // bas, don't care about details, change to nop
     view[0] = 0x47;
     view[1] = 0;
     view[2] = 0;
     view[3] = 0;
     return;
   }
 else if (view[0] == 0xc0)
   {
     tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 6);
     // brasl %r14, __tls_get_offset@plt
     if (view[1] == 0xe5)
       {
         // Change to nop jump. There was a PLT32DBL reloc at the last
         // 4 bytes, overwrite its result.
         view[1] = 0x04;
         view[2] = 0;
         view[3] = 0;
         view[4] = 0;
         view[5] = 0;
         return;
       }
   }
 gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                        _("unsupported op for LD to LE"));
}

// Do a relocation in which we convert a TLS Initial-Exec to a
// Local-Exec.

template<int size>
inline void
Target_s390<size>::Relocate::tls_ie_to_le(
   const Relocate_info<size, true>* relinfo,
   size_t relnum,
   const elfcpp::Rela<size, true>& rela,
   unsigned char* view,
   section_size_type view_size)
{
 tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);

 if (view[0] == 0x58)
   {
     // l %rX, 0(%rY) or l %rX, 0(%rY, %r12)
     if ((view[2] & 0x0f) != 0 || view[3] != 0)
       goto err;
     int rx = view[1] >> 4 & 0xf;
     int ry = view[1] & 0xf;
     int rz = view[2] >> 4 & 0xf;
     if (rz == 0)
       {
       }
     else if (ry == 0)
       {
         ry = rz;
       }
     else if (rz == 12)
       {
       }
     else if (ry == 12)
       {
         ry = rz;
       }
     else
       goto err;
     // to lr %rX, $rY
     view[0] = 0x18;
     view[1] = rx << 4 | ry;
     // and insert a nop
     view[2] = 0x07;
     view[3] = 0x00;
   }
 else if (view[0] == 0xe3)
   {
     tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 6);
     // lg %rX, 0(%rY) or lg %rX, 0(%rY, %r12)
     if ((view[2] & 0x0f) != 0 ||
         view[3] != 0 ||
         view[4] != 0 ||
         view[5] != 0x04)
       goto err;
     int rx = view[1] >> 4 & 0xf;
     int ry = view[1] & 0xf;
     int rz = view[2] >> 4 & 0xf;
     if (rz == 0)
       {
       }
     else if (ry == 0)
       {
         ry = rz;
       }
     else if (rz == 12)
       {
       }
     else if (ry == 12)
       {
         ry = rz;
       }
     else
       goto err;
     // to sllg %rX, $rY, 0
     view[0] = 0xeb;
     view[1] = rx << 4 | ry;
     view[2] = 0x00;
     view[3] = 0x00;
     view[4] = 0x00;
     view[5] = 0x0d;
   }
 else
   {
err:
     gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                            _("unsupported op for IE to LE"));
   }
}

// Scan relocations for a section.

template<int size>
void
Target_s390<size>::scan_relocs(Symbol_table* symtab,
                                Layout* layout,
                                Sized_relobj_file<size, true>* 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 gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
     Classify_reloc;

 if (sh_type == elfcpp::SHT_REL)
   {
     gold_error(_("%s: unsupported REL reloc section"),
                object->name().c_str());
     return;
   }

 gold::scan_relocs<size, true, Target_s390<size>, Scan, Classify_reloc>(
   symtab,
   layout,
   this,
   object,
   data_shndx,
   prelocs,
   reloc_count,
   output_section,
   needs_special_offset_handling,
   local_symbol_count,
   plocal_symbols);
}

// Finalize the sections.

template<int size>
void
Target_s390<size>::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, size == 32, false);

 this->layout_ = layout;

 // 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 (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());
   }
}

// Scan the relocs during a relocatable link.

template<int size>
void
Target_s390<size>::scan_relocatable_relocs(
   Symbol_table* symtab,
   Layout* layout,
   Sized_relobj_file<size, true>* 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, true>
     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, true, 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>
void
Target_s390<size>::emit_relocs_scan(
   Symbol_table* symtab,
   Layout* layout,
   Sized_relobj_file<size, true>* 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, true>
     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, true, 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>
void
Target_s390<size>::relocate_relocs(
   const Relocate_info<size, true>* 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, true>
     Classify_reloc;

 gold_assert(sh_type == elfcpp::SHT_RELA);

 gold::relocate_relocs<size, true, Classify_reloc>(
   relinfo,
   prelocs,
   reloc_count,
   output_section,
   offset_in_output_section,
   view,
   view_address,
   view_size,
   reloc_view,
   reloc_view_size);
}

// Return the offset to use for the GOT_INDX'th got entry which is
// for a local tls symbol specified by OBJECT, SYMNDX.
template<int size>
int64_t
Target_s390<size>::do_tls_offset_for_local(
   const Relobj*,
   unsigned int,
   Output_data_got_base*,
   unsigned int,
   uint64_t) const
{
 // The only way we can get called is when IEENT/GOTIE12/GOTIE20
 // couldn't be optimised to LE.
 Output_segment* tls_segment = layout_->tls_segment();
 return -tls_segment->memsz();
}

// Return the offset to use for the GOT_INDX'th got entry which is
// for global tls symbol GSYM.
template<int size>
int64_t
Target_s390<size>::do_tls_offset_for_global(
   Symbol*,
   Output_data_got_base*,
   unsigned int,
   uint64_t) const
{
 Output_segment* tls_segment = layout_->tls_segment();
 return -tls_segment->memsz();
}

// 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>
uint64_t
Target_s390<size>::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 a string used to fill a code section with nops to take up
// the specified length.

template<int size>
std::string
Target_s390<size>::do_code_fill(section_size_type length) const
{
 if (length & 1)
   gold_warning(_("S/390 code fill of odd length requested"));
 return std::string(length, static_cast<char>(0x07));
}

// Return whether SYM should be treated as a call to a non-split
// function.  We don't want that to be true of a larl instruction
// that merely loads its address.

template<int size>
bool
Target_s390<size>::do_is_call_to_non_split(const Symbol* sym,
                                          const unsigned char* preloc,
                                          const unsigned char* view,
                                          section_size_type view_size) const
{
 if (sym->type() != elfcpp::STT_FUNC)
   return false;
 typename Reloc_types<elfcpp::SHT_RELA, size, true>::Reloc reloc(preloc);
 typename elfcpp::Elf_types<size>::Elf_WXword r_info
   = reloc.get_r_info();
 unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
 section_offset_type offset = reloc.get_r_offset();
 switch (r_type)
   {
   // PLT refs always involve calling the function.
   case elfcpp::R_390_PLT12DBL:
   case elfcpp::R_390_PLT16DBL:
   case elfcpp::R_390_PLT24DBL:
   case elfcpp::R_390_PLT32:
   case elfcpp::R_390_PLT32DBL:
   case elfcpp::R_390_PLT64:
   case elfcpp::R_390_PLTOFF16:
   case elfcpp::R_390_PLTOFF32:
   case elfcpp::R_390_PLTOFF64:
   // Could be used for calls for -msmall-exec.
   case elfcpp::R_390_PC16DBL:
     return true;

   // Tricky case.  When used in a brasl, jg, and other branch instructions,
   // it's a call or a sibcall.  However, when used in larl, it only loads
   // the function's address - not a call.
   case elfcpp::R_390_PC32DBL:
     {
       if (offset < 2
           || offset + 4 > static_cast<section_offset_type>(view_size))
         {
           // Should not happen.
           gold_error(_("instruction with PC32DBL not wholly within section"));
           return false;
         }

       uint8_t op0 = view[offset-2];
       uint8_t op1 = view[offset-1] & 0xf;

       // LARL
       if (op0 == 0xc0 && op1 == 0)
         return false;

       // Otherwise, it's either a call instruction, a branch instruction
       // (used as a sibcall), or a data manipulation instruction (which
       // has no business being used on a function, and can be ignored).
       return true;
     }

   // Otherwise, it's probably not a call.
   default:
     return false;
   }
}

// Code sequences to match below.

template<int size>
const unsigned char
Target_s390<size>::ss_code_bras_8[] = {
 0xa7, 0x15, 0x00, 0x06,               // bras %r1, .+0xc
};

template<int size>
const unsigned char
Target_s390<size>::ss_code_l_basr[] = {
 0x58, 0xe0, 0x10, 0x00,               // l %r14, 0(%r1)
 0x58, 0x10, 0x10, 0x04,               // l %r1, 4(%r1)
 0x0d, 0xee,                           // basr %r14, %r14
};

template<int size>
const unsigned char
Target_s390<size>::ss_code_a_basr[] = {
 0x18, 0xe1,                           // lr %r14, %r1
 0x5a, 0xe0, 0x10, 0x00,               // a %r14, 0(%r1)
 0x5a, 0x10, 0x10, 0x04,               // a %r1, 4(%r1)
 0x0d, 0xee,                           // basr %r14, %r14
};

template<int size>
const unsigned char
Target_s390<size>::ss_code_larl[] = {
 0xc0, 0x10,                           // larl %r1, ...
};

template<int size>
const unsigned char
Target_s390<size>::ss_code_brasl[] = {
 0xc0, 0xe5,                           // brasl %r14, ...
};

template<int size>
const unsigned char
Target_s390<size>::ss_code_jg[] = {
 0xc0, 0xf4,                           // jg ...
};

template<int size>
const unsigned char
Target_s390<size>::ss_code_jgl[] = {
 0xc0, 0x44,                           // jgl ...
};

template<>
bool
Target_s390<32>::ss_match_st_r14(unsigned char* view,
                                section_size_type view_size,
                                section_offset_type *offset) const
{
 static const unsigned char ss_code_st_r14[] = {
   0x50, 0xe0, 0xf0, 0x04,             // st %r14, 4(%r15)
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_st_r14,
                         sizeof ss_code_st_r14))
   return false;
 *offset += sizeof ss_code_st_r14;
 return true;
}

template<>
bool
Target_s390<64>::ss_match_st_r14(unsigned char* view,
                                section_size_type view_size,
                                section_offset_type *offset) const
{
 static const unsigned char ss_code_st_r14[] = {
   0xe3, 0xe0, 0xf0, 0x08, 0x00, 0x24  // stg %r14, 8(%r15)
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_st_r14,
                         sizeof ss_code_st_r14))
   return false;
 *offset += sizeof ss_code_st_r14;
 return true;
}

template<>
bool
Target_s390<32>::ss_match_l_r14(unsigned char* view,
                               section_size_type view_size,
                               section_offset_type *offset) const
{
 static const unsigned char ss_code_l_r14[] = {
   0x58, 0xe0, 0xf0, 0x04,             // l %r14, 4(%r15)
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_l_r14,
                         sizeof ss_code_l_r14))
   return false;
 *offset += sizeof ss_code_l_r14;
 return true;
}

template<>
bool
Target_s390<64>::ss_match_l_r14(unsigned char* view,
                               section_size_type view_size,
                               section_offset_type *offset) const
{
 static const unsigned char ss_code_l_r14[] = {
   0xe3, 0xe0, 0xf0, 0x08, 0x00, 0x04  // lg %r14, 8(%r15)
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_l_r14,
                         sizeof ss_code_l_r14))
   return false;
 *offset += sizeof ss_code_l_r14;
 return true;
}

template<int size>
bool
Target_s390<size>::ss_match_mcount(unsigned char* view,
                                  section_size_type view_size,
                                  section_offset_type *offset) const
{
 // Match the mcount call sequence.
 section_offset_type myoff = *offset;

 // First, look for the store instruction saving %r14.
 if (!this->ss_match_st_r14(view, view_size, &myoff))
   return false;

 // Now, param load and the actual call.
 if (this->match_view_u(view, view_size, myoff, ss_code_larl,
                        sizeof ss_code_larl))
   {
     myoff += sizeof ss_code_larl + 4;

     // After larl, expect a brasl.
     if (!this->match_view_u(view, view_size, myoff, ss_code_brasl,
                             sizeof ss_code_brasl))
       return false;
     myoff += sizeof ss_code_brasl + 4;
   }
 else if (size == 32 &&
          this->match_view_u(view, view_size, myoff, ss_code_bras_8,
                             sizeof ss_code_bras_8))
   {
     // The bras skips over a block of 8 bytes, loading its address
     // to %r1.
     myoff += sizeof ss_code_bras_8 + 8;

     // Now, there are two sequences used for actual load and call,
     // absolute and PIC.
     if (this->match_view_u(view, view_size, myoff, ss_code_l_basr,
                            sizeof ss_code_l_basr))
       myoff += sizeof ss_code_l_basr;
     else if (this->match_view_u(view, view_size, myoff, ss_code_a_basr,
                                 sizeof ss_code_a_basr))
       myoff += sizeof ss_code_a_basr;
     else
       return false;
   }
 else
   return false;

 // Finally, a load bringing %r14 back.
 if (!this->ss_match_l_r14(view, view_size, &myoff))
   return false;

 // Found it.
 *offset = myoff;
 return true;
}

template<>
bool
Target_s390<32>::ss_match_ear(unsigned char* view,
                               section_size_type view_size,
                               section_offset_type *offset) const
{
 static const unsigned char ss_code_ear[] = {
   0xb2, 0x4f, 0x00, 0x10,             // ear %r1, %a0
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_ear,
                         sizeof ss_code_ear))
   return false;
 *offset += sizeof ss_code_ear;
 return true;
}

template<>
bool
Target_s390<64>::ss_match_ear(unsigned char* view,
                               section_size_type view_size,
                               section_offset_type *offset) const
{
 static const unsigned char ss_code_ear[] = {
   0xb2, 0x4f, 0x00, 0x10,             // ear %r1, %a0
   0xeb, 0x11, 0x00, 0x20, 0x00, 0x0d, // sllg %r1,%r1,32
   0xb2, 0x4f, 0x00, 0x11,             // ear %r1, %a1
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_ear,
                         sizeof ss_code_ear))
   return false;
 *offset += sizeof ss_code_ear;
 return true;
}

template<>
bool
Target_s390<32>::ss_match_c(unsigned char* view,
                               section_size_type view_size,
                               section_offset_type *offset) const
{
 static const unsigned char ss_code_c[] = {
   0x59, 0xf0, 0x10, 0x20,             // c %r15, 0x20(%r1)
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_c,
                         sizeof ss_code_c))
   return false;
 *offset += sizeof ss_code_c;
 return true;
}

template<>
bool
Target_s390<64>::ss_match_c(unsigned char* view,
                               section_size_type view_size,
                               section_offset_type *offset) const
{
 static const unsigned char ss_code_c[] = {
   0xe3, 0xf0, 0x10, 0x38, 0x00, 0x20, // cg %r15, 0x38(%r1)
 };
 if (!this->match_view_u(view, view_size, *offset, ss_code_c,
                         sizeof ss_code_c))
   return false;
 *offset += sizeof ss_code_c;
 return true;
}

template<>
bool
Target_s390<32>::ss_match_l(unsigned char* view,
                           section_size_type view_size,
                           section_offset_type *offset,
                           int *guard_reg) const
{
 // l %guard_reg, 0x20(%r1)
 if (convert_to_section_size_type(*offset + 4) > view_size
     || view[*offset] != 0x58
     || (view[*offset + 1] & 0xf) != 0x0
     || view[*offset + 2] != 0x10
     || view[*offset + 3] != 0x20)
   return false;
 *offset += 4;
 *guard_reg = view[*offset + 1] >> 4 & 0xf;
 return true;
}

template<>
bool
Target_s390<64>::ss_match_l(unsigned char* view,
                           section_size_type view_size,
                           section_offset_type *offset,
                           int *guard_reg) const
{
 // lg %guard_reg, 0x38(%r1)
 if (convert_to_section_size_type(*offset + 6) > view_size
     || view[*offset] != 0xe3
     || (view[*offset + 1] & 0xf) != 0x0
     || view[*offset + 2] != 0x10
     || view[*offset + 3] != 0x38
     || view[*offset + 4] != 0x00
     || view[*offset + 5] != 0x04)
   return false;
 *offset += 6;
 *guard_reg = view[*offset + 1] >> 4 & 0xf;
 return true;
}

template<int size>
bool
Target_s390<size>::ss_match_ahi(unsigned char* view,
                               section_size_type view_size,
                               section_offset_type *offset,
                               int guard_reg,
                               uint32_t *arg) const
{
 int op = size == 32 ? 0xa : 0xb;
 // a[g]hi %guard_reg, <arg>
 if (convert_to_section_size_type(*offset + 4) > view_size
     || view[*offset] != 0xa7
     || view[*offset + 1] != (guard_reg << 4 | op)
     // Disallow negative size.
     || view[*offset + 2] & 0x80)
   return false;
 *arg = elfcpp::Swap<16, true>::readval(view + *offset + 2);
 *offset += 4;
 return true;
}

template<int size>
bool
Target_s390<size>::ss_match_alfi(unsigned char* view,
                                section_size_type view_size,
                                section_offset_type *offset,
                                int guard_reg,
                                uint32_t *arg) const
{
 int op = size == 32 ? 0xb : 0xa;
 // al[g]fi %guard_reg, <arg>
 if (convert_to_section_size_type(*offset + 6) > view_size
     || view[*offset] != 0xc2
     || view[*offset + 1] != (guard_reg << 4 | op))
   return false;
 *arg = elfcpp::Swap<32, true>::readval(view + *offset + 2);
 *offset += 6;
 return true;
}

template<>
bool
Target_s390<32>::ss_match_cr(unsigned char* view,
                            section_size_type view_size,
                            section_offset_type *offset,
                            int guard_reg) const
{
 // cr %r15, %guard_reg
 if (convert_to_section_size_type(*offset + 2) > view_size
     || view[*offset] != 0x19
     || view[*offset + 1] != (0xf0 | guard_reg))
   return false;
 *offset += 2;
 return true;
}

template<>
bool
Target_s390<64>::ss_match_cr(unsigned char* view,
                            section_size_type view_size,
                            section_offset_type *offset,
                            int guard_reg) const
{
 // cgr %r15, %guard_reg
 if (convert_to_section_size_type(*offset + 4) > view_size
     || view[*offset] != 0xb9
     || view[*offset + 1] != 0x20
     || view[*offset + 2] != 0x00
     || view[*offset + 3] != (0xf0 | guard_reg))
   return false;
 *offset += 4;
 return true;
}


// FNOFFSET in section SHNDX in OBJECT is the start of a function
// compiled with -fsplit-stack.  The function calls non-split-stack
// code.  We have to change the function so that it always ensures
// that it has enough stack space to run some random function.

template<int size>
void
Target_s390<size>::do_calls_non_split(Relobj* object, unsigned int shndx,
                                     section_offset_type fnoffset,
                                     section_size_type,
                                     const unsigned char *prelocs,
                                     size_t reloc_count,
                                     unsigned char* view,
                                     section_size_type view_size,
                                     std::string*,
                                     std::string*) const
{
 // true if there's a conditional call to __morestack in the function,
 // false if there's an unconditional one.
 bool conditional = false;
 // Offset of the byte after the compare insn, if conditional.
 section_offset_type cmpend = 0;
 // Type and immediate offset of the add instruction that adds frame size
 // to guard.
 enum {
   SS_ADD_NONE,
   SS_ADD_AHI,
   SS_ADD_ALFI,
 } fsadd_type = SS_ADD_NONE;
 section_offset_type fsadd_offset = 0;
 uint32_t fsadd_frame_size = 0;
 // Register used for loading guard.  Usually r1, but can also be r0 or r2-r5.
 int guard_reg;
 // Offset of the conditional jump.
 section_offset_type jump_offset = 0;
 // Section view and offset of param block.
 section_offset_type param_offset = 0;
 unsigned char *param_view = 0;
 section_size_type param_view_size = 0;
 // Current position in function.
 section_offset_type curoffset = fnoffset;
 // And the position of split-stack prologue.
 section_offset_type ssoffset;
 // Frame size.
 typename elfcpp::Elf_types<size>::Elf_Addr frame_size;
 // Relocation parsing.
 typedef typename Reloc_types<elfcpp::SHT_RELA, size, true>::Reloc Reltype;
 const int reloc_size = Reloc_types<elfcpp::SHT_RELA, size, true>::reloc_size;
 const unsigned char *pr = prelocs;

 // If the function was compiled with -pg, the profiling code may come before
 // the split-stack prologue.  Skip it.

 this->ss_match_mcount(view, view_size, &curoffset);
 ssoffset = curoffset;

 // First, figure out if there's a conditional call by looking for the
 // extract-tp, add, cmp sequence.

 if (this->ss_match_ear(view, view_size, &curoffset))
   {
     // Found extract-tp, now look for an add and compare.
     conditional = true;
     if (this->ss_match_c(view, view_size, &curoffset))
       {
         // Found a direct compare of stack pointer with the guard,
         // we're done here.
       }
     else if (this->ss_match_l(view, view_size, &curoffset, &guard_reg))
       {
         // Found a load of guard to register, look for an add and compare.
         if (this->ss_match_ahi(view, view_size, &curoffset, guard_reg,
                                &fsadd_frame_size))
           {
             fsadd_type = SS_ADD_AHI;
             fsadd_offset = curoffset - 2;
           }
         else if (this->ss_match_alfi(view, view_size, &curoffset, guard_reg,
                                      &fsadd_frame_size))
           {
             fsadd_type = SS_ADD_ALFI;
             fsadd_offset = curoffset - 4;
           }
         else
           {
             goto bad;
           }
         // Now, there has to be a compare.
         if (!this->ss_match_cr(view, view_size, &curoffset, guard_reg))
           goto bad;
       }
     else
       {
         goto bad;
       }
     cmpend = curoffset;
   }

 // Second, look for the call.
 if (!this->match_view_u(view, view_size, curoffset, ss_code_larl,
                         sizeof ss_code_larl))
   goto bad;
 curoffset += sizeof ss_code_larl;

 // Find out larl's operand.  It should be a local symbol in .rodata
 // section.
 for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
   {
     Reltype reloc(pr);
     if (static_cast<section_offset_type>(reloc.get_r_offset())
         == curoffset)
       {
         typename elfcpp::Elf_types<size>::Elf_WXword r_info
           = reloc.get_r_info();
         unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
         unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
         if (r_type != elfcpp::R_390_PC32DBL)
           goto bad;
         if (r_sym >= object->local_symbol_count())
           goto bad;
         Sized_relobj_file<size, true> *object_sized =
           static_cast<Sized_relobj_file<size, true> *>(object);
         const Symbol_value<size>* sym = object_sized->local_symbol(r_sym);
         bool param_shndx_ordinary;
         const unsigned int param_shndx =
           sym->input_shndx(&param_shndx_ordinary);
         if (!param_shndx_ordinary)
           goto bad;
         param_offset = sym->input_value() + reloc.get_r_addend() - 2
                        - object->output_section(param_shndx)->address()
                        - object->output_section_offset(param_shndx);
         param_view = object->get_output_view(param_shndx,
                                                 &param_view_size);
         break;
       }
   }

 if (!param_view)
   goto bad;

 curoffset += 4;

 // Now, there has to be a jump to __morestack.
 jump_offset = curoffset;

 if (this->match_view_u(view, view_size, curoffset,
                      conditional ? ss_code_jgl : ss_code_jg,
                      sizeof ss_code_jg))
   curoffset += sizeof ss_code_jg;
 else
   goto bad;

 curoffset += 4;

 // Read the frame size.
 if (convert_to_section_size_type(param_offset + size / 8) > param_view_size)
   goto bad;
 frame_size = elfcpp::Swap<size, true>::readval(param_view + param_offset);

 // Sanity check.
 if (fsadd_type != SS_ADD_NONE && fsadd_frame_size != frame_size)
   goto bad;

 // Bump the frame size.
 frame_size += parameters->options().split_stack_adjust_size();

 // Store it to the param block.
 elfcpp::Swap<size, true>::writeval(param_view + param_offset, frame_size);

 if (!conditional)
   {
     // If the call was already unconditional, we're done.
   }
 else if (frame_size <= 0xffffffff && fsadd_type == SS_ADD_ALFI)
   {
     // Using alfi to add the frame size, and it still fits.  Adjust it.
     elfcpp::Swap_unaligned<32, true>::writeval(view + fsadd_offset,
                                                frame_size);
   }
 else
   {
     // We were either relying on the backoff area, or used ahi to load
     // frame size.  This won't fly, as our new frame size is too large.
     // Convert the sequence to unconditional by nopping out the comparison,
     // and rewiring the jump.
     this->set_view_to_nop(view, view_size, ssoffset, cmpend - ssoffset);

     // The jump is jgl, we'll mutate it to jg.
     view[jump_offset+1] = 0xf4;
   }

 return;

bad:
 if (!object->has_no_split_stack())
     object->error(_("failed to match split-stack sequence at "
                     "section %u offset %0zx"),
                   shndx, static_cast<size_t>(fnoffset));
}

// Relocate section data.

template<int size>
void
Target_s390<size>::relocate_section(
   const Relocate_info<size, true>* 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 gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
     Classify_reloc;

 gold_assert(sh_type == elfcpp::SHT_RELA);

 gold::relocate_section<size, true, Target_s390<size>, 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>
void
Target_s390<size>::apply_relocation(
   const Relocate_info<size, true>* 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, true, Target_s390<size>,
                        typename Target_s390<size>::Relocate>(
   relinfo,
   this,
   r_offset,
   r_type,
   r_addend,
   gsym,
   view,
   address,
   view_size);
}

// The selector for s390 object files.

template<int size>
class Target_selector_s390 : public Target_selector
{
public:
 Target_selector_s390()
   : Target_selector(elfcpp::EM_S390, size, true,
                     (size == 64 ? "elf64-s390" : "elf32-s390"),
                     (size == 64 ? "elf64_s390" : "elf32_s390"))
 { }

 virtual Target*
 do_instantiate_target()
 { return new Target_s390<size>(); }
};

Target_selector_s390<32> target_selector_s390;
Target_selector_s390<64> target_selector_s390x;

} // End anonymous namespace.