gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gold / sparc.cc
index aa8bbbd912e2d765cdf8402a7c2ac7a22ca6b67e..e73970afd779c3af6336947a739d7de71ac068b7 100644 (file)
@@ -1,6 +1,6 @@
 // sparc.cc -- sparc target support for gold.
 
-// Copyright 2008 Free Software Foundation, Inc.
+// Copyright (C) 2008-2020 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>.
 
 // This file is part of gold.
@@ -40,6 +40,7 @@
 #include "target-select.h"
 #include "tls.h"
 #include "errors.h"
+#include "gc.h"
 
 namespace
 {
@@ -57,18 +58,38 @@ class Target_sparc : public Sized_target<size, big_endian>
 
   Target_sparc()
     : Sized_target<size, big_endian>(&sparc_info),
-      got_(NULL), plt_(NULL), rela_dyn_(NULL),
-      copy_relocs_(elfcpp::R_SPARC_COPY), dynbss_(NULL),
-      got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL)
+      got_(NULL), plt_(NULL), rela_dyn_(NULL), rela_ifunc_(NULL),
+      copy_relocs_(elfcpp::R_SPARC_COPY),
+      got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL),
+      elf_machine_(sparc_info.machine_code), elf_flags_(0),
+      elf_flags_set_(false), register_syms_()
   {
   }
 
+  // Make a new symbol table entry.
+  Sized_symbol<size>*
+  make_symbol(const char*, elfcpp::STT, Object*, unsigned int, uint64_t);
+
+  // Process the relocations to determine unreferenced sections for
+  // garbage collection.
+  void
+  gc_process_relocs(Symbol_table* symtab,
+                   Layout* layout,
+                   Sized_relobj_file<size, big_endian>* object,
+                   unsigned int data_shndx,
+                   unsigned int sh_type,
+                   const unsigned char* prelocs,
+                   size_t reloc_count,
+                   Output_section* output_section,
+                   bool needs_special_offset_handling,
+                   size_t local_symbol_count,
+                   const unsigned char* plocal_symbols);
+
   // Scan the relocations to look for symbol adjustments.
   void
-  scan_relocs(const General_options& options,
-             Symbol_table* symtab,
+  scan_relocs(Symbol_table* symtab,
              Layout* layout,
-             Sized_relobj<size, big_endian>* object,
+             Sized_relobj_file<size, big_endian>* object,
              unsigned int data_shndx,
              unsigned int sh_type,
              const unsigned char* prelocs,
@@ -79,7 +100,7 @@ class Target_sparc : public Sized_target<size, big_endian>
              const unsigned char* plocal_symbols);
   // Finalize the sections.
   void
-  do_finalize_sections(Layout*);
+  do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);
 
   // Return the value to use for a dynamic which requires special
   // treatment.
@@ -96,14 +117,14 @@ class Target_sparc : public Sized_target<size, big_endian>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-                  section_size_type view_size);
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
-  scan_relocatable_relocs(const General_options& options,
-                         Symbol_table* symtab,
+  scan_relocatable_relocs(Symbol_table* symtab,
                          Layout* layout,
-                         Sized_relobj<size, big_endian>* object,
+                         Sized_relobj_file<size, big_endian>* object,
                          unsigned int data_shndx,
                          unsigned int sh_type,
                          const unsigned char* prelocs,
@@ -114,39 +135,102 @@ class Target_sparc : public Sized_target<size, big_endian>
                          const unsigned char* plocal_symbols,
                          Relocatable_relocs*);
 
-  // Relocate a section during a relocatable link.
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+                  Layout* layout,
+                  Sized_relobj_file<size, big_endian>* object,
+                  unsigned int data_shndx,
+                  unsigned int sh_type,
+                  const unsigned char* prelocs,
+                  size_t reloc_count,
+                  Output_section* output_section,
+                  bool needs_special_offset_handling,
+                  size_t local_symbol_count,
+                  const unsigned char* plocal_syms,
+                  Relocatable_relocs* rr);
+
+  // Emit relocations for a section.
   void
-  relocate_for_relocatable(const Relocate_info<size, big_endian>*,
-                          unsigned int sh_type,
-                          const unsigned char* prelocs,
-                          size_t reloc_count,
-                          Output_section* output_section,
-                          off_t offset_in_output_section,
-                          const Relocatable_relocs*,
-                          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);
+  relocate_relocs(const Relocate_info<size, big_endian>*,
+                 unsigned int sh_type,
+                 const unsigned char* prelocs,
+                 size_t reloc_count,
+                 Output_section* output_section,
+                 typename elfcpp::Elf_types<size>::Elf_Off
+                    offset_in_output_section,
+                 unsigned char* view,
+                 typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+                 section_size_type view_size,
+                 unsigned char* reloc_view,
+                 section_size_type reloc_view_size);
+
   // Return whether SYM is defined by the ABI.
   bool
-  do_is_defined_by_abi(Symbol* sym) const
-  {
-    // XXX Really need to support this better...
-    if (sym->type() == elfcpp::STT_SPARC_REGISTER)
-      return 1;
+  do_is_defined_by_abi(const Symbol* sym) const
+  { return strcmp(sym->name(), "___tls_get_addr") == 0; }
 
-    return strcmp(sym->name(), "___tls_get_addr") == 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 whether there is a GOT section.
+  bool
+  has_got_section() const
+  { return this->got_ != NULL; }
 
   // Return the size of the GOT section.
   section_size_type
-  got_size()
+  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 address of the GOT.
+  uint64_t
+  got_address() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_->address();
+  }
+
+  // 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;
+
+ protected:
+  // Make an ELF object.
+  Object*
+  do_make_elf_object(const std::string&, Input_file*, off_t,
+                    const elfcpp::Ehdr<size, big_endian>& ehdr);
+
+  void
+  do_adjust_elf_header(unsigned char* view, int len);
+
  private:
 
   // The class which scans relocations.
@@ -157,31 +241,56 @@ class Target_sparc : public Sized_target<size, big_endian>
       : issued_non_pic_error_(false)
     { }
 
+    static inline int
+    get_reference_flags(unsigned int r_type);
+
     inline void
-    local(const General_options& options, Symbol_table* symtab,
-         Layout* layout, Target_sparc* target,
-         Sized_relobj<size, big_endian>* object,
+    local(Symbol_table* symtab, Layout* layout, Target_sparc* target,
+         Sized_relobj_file<size, big_endian>* object,
          unsigned int data_shndx,
          Output_section* output_section,
          const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
-         const elfcpp::Sym<size, big_endian>& lsym);
+         const elfcpp::Sym<size, big_endian>& lsym,
+         bool is_discarded);
 
     inline void
-    global(const General_options& options, Symbol_table* symtab,
-          Layout* layout, Target_sparc* target,
-          Sized_relobj<size, big_endian>* object,
+    global(Symbol_table* symtab, Layout* layout, Target_sparc* target,
+          Sized_relobj_file<size, big_endian>* object,
           unsigned int data_shndx,
           Output_section* output_section,
           const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
           Symbol* gsym);
 
+    inline bool
+    local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                       Target_sparc* ,
+                                       Sized_relobj_file<size, big_endian>* ,
+                                       unsigned int ,
+                                       Output_section* ,
+                                       const elfcpp::Rela<size, big_endian>& ,
+                                       unsigned int ,
+                                       const elfcpp::Sym<size, big_endian>&)
+    { return false; }
+
+    inline bool
+    global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                        Target_sparc* ,
+                                        Sized_relobj_file<size, big_endian>* ,
+                                        unsigned int ,
+                                        Output_section* ,
+                                        const elfcpp::Rela<size,
+                                                           big_endian>& ,
+                                        unsigned int , Symbol*)
+    { return false; }
+
+
   private:
     static void
-    unsupported_reloc_local(Sized_relobj<size, big_endian>*,
+    unsupported_reloc_local(Sized_relobj_file<size, big_endian>*,
                            unsigned int r_type);
 
     static void
-    unsupported_reloc_global(Sized_relobj<size, big_endian>*,
+    unsupported_reloc_global(Sized_relobj_file<size, big_endian>*,
                             unsigned int r_type, Symbol*);
 
     static void
@@ -191,6 +300,10 @@ class Target_sparc : public Sized_target<size, big_endian>
     void
     check_non_pic(Relobj*, unsigned int r_type);
 
+    bool
+    reloc_needs_plt_for_ifunc(Sized_relobj_file<size, big_endian>*,
+                             unsigned int r_type);
+
     // Whether we have issued an error about a non-PIC compilation.
     bool issued_non_pic_error_;
   };
@@ -200,7 +313,7 @@ class Target_sparc : public Sized_target<size, big_endian>
   {
    public:
     Relocate()
-      : ignore_gd_add_(false)
+      : ignore_gd_add_(false), reloc_adjust_addr_(NULL)
     { }
 
     ~Relocate()
@@ -215,50 +328,58 @@ class Target_sparc : public Sized_target<size, big_endian>
     // Do a relocation.  Return false if the caller should not issue
     // any warnings about this relocation.
     inline bool
-    relocate(const Relocate_info<size, big_endian>*, Target_sparc*,
-            size_t relnum, const elfcpp::Rela<size, big_endian>&,
-            unsigned int r_type, const Sized_symbol<size>*,
-            const Symbol_value<size>*,
-            unsigned char*,
-            typename elfcpp::Elf_types<size>::Elf_Addr,
+    relocate(const Relocate_info<size, big_endian>*, unsigned int,
+            Target_sparc*, 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 void
     relocate_tls(const Relocate_info<size, big_endian>*, Target_sparc* target,
-                 size_t relnum, const elfcpp::Rela<size, big_endian>&,
+                size_t relnum, const elfcpp::Rela<size, big_endian>&,
                 unsigned int r_type, const Sized_symbol<size>*,
                 const Symbol_value<size>*,
                 unsigned char*,
                 typename elfcpp::Elf_types<size>::Elf_Addr,
                 section_size_type);
 
+    inline void
+    relax_call(Target_sparc<size, big_endian>* target,
+              unsigned char* view,
+              const elfcpp::Rela<size, big_endian>& rela,
+              section_size_type view_size);
+
     // Ignore the next relocation which should be R_SPARC_TLS_GD_ADD
     bool ignore_gd_add_;
-  };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
-  {
-   public:
-    unsigned int
-    get_size_for_reloc(unsigned int, Relobj*);
+    // If we hit a reloc at this view address, adjust it back by 4 bytes.
+    unsigned char *reloc_adjust_addr_;
   };
 
   // Get the GOT section, creating it if necessary.
   Output_data_got<size, big_endian>*
   got_section(Symbol_table*, Layout*);
 
+  // Create the PLT section.
+  void
+  make_plt_section(Symbol_table* symtab, Layout* layout);
+
   // Create a PLT entry for a global symbol.
   void
   make_plt_entry(Symbol_table*, Layout*, Symbol*);
 
+  // Create a PLT entry for a local STT_GNU_IFUNC symbol.
+  void
+  make_local_ifunc_plt_entry(Symbol_table*, Layout*,
+                            Sized_relobj_file<size, big_endian>* relobj,
+                            unsigned int local_sym_index);
+
   // Create a GOT entry for the TLS module index.
   unsigned int
   got_mod_index_entry(Symbol_table* symtab, Layout* layout,
-                     Sized_relobj<size, big_endian>* object);
+                     Sized_relobj_file<size, big_endian>* object);
 
   // Return the gsym for "__tls_get_addr".  Cache if not already
   // cached.
@@ -272,7 +393,7 @@ class Target_sparc : public Sized_target<size, big_endian>
   }
 
   // Get the PLT section.
-  const Output_data_plt_sparc<size, big_endian>*
+  Output_data_plt_sparc<size, big_endian>*
   plt_section() const
   {
     gold_assert(this->plt_ != NULL);
@@ -283,27 +404,24 @@ class Target_sparc : public Sized_target<size, big_endian>
   Reloc_section*
   rela_dyn_section(Layout*);
 
-  // Return true if the symbol may need a COPY relocation.
-  // References from an executable object to non-function symbols
-  // defined in a dynamic object may need a COPY relocation.
-  bool
-  may_need_copy_reloc(Symbol* gsym)
-  {
-    return (!parameters->options().shared()
-            && gsym->is_from_dynobj()
-            && gsym->type() != elfcpp::STT_FUNC);
-  }
+  // Get the section to use for IFUNC relocations.
+  Reloc_section*
+  rela_ifunc_section(Layout*);
 
   // Copy a relocation against a global symbol.
   void
-  copy_reloc(Symbol_table* symtab, Layout* layout, Relobj* object,
+  copy_reloc(Symbol_table* symtab, Layout* layout,
+            Sized_relobj_file<size, big_endian>* object,
             unsigned int shndx, Output_section* output_section,
             Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
   {
+    unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
     this->copy_relocs_.copy_reloc(symtab, layout,
                                  symtab->get_sized_symbol<size>(sym),
                                  object, shndx, output_section,
-                                 reloc, this->rela_dyn_section(layout));
+                                 r_type, reloc.get_r_offset(),
+                                 reloc.get_r_addend(),
+                                 this->rela_dyn_section(layout));
   }
 
   // Information about this specific target which we pass to the
@@ -311,6 +429,9 @@ class Target_sparc : public Sized_target<size, big_endian>
   static Target::Target_info sparc_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
@@ -318,20 +439,38 @@ class Target_sparc : public Sized_target<size, big_endian>
     GOT_TYPE_TLS_PAIR = 2,      // GOT entry for TLS module/offset pair
   };
 
+  struct Register_symbol
+  {
+    Register_symbol()
+      : name(NULL), shndx(0), obj(NULL)
+    { }
+    const char* name;
+    unsigned int shndx;
+    Object* obj;
+  };
+
   // The GOT section.
   Output_data_got<size, big_endian>* got_;
   // The PLT section.
   Output_data_plt_sparc<size, big_endian>* plt_;
   // The dynamic reloc section.
   Reloc_section* rela_dyn_;
+  // The section to use for IFUNC relocs.
+  Reloc_section* rela_ifunc_;
   // Relocs saved to avoid a COPY reloc.
   Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
-  // Space for variables copied with a COPY reloc.
-  Output_data_space* dynbss_;
   // Offset of the GOT entry for the TLS module index;
   unsigned int got_mod_index_offset_;
   // Cached pointer to __tls_get_addr symbol
   Symbol* tls_get_addr_sym_;
+  // Accumulated elf machine type
+  elfcpp::Elf_Half elf_machine_;
+  // Accumulated elf header flags
+  elfcpp::Elf_Word elf_flags_;
+  // Whether elf_flags_ has been set for the first time yet
+  bool elf_flags_set_;
+  // STT_SPARC_REGISTER symbols (%g2, %g3, %g6, %g7).
+  Register_symbol register_syms_[4];
 };
 
 template<>
@@ -344,11 +483,23 @@ Target::Target_info Target_sparc<32, true>::sparc_info =
   false,               // has_resolve
   false,               // has_code_fill
   true,                        // is_default_stack_executable
+  false,               // can_icf_inline_merge_sections
   '\0',                        // wrap_char
   "/usr/lib/ld.so.1",  // dynamic_linker
   0x00010000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
-  8 * 1024             // common_pagesize (overridable by -z common-page-size)
+  8 * 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<>
@@ -357,15 +508,27 @@ Target::Target_info Target_sparc<64, true>::sparc_info =
   64,                  // size
   true,                        // is_big_endian
   elfcpp::EM_SPARCV9,  // machine_code
-  false,               // has_make_symbol
+  true,                        // has_make_symbol
   false,               // has_resolve
   false,               // has_code_fill
   true,                        // is_default_stack_executable
+  false,               // can_icf_inline_merge_sections
   '\0',                        // wrap_char
   "/usr/lib/sparcv9/ld.so.1",  // dynamic_linker
   0x100000,            // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
-  8 * 1024             // common_pagesize (overridable by -z common-page-size)
+  8 * 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
 };
 
 // We have to take care here, even when operating in little-endian
@@ -401,7 +564,7 @@ private:
   rela(unsigned char* view,
        unsigned int right_shift,
        typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Swap<valsize, big_endian>::Valtype addend)
   {
@@ -422,7 +585,7 @@ private:
   static inline void
   rela_ua(unsigned char* view,
          unsigned int right_shift, elfcpp::Elf_Xword dst_mask,
-         const Sized_relobj<size, big_endian>* object,
+         const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Swap<size, big_endian>::Valtype addend)
   {
@@ -445,7 +608,7 @@ private:
   pcrela(unsigned char* view,
         unsigned int right_shift,
         typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
-        const Sized_relobj<size, big_endian>* object,
+        const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         typename elfcpp::Swap<size, big_endian>::Valtype addend,
         typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -465,7 +628,7 @@ private:
   template<int valsize>
   static inline void
   pcrela_unaligned(unsigned char* view,
-                  const Sized_relobj<size, big_endian>* object,
+                  const Sized_relobj_file<size, big_endian>* object,
                   const Symbol_value<size>* psymval,
                   typename elfcpp::Swap<size, big_endian>::Valtype addend,
                   typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -485,7 +648,7 @@ public:
   // R_SPARC_WDISP30: (Symbol + Addend - Address) >> 2
   static inline void
   wdisp30(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          const Sized_relobj_file<size, big_endian>* object,
           const Symbol_value<size>* psymval,
           typename elfcpp::Elf_types<size>::Elf_Addr addend,
           typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -497,7 +660,7 @@ public:
   // R_SPARC_WDISP22: (Symbol + Addend - Address) >> 2
   static inline void
   wdisp22(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          const Sized_relobj_file<size, big_endian>* object,
           const Symbol_value<size>* psymval,
           typename elfcpp::Elf_types<size>::Elf_Addr addend,
           typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -509,7 +672,7 @@ public:
   // R_SPARC_WDISP19: (Symbol + Addend - Address) >> 2
   static inline void
   wdisp19(unsigned char* view,
-         const Sized_relobj<size, big_endian>* object,
+         const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
          typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -521,7 +684,7 @@ public:
   // R_SPARC_WDISP16: (Symbol + Addend - Address) >> 2
   static inline void
   wdisp16(unsigned char* view,
-         const Sized_relobj<size, big_endian>* object,
+         const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
          typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -541,10 +704,33 @@ public:
     elfcpp::Swap<32, true>::writeval(wv, val | reloc);
   }
 
+  // R_SPARC_WDISP10: (Symbol + Addend - Address) >> 2
+  static inline void
+  wdisp10(unsigned char* view,
+         const Sized_relobj_file<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Elf_types<size>::Elf_Addr addend,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = ((psymval->value(object, addend) - address)
+                    >> 2);
+
+    // The relocation value is split between the low bits 5-12,
+    // and high bits 19-20.
+    val &= ~((0x3 << 19) | (0xff << 5));
+    reloc = (((reloc & 0x300) << (19 - 8))
+            | ((reloc & 0xff) << (5 - 0)));
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
   // R_SPARC_PC22: (Symbol + Addend - Address) >> 10
   static inline void
   pc22(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend,
        typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -556,7 +742,7 @@ public:
   // R_SPARC_PC10: (Symbol + Addend - Address) & 0x3ff
   static inline void
   pc10(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend,
        typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -577,7 +763,7 @@ public:
   // R_SPARC_HI22: (Symbol + Addend) >> 10
   static inline void
   hi22(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -587,7 +773,7 @@ public:
   // R_SPARC_PCPLT22: (Symbol + Addend - Address) >> 10
   static inline void
   pcplt22(unsigned char* view,
-         const Sized_relobj<size, big_endian>* object,
+         const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
          typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -608,7 +794,7 @@ public:
   // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
   static inline void
   lo10(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -618,7 +804,7 @@ public:
   // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
   static inline void
   lo10(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend,
        typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -630,7 +816,7 @@ public:
   // R_SPARC_OLO10: ((Symbol + Addend) & 0x3ff) + Addend2
   static inline void
   olo10(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend,
        typename elfcpp::Elf_types<size>::Elf_Addr addend2)
@@ -651,7 +837,7 @@ public:
   // R_SPARC_22: (Symbol + Addend)
   static inline void
   rela32_22(unsigned char* view,
-           const Sized_relobj<size, big_endian>* object,
+           const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -670,7 +856,7 @@ public:
   // R_SPARC_13: (Symbol + Addend)
   static inline void
   rela32_13(unsigned char* view,
-           const Sized_relobj<size, big_endian>* object,
+           const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -680,7 +866,7 @@ public:
   // R_SPARC_UA16: (Symbol + Addend)
   static inline void
   ua16(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -690,7 +876,7 @@ public:
   // R_SPARC_UA32: (Symbol + Addend)
   static inline void
   ua32(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -700,7 +886,7 @@ public:
   // R_SPARC_UA64: (Symbol + Addend)
   static inline void
   ua64(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -711,7 +897,7 @@ public:
   // R_SPARC_DISP8: (Symbol + Addend - Address)
   static inline void
   disp8(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend,
        typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -723,7 +909,7 @@ public:
   // R_SPARC_DISP16: (Symbol + Addend - Address)
   static inline void
   disp16(unsigned char* view,
-        const Sized_relobj<size, big_endian>* object,
+        const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         typename elfcpp::Elf_types<size>::Elf_Addr addend,
         typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -735,7 +921,7 @@ public:
   // R_SPARC_DISP32: (Symbol + Addend - Address)
   static inline void
   disp32(unsigned char* view,
-        const Sized_relobj<size, big_endian>* object,
+        const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         typename elfcpp::Elf_types<size>::Elf_Addr addend,
         typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -747,7 +933,7 @@ public:
   // R_SPARC_DISP64: (Symbol + Addend - Address)
   static inline void
   disp64(unsigned char* view,
-        const Sized_relobj<size, big_endian>* object,
+        const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         elfcpp::Elf_Xword addend,
         typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -756,10 +942,20 @@ public:
                                        addend, address);
   }
 
+  // R_SPARC_H34: (Symbol + Addend) >> 12
+  static inline void
+  h34(unsigned char* view,
+      const Sized_relobj_file<size, big_endian>* object,
+      const Symbol_value<size>* psymval,
+      typename elfcpp::Elf_types<size>::Elf_Addr  addend)
+  {
+    This_insn::template rela<32>(view, 12, 0x003fffff, object, psymval, addend);
+  }
+
   // R_SPARC_H44: (Symbol + Addend) >> 22
   static inline void
   h44(unsigned char* view,
-      const Sized_relobj<size, big_endian>* object,
+      const Sized_relobj_file<size, big_endian>* object,
       const Symbol_value<size>* psymval,
       typename elfcpp::Elf_types<size>::Elf_Addr  addend)
   {
@@ -769,7 +965,7 @@ public:
   // R_SPARC_M44: ((Symbol + Addend) >> 12) & 0x3ff
   static inline void
   m44(unsigned char* view,
-      const Sized_relobj<size, big_endian>* object,
+      const Sized_relobj_file<size, big_endian>* object,
       const Symbol_value<size>* psymval,
       typename elfcpp::Elf_types<size>::Elf_Addr  addend)
   {
@@ -779,7 +975,7 @@ public:
   // R_SPARC_L44: (Symbol + Addend) & 0xfff
   static inline void
   l44(unsigned char* view,
-      const Sized_relobj<size, big_endian>* object,
+      const Sized_relobj_file<size, big_endian>* object,
       const Symbol_value<size>* psymval,
       typename elfcpp::Elf_types<size>::Elf_Addr  addend)
   {
@@ -789,7 +985,7 @@ public:
   // R_SPARC_HH22: (Symbol + Addend) >> 42
   static inline void
   hh22(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -799,7 +995,7 @@ public:
   // R_SPARC_PC_HH22: (Symbol + Addend - Address) >> 42
   static inline void
   pc_hh22(unsigned char* view,
-         const Sized_relobj<size, big_endian>* object,
+         const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
          typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -811,7 +1007,7 @@ public:
   // R_SPARC_HM10: ((Symbol + Addend) >> 32) & 0x3ff
   static inline void
   hm10(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -821,7 +1017,7 @@ public:
   // R_SPARC_PC_HM10: ((Symbol + Addend - Address) >> 32) & 0x3ff
   static inline void
   pc_hm10(unsigned char* view,
-         const Sized_relobj<size, big_endian>* object,
+         const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Elf_types<size>::Elf_Addr addend,
          typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -833,7 +1029,7 @@ public:
   // R_SPARC_11: (Symbol + Addend)
   static inline void
   rela32_11(unsigned char* view,
-           const Sized_relobj<size, big_endian>* object,
+           const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -843,7 +1039,7 @@ public:
   // R_SPARC_10: (Symbol + Addend)
   static inline void
   rela32_10(unsigned char* view,
-           const Sized_relobj<size, big_endian>* object,
+           const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -853,7 +1049,7 @@ public:
   // R_SPARC_7: (Symbol + Addend)
   static inline void
   rela32_7(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          const Sized_relobj_file<size, big_endian>* object,
           const Symbol_value<size>* psymval,
           typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -863,7 +1059,7 @@ public:
   // R_SPARC_6: (Symbol + Addend)
   static inline void
   rela32_6(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          const Sized_relobj_file<size, big_endian>* object,
           const Symbol_value<size>* psymval,
           typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -873,7 +1069,7 @@ public:
   // R_SPARC_5: (Symbol + Addend)
   static inline void
   rela32_5(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          const Sized_relobj_file<size, big_endian>* object,
           const Symbol_value<size>* psymval,
           typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -927,10 +1123,31 @@ public:
     elfcpp::Swap<32, true>::writeval(wv, val | reloc);
   }
 
+  // R_SPARC_GOTDATA_OP_HIX22: @gdopoff(Symbol + Addend) >> 10
+  static inline void
+  gdop_hix22(unsigned char* view,
+            typename elfcpp::Elf_types<size>::Elf_Addr value)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    int32_t reloc = static_cast<int32_t>(value);
+
+    val &= ~0x3fffff;
+
+    if (reloc < 0)
+      reloc ^= ~static_cast<int32_t>(0);
+    reloc >>= 10;
+
+    reloc &= 0x3fffff;
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
   // R_SPARC_HIX22: ((Symbol + Addend) ^ 0xffffffffffffffff) >> 10
   static inline void
   hix22(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -968,10 +1185,29 @@ public:
     elfcpp::Swap<32, true>::writeval(wv, val | reloc);
   }
 
+  // R_SPARC_GOTDATA_OP_LOX10: (@gdopoff(Symbol + Addend) & 0x3ff) | 0x1c00
+  static inline void
+  gdop_lox10(unsigned char* view,
+            typename elfcpp::Elf_types<size>::Elf_Addr value)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    int32_t reloc = static_cast<int32_t>(value);
+
+    if (reloc < 0)
+      reloc = (reloc & 0x3ff) | 0x1c00;
+    else
+      reloc = (reloc & 0x3ff);
+
+    val &= ~0x1fff;
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
   // R_SPARC_LOX10: ((Symbol + Addend) & 0x3ff) | 0x1c00
   static inline void
   lox10(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -1001,15 +1237,14 @@ Target_sparc<size, big_endian>::got_section(Symbol_table* symtab,
 
       this->got_ = new Output_data_got<size, big_endian>();
 
-      Output_section* os;
-      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-                                          (elfcpp::SHF_ALLOC
-                                           | elfcpp::SHF_WRITE),
-                                          this->got_);
-      os->set_is_relro();
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_WRITE),
+                                     this->got_, ORDER_RELRO, true);
 
       // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
       symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+                                   Symbol_table::PREDEFINED,
                                    this->got_,
                                    0, 0, elfcpp::STT_OBJECT,
                                    elfcpp::STB_LOCAL,
@@ -1031,11 +1266,36 @@ Target_sparc<size, big_endian>::rela_dyn_section(Layout* layout)
       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_);
+                                     elfcpp::SHF_ALLOC, this->rela_dyn_,
+                                     ORDER_DYNAMIC_RELOCS, false);
     }
   return this->rela_dyn_;
 }
 
+// Get the section to use for IFUNC relocs, creating it if
+// necessary.  These go in .rela.dyn, but only after all other dynamic
+// relocations.  They need to follow the other dynamic relocations so
+// that they can refer to global variables initialized by those
+// relocs.
+
+template<int size, bool big_endian>
+typename Target_sparc<size, big_endian>::Reloc_section*
+Target_sparc<size, big_endian>::rela_ifunc_section(Layout* layout)
+{
+  if (this->rela_ifunc_ == NULL)
+    {
+      // Make sure we have already created the dynamic reloc section.
+      this->rela_dyn_section(layout);
+      this->rela_ifunc_ = new Reloc_section(false);
+      layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+                                     elfcpp::SHF_ALLOC, this->rela_ifunc_,
+                                     ORDER_DYNAMIC_RELOCS, false);
+      gold_assert(this->rela_dyn_->output_section()
+                 == this->rela_ifunc_->output_section());
+    }
+  return this->rela_ifunc_;
+}
+
 // A class to handle the PLT data.
 
 template<int size, bool big_endian>
@@ -1048,7 +1308,13 @@ class Output_data_plt_sparc : public Output_section_data
   Output_data_plt_sparc(Layout*);
 
   // Add an entry to the PLT.
-  void add_entry(Symbol* gsym);
+  void add_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym);
+
+  // Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
+  unsigned int
+  add_local_ifunc_entry(Symbol_table*, Layout*,
+                       Sized_relobj_file<size, big_endian>* relobj,
+                       unsigned int local_sym_index);
 
   // Return the .rela.plt section data.
   const Reloc_section* rel_plt() const
@@ -1056,6 +1322,41 @@ class Output_data_plt_sparc : public Output_section_data
     return this->rel_;
   }
 
+  // Return where the IFUNC relocations should go.
+  Reloc_section*
+  rela_ifunc(Symbol_table*, Layout*);
+
+  void
+  emit_pending_ifunc_relocs();
+
+  // Return whether we created a section for IFUNC relocations.
+  bool
+  has_ifunc_section() const
+  { return this->ifunc_rel_ != NULL; }
+
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_ + this->ifunc_count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return 4 * base_plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return base_plt_entry_size; }
+
+  // Return the PLT address to use for a global symbol.
+  uint64_t
+  address_for_global(const Symbol*);
+
+  // Return the PLT address to use for a local symbol.
+  uint64_t
+  address_for_local(const Relobj*, unsigned int symndx);
+
  protected:
   void do_adjust_output_section(Output_section* os);
 
@@ -1075,34 +1376,69 @@ class Output_data_plt_sparc : public Output_section_data
     (plt_entries_per_block
      * (plt_insn_chunk_size + plt_pointer_chunk_size));
 
-  // Set the final size.
-  void
-  set_final_data_size()
+  section_offset_type
+  plt_index_to_offset(unsigned int index)
   {
-    unsigned int full_count = this->count_ + 4;
-    unsigned int extra = (size == 32 ? 4 : 0);
+    section_offset_type offset;
 
-    if (size == 32 || full_count < 32768)
-      this->set_data_size((full_count * base_plt_entry_size) + extra);
+    if (size == 32 || index < 32768)
+      offset = index * base_plt_entry_size;
     else
       {
-       unsigned int ext_cnt = full_count - 32768;
+       unsigned int ext_index = index - 32768;
 
-       this->set_data_size((32768 * base_plt_entry_size)
-                           + (ext_cnt
-                              * (plt_insn_chunk_size
-                                 + plt_pointer_chunk_size)));
+       offset = (32768 * base_plt_entry_size)
+         + ((ext_index / plt_entries_per_block)
+            * plt_block_size)
+         + ((ext_index % plt_entries_per_block)
+            * plt_insn_chunk_size);
       }
+    return offset;
+  }
+
+  // Set the final size.
+  void
+  set_final_data_size()
+  {
+    unsigned int full_count = this->entry_count() + 4;
+    unsigned int extra = (size == 32 ? 4 : 0);
+    section_offset_type sz = plt_index_to_offset(full_count) + extra;
+
+    return this->set_data_size(sz);
   }
 
   // Write out the PLT data.
   void
   do_write(Output_file*);
 
+  struct Global_ifunc
+  {
+    Reloc_section* rel;
+    Symbol* gsym;
+    unsigned int plt_index;
+  };
+
+  struct Local_ifunc
+  {
+    Reloc_section* rel;
+    Sized_relobj_file<size, big_endian>* object;
+    unsigned int local_sym_index;
+    unsigned int plt_index;
+  };
+
   // The reloc section.
   Reloc_section* rel_;
+  // The IFUNC relocations, if necessary.  These must follow the
+  // regular relocations.
+  Reloc_section* ifunc_rel_;
   // The number of PLT entries.
   unsigned int count_;
+  // The number of PLT entries for IFUNC symbols.
+  unsigned int ifunc_count_;
+  // Global STT_GNU_IFUNC symbols.
+  std::vector<Global_ifunc> global_ifuncs_;
+  // Local STT_GNU_IFUNC symbols.
+  std::vector<Local_ifunc> local_ifuncs_;
 };
 
 // Define the constants as required by C++ standard.
@@ -1129,11 +1465,13 @@ const unsigned int Output_data_plt_sparc<size, big_endian>::plt_block_size;
 
 template<int size, bool big_endian>
 Output_data_plt_sparc<size, big_endian>::Output_data_plt_sparc(Layout* layout)
-  : Output_section_data(size == 32 ? 4 : 8), count_(0)
+  : Output_section_data(size == 32 ? 4 : 8), ifunc_rel_(NULL),
+    count_(0), ifunc_count_(0), global_ifuncs_(), local_ifuncs_()
 {
   this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
-                                 elfcpp::SHF_ALLOC, this->rel_);
+                                 elfcpp::SHF_ALLOC, this->rel_,
+                                 ORDER_DYNAMIC_PLT_RELOCS, false);
 }
 
 template<int size, bool big_endian>
@@ -1147,38 +1485,173 @@ Output_data_plt_sparc<size, big_endian>::do_adjust_output_section(Output_section
 
 template<int size, bool big_endian>
 void
-Output_data_plt_sparc<size, big_endian>::add_entry(Symbol* gsym)
+Output_data_plt_sparc<size, big_endian>::add_entry(Symbol_table* symtab,
+                                                  Layout* layout,
+                                                  Symbol* gsym)
 {
   gold_assert(!gsym->has_plt_offset());
 
-  unsigned int index = this->count_ + 4;
   section_offset_type plt_offset;
+  unsigned int index;
 
-  if (size == 32 || index < 32768)
-    plt_offset = index * base_plt_entry_size;
+  if (gsym->type() == elfcpp::STT_GNU_IFUNC
+      && gsym->can_use_relative_reloc(false))
+    {
+      index = this->ifunc_count_;
+      plt_offset = plt_index_to_offset(index);
+      gsym->set_plt_offset(plt_offset);
+      ++this->ifunc_count_;
+      Reloc_section* rel = this->rela_ifunc(symtab, layout);
+
+      struct Global_ifunc gi;
+      gi.rel = rel;
+      gi.gsym = gsym;
+      gi.plt_index = index;
+      this->global_ifuncs_.push_back(gi);
+    }
   else
     {
-       unsigned int ext_index = index - 32768;
+      plt_offset = plt_index_to_offset(this->count_ + 4);
+      gsym->set_plt_offset(plt_offset);
+      ++this->count_;
+      gsym->set_needs_dynsym_entry();
+      this->rel_->add_global(gsym, elfcpp::R_SPARC_JMP_SLOT, this,
+                            plt_offset, 0);
+    }
 
-       plt_offset = (32768 * base_plt_entry_size)
-         + ((ext_index / plt_entries_per_block)
-            * plt_block_size)
-         + ((ext_index % plt_entries_per_block)
-            * plt_insn_chunk_size);
+  // 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.
+}
+
+template<int size, bool big_endian>
+unsigned int
+Output_data_plt_sparc<size, big_endian>::add_local_ifunc_entry(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* relobj,
+    unsigned int local_sym_index)
+{
+  unsigned int index = this->ifunc_count_;
+  section_offset_type plt_offset;
+
+  plt_offset = plt_index_to_offset(index);
+  ++this->ifunc_count_;
+
+  Reloc_section* rel = this->rela_ifunc(symtab, layout);
+
+  struct Local_ifunc li;
+  li.rel = rel;
+  li.object = relobj;
+  li.local_sym_index = local_sym_index;
+  li.plt_index = index;
+  this->local_ifuncs_.push_back(li);
+
+  return plt_offset;
+}
+
+// Emit any pending IFUNC plt relocations.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::emit_pending_ifunc_relocs()
+{
+  // Emit any pending IFUNC relocs.
+  for (typename std::vector<Global_ifunc>::const_iterator p =
+        this->global_ifuncs_.begin();
+       p != this->global_ifuncs_.end();
+       ++p)
+    {
+      section_offset_type plt_offset;
+      unsigned int index;
+
+      index = this->count_ + p->plt_index + 4;
+      plt_offset = this->plt_index_to_offset(index);
+      p->rel->add_symbolless_global_addend(p->gsym, elfcpp::R_SPARC_JMP_IREL,
+                                          this, plt_offset, 0);
+    }
+
+  for (typename std::vector<Local_ifunc>::const_iterator p =
+        this->local_ifuncs_.begin();
+       p != this->local_ifuncs_.end();
+       ++p)
+    {
+      section_offset_type plt_offset;
+      unsigned int index;
+
+      index = this->count_ + p->plt_index + 4;
+      plt_offset = this->plt_index_to_offset(index);
+      p->rel->add_symbolless_local_addend(p->object, p->local_sym_index,
+                                         elfcpp::R_SPARC_JMP_IREL,
+                                         this, plt_offset, 0);
+    }
+}
+
+// Return where the IFUNC relocations should go in the PLT.  These
+// follow the non-IFUNC relocations.
+
+template<int size, bool big_endian>
+typename Output_data_plt_sparc<size, big_endian>::Reloc_section*
+Output_data_plt_sparc<size, big_endian>::rela_ifunc(
+       Symbol_table* symtab,
+       Layout* layout)
+{
+  if (this->ifunc_rel_ == NULL)
+    {
+      this->ifunc_rel_ = new Reloc_section(false);
+      layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+                                     elfcpp::SHF_ALLOC, this->ifunc_rel_,
+                                     ORDER_DYNAMIC_PLT_RELOCS, false);
+      gold_assert(this->ifunc_rel_->output_section()
+                 == this->rel_->output_section());
+
+      if (parameters->doing_static_link())
+       {
+         // A statically linked executable will only have a .rel.plt
+         // section to hold R_SPARC_IRELATIVE and R_SPARC_JMP_IREL
+         // relocs for STT_GNU_IFUNC symbols.  The library will use
+         // these symbols to locate the IRELATIVE and JMP_IREL relocs
+         // at program startup time.
+         symtab->define_in_output_data("__rela_iplt_start", NULL,
+                                       Symbol_table::PREDEFINED,
+                                       this->ifunc_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->ifunc_rel_, 0, 0,
+                                       elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
+                                       elfcpp::STV_HIDDEN, 0, true, true);
+       }
     }
+  return this->ifunc_rel_;
+}
 
-  gsym->set_plt_offset(plt_offset);
+// Return the PLT address to use for a global symbol.
 
-  ++this->count_;
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_sparc<size, big_endian>::address_for_global(const Symbol* gsym)
+{
+  uint64_t offset = 0;
+  if (gsym->type() == elfcpp::STT_GNU_IFUNC
+      && gsym->can_use_relative_reloc(false))
+    offset = plt_index_to_offset(this->count_ + 4);
+  return this->address() + offset + gsym->plt_offset();
+}
 
-  // Every PLT entry needs a reloc.
-  gsym->set_needs_dynsym_entry();
-  this->rel_->add_global(gsym, elfcpp::R_SPARC_JMP_SLOT, this,
-                        plt_offset, 0);
+// Return the PLT address to use for a local symbol.  These are always
+// IRELATIVE relocs.
 
-  // 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.
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_sparc<size, big_endian>::address_for_local(
+       const Relobj* object,
+       unsigned int r_sym)
+{
+  return (this->address()
+         + plt_index_to_offset(this->count_ + 4)
+         + object->local_plt_offset(r_sym));
 }
 
 static const unsigned int sparc_nop = 0x01000000;
@@ -1206,10 +1679,10 @@ Output_data_plt_sparc<size, big_endian>::do_write(Output_file* of)
   unsigned char* pov = oview;
 
   memset(pov, 0, base_plt_entry_size * 4);
-  pov += base_plt_entry_size * 4;
+  pov += this->first_plt_entry_offset();
 
   unsigned int plt_offset = base_plt_entry_size * 4;
-  const unsigned int count = this->count_;
+  const unsigned int count = this->entry_count();
 
   if (size == 64)
     {
@@ -1329,6 +1802,38 @@ Output_data_plt_sparc<size, big_endian>::do_write(Output_file* of)
   of->write_output_view(offset, oview_size, oview);
 }
 
+// Create the PLT section.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::make_plt_section(Symbol_table* symtab,
+                                                Layout* layout)
+{
+  // 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 Sparc 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_sparc<size, big_endian>(layout);
+  layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+                                 (elfcpp::SHF_ALLOC
+                                  | elfcpp::SHF_EXECINSTR
+                                  | elfcpp::SHF_WRITE),
+                                 this->plt_, ORDER_NON_RELRO_FIRST, false);
+
+  // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
+  symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
+                               Symbol_table::PREDEFINED,
+                               this->plt_,
+                               0, 0, elfcpp::STT_OBJECT,
+                               elfcpp::STB_LOCAL,
+                               elfcpp::STV_HIDDEN, 0,
+                               false, false);
+}
+
 // Create a PLT entry for a global symbol.
 
 template<int size, bool big_endian>
@@ -1341,36 +1846,68 @@ Target_sparc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
     return;
 
   if (this->plt_ == NULL)
-    {
-      // Create the GOT sections first.
-      this->got_section(symtab, layout);
+    this->make_plt_section(symtab, layout);
 
-      this->plt_ = new Output_data_plt_sparc<size, big_endian>(layout);
-      layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
-                                     (elfcpp::SHF_ALLOC
-                                      | elfcpp::SHF_EXECINSTR
-                                      | elfcpp::SHF_WRITE),
-                                     this->plt_);
+  this->plt_->add_entry(symtab, layout, gsym);
+}
 
-      // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
-      symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
-                                   this->plt_,
-                                   0, 0, elfcpp::STT_OBJECT,
-                                   elfcpp::STB_LOCAL,
-                                   elfcpp::STV_HIDDEN, 0,
-                                   false, false);
-    }
+// Make a PLT entry for a local STT_GNU_IFUNC symbol.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::make_local_ifunc_plt_entry(
+       Symbol_table* symtab,
+       Layout* layout,
+       Sized_relobj_file<size, big_endian>* relobj,
+       unsigned int local_sym_index)
+{
+  if (relobj->local_has_plt_offset(local_sym_index))
+    return;
+  if (this->plt_ == NULL)
+    this->make_plt_section(symtab, layout);
+  unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout,
+                                                             relobj,
+                                                             local_sym_index);
+  relobj->set_local_plt_offset(local_sym_index, plt_offset);
+}
+
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
 
-  this->plt_->add_entry(gsym);
+// Return the offset of the first non-reserved PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_sparc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_sparc<size, big_endian>::get_plt_entry_size();
 }
 
 // Create a GOT entry for the TLS module index.
 
 template<int size, bool big_endian>
 unsigned int
-Target_sparc<size, big_endian>::got_mod_index_entry(Symbol_table* symtab,
-                                                   Layout* layout,
-                                                   Sized_relobj<size, big_endian>* object)
+Target_sparc<size, big_endian>::got_mod_index_entry(
+     Symbol_table* symtab,
+     Layout* layout,
+     Sized_relobj_file<size, big_endian>* object)
 {
   if (this->got_mod_index_offset_ == -1U)
     {
@@ -1437,6 +1974,7 @@ optimize_tls_reloc(bool is_final, int r_type)
     case elfcpp::R_SPARC_TLS_IE_LO10:
     case elfcpp::R_SPARC_TLS_IE_LD:
     case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
       // 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
@@ -1456,12 +1994,129 @@ optimize_tls_reloc(bool is_final, int r_type)
     }
 }
 
-// Generate a PLT entry slot for a call to __tls_get_addr
+// Get the Reference_flags for a particular relocation.
+
 template<int size, bool big_endian>
-void
-Target_sparc<size, big_endian>::Scan::generate_tls_call(Symbol_table* symtab,
-                                                       Layout* layout,
-                                                       Target_sparc<size, big_endian>* target)
+int
+Target_sparc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
+{
+  r_type &= 0xff;
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_NONE:
+    case elfcpp::R_SPARC_REGISTER:
+    case elfcpp::R_SPARC_GNU_VTINHERIT:
+    case elfcpp::R_SPARC_GNU_VTENTRY:
+      // No symbol reference.
+      return 0;
+
+    case elfcpp::R_SPARC_UA64:
+    case elfcpp::R_SPARC_64:
+    case elfcpp::R_SPARC_HIX22:
+    case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H34:
+    case elfcpp::R_SPARC_H44:
+    case elfcpp::R_SPARC_M44:
+    case elfcpp::R_SPARC_L44:
+    case elfcpp::R_SPARC_HH22:
+    case elfcpp::R_SPARC_HM10:
+    case elfcpp::R_SPARC_LM22:
+    case elfcpp::R_SPARC_HI22:
+    case elfcpp::R_SPARC_LO10:
+    case elfcpp::R_SPARC_OLO10:
+    case elfcpp::R_SPARC_UA32:
+    case elfcpp::R_SPARC_32:
+    case elfcpp::R_SPARC_UA16:
+    case elfcpp::R_SPARC_16:
+    case elfcpp::R_SPARC_11:
+    case elfcpp::R_SPARC_10:
+    case elfcpp::R_SPARC_8:
+    case elfcpp::R_SPARC_7:
+    case elfcpp::R_SPARC_6:
+    case elfcpp::R_SPARC_5:
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_DISP8:
+    case elfcpp::R_SPARC_DISP16:
+    case elfcpp::R_SPARC_DISP32:
+    case elfcpp::R_SPARC_DISP64:
+    case elfcpp::R_SPARC_PC_HH22:
+    case elfcpp::R_SPARC_PC_HM10:
+    case elfcpp::R_SPARC_PC_LM22:
+    case elfcpp::R_SPARC_PC10:
+    case elfcpp::R_SPARC_PC22:
+    case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WDISP22:
+    case elfcpp::R_SPARC_WDISP19:
+    case elfcpp::R_SPARC_WDISP16:
+    case elfcpp::R_SPARC_WDISP10:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_SPARC_PLT64:
+    case elfcpp::R_SPARC_PLT32:
+    case elfcpp::R_SPARC_HIPLT22:
+    case elfcpp::R_SPARC_LOPLT10:
+    case elfcpp::R_SPARC_PCPLT10:
+      return Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_PCPLT32:
+    case elfcpp::R_SPARC_PCPLT22:
+    case elfcpp::R_SPARC_WPLT30:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+    case elfcpp::R_SPARC_GOT10:
+    case elfcpp::R_SPARC_GOT13:
+    case elfcpp::R_SPARC_GOT22:
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+    case elfcpp::R_SPARC_TLS_LDM_HI22: // Local-dynamic
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:        // Alternate local-dynamic
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+    case elfcpp::R_SPARC_TLS_LE_HIX22:
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+    case elfcpp::R_SPARC_TLS_IE_HI22:  // Initial-exec
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+      return Symbol::TLS_REF;
+
+    case elfcpp::R_SPARC_COPY:
+    case elfcpp::R_SPARC_GLOB_DAT:
+    case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_JMP_IREL:
+    case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_IRELATIVE:
+    case elfcpp::R_SPARC_TLS_DTPMOD64:
+    case elfcpp::R_SPARC_TLS_DTPMOD32:
+    case elfcpp::R_SPARC_TLS_DTPOFF64:
+    case elfcpp::R_SPARC_TLS_DTPOFF32:
+    case elfcpp::R_SPARC_TLS_TPOFF64:
+    case elfcpp::R_SPARC_TLS_TPOFF32:
+    default:
+      // Not expected.  We will give an error later.
+      return 0;
+    }
+}
+
+// Generate a PLT entry slot for a call to __tls_get_addr
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::generate_tls_call(Symbol_table* symtab,
+                                                       Layout* layout,
+                                                       Target_sparc<size, big_endian>* target)
 {
   Symbol* gsym = target->tls_get_addr_sym(symtab);
 
@@ -1473,7 +2128,7 @@ Target_sparc<size, big_endian>::Scan::generate_tls_call(Symbol_table* symtab,
 template<int size, bool big_endian>
 void
 Target_sparc<size, big_endian>::Scan::unsupported_reloc_local(
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int r_type)
 {
   gold_error(_("%s: unsupported reloc %u against local symbol"),
@@ -1495,10 +2150,13 @@ Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int
        {
          // These are the relocation types supported by glibc for sparc 64-bit.
        case elfcpp::R_SPARC_RELATIVE:
+       case elfcpp::R_SPARC_IRELATIVE:
        case elfcpp::R_SPARC_COPY:
+       case elfcpp::R_SPARC_32:
        case elfcpp::R_SPARC_64:
        case elfcpp::R_SPARC_GLOB_DAT:
        case elfcpp::R_SPARC_JMP_SLOT:
+       case elfcpp::R_SPARC_JMP_IREL:
        case elfcpp::R_SPARC_TLS_DTPMOD64:
        case elfcpp::R_SPARC_TLS_DTPOFF64:
        case elfcpp::R_SPARC_TLS_TPOFF64:
@@ -1513,6 +2171,7 @@ Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int
        case elfcpp::R_SPARC_LO10:
        case elfcpp::R_SPARC_HI22:
        case elfcpp::R_SPARC_OLO10:
+       case elfcpp::R_SPARC_H34:
        case elfcpp::R_SPARC_H44:
        case elfcpp::R_SPARC_M44:
        case elfcpp::R_SPARC_L44:
@@ -1534,10 +2193,12 @@ Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int
        {
          // These are the relocation types supported by glibc for sparc 32-bit.
        case elfcpp::R_SPARC_RELATIVE:
+       case elfcpp::R_SPARC_IRELATIVE:
        case elfcpp::R_SPARC_COPY:
        case elfcpp::R_SPARC_GLOB_DAT:
        case elfcpp::R_SPARC_32:
        case elfcpp::R_SPARC_JMP_SLOT:
+       case elfcpp::R_SPARC_JMP_IREL:
        case elfcpp::R_SPARC_TLS_DTPMOD32:
        case elfcpp::R_SPARC_TLS_DTPOFF32:
        case elfcpp::R_SPARC_TLS_TPOFF32:
@@ -1565,31 +2226,59 @@ Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int
   // 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 big_endian>
+bool
+Target_sparc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
+     Sized_relobj_file<size, big_endian>* object,
+     unsigned int r_type)
+{
+  int flags = Scan::get_reference_flags(r_type);
+  if (flags & Symbol::TLS_REF)
+    gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
+              object->name().c_str(), r_type);
+  return flags != 0;
+}
+
 // Scan a relocation for a local symbol.
 
 template<int size, bool big_endian>
 inline void
 Target_sparc<size, big_endian>::Scan::local(
-                       const General_options&,
                        Symbol_table* symtab,
                        Layout* layout,
                        Target_sparc<size, big_endian>* target,
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int data_shndx,
                        Output_section* output_section,
                        const elfcpp::Rela<size, big_endian>& reloc,
                        unsigned int r_type,
-                       const elfcpp::Sym<size, big_endian>& lsym)
+                       const elfcpp::Sym<size, big_endian>& lsym,
+                       bool is_discarded)
 {
-  unsigned int orig_r_type = r_type;
+  if (is_discarded)
+    return;
 
+  bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
+  unsigned int orig_r_type = r_type;
   r_type &= 0xff;
+
+  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_SPARC_NONE:
@@ -1606,19 +2295,23 @@ Target_sparc<size, big_endian>::Scan::local(
       // apply the link-time value, so we flag the location with
       // an R_SPARC_RELATIVE relocation so the dynamic loader can
       // relocate it easily.
-      if (parameters->options().output_is_position_independent())
-        {
-          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_SPARC_RELATIVE,
+      if (parameters->options().output_is_position_independent()
+         && ((size == 64 && r_type == elfcpp::R_SPARC_64)
+             || (size == 32 && r_type == elfcpp::R_SPARC_32)))
+       {
+         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_SPARC_RELATIVE,
                                       output_section, data_shndx,
                                       reloc.get_r_offset(),
-                                      reloc.get_r_addend());
-        }
-      break;
+                                      reloc.get_r_addend(), is_ifunc);
+         break;
+       }
+      // Fall through.
 
     case elfcpp::R_SPARC_HIX22:
     case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H34:
     case elfcpp::R_SPARC_H44:
     case elfcpp::R_SPARC_M44:
     case elfcpp::R_SPARC_L44:
@@ -1642,33 +2335,34 @@ Target_sparc<size, big_endian>::Scan::local(
       // executable), we need to create a dynamic relocation for
       // this location.
       if (parameters->options().output_is_position_independent())
-        {
-          Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+       {
+         Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+         unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
 
          check_non_pic(object, r_type);
-          if (lsym.get_st_type() != elfcpp::STT_SECTION)
-            {
-              unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
-              rela_dyn->add_local(object, r_sym, orig_r_type, output_section,
+         if (lsym.get_st_type() != elfcpp::STT_SECTION)
+           {
+             rela_dyn->add_local(object, r_sym, orig_r_type, output_section,
                                  data_shndx, reloc.get_r_offset(),
                                  reloc.get_r_addend());
-            }
-          else
-            {
-             unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
-              gold_assert(lsym.get_st_value() == 0);
-              rela_dyn->add_local_relative(object, r_sym, orig_r_type,
-                                          output_section, data_shndx,
-                                          reloc.get_r_offset(),
-                                          reloc.get_r_addend());
-            }
-        }
+           }
+         else
+           {
+             gold_assert(lsym.get_st_value() == 0);
+             rela_dyn->add_symbolless_local_addend(object, r_sym, orig_r_type,
+                                                   output_section, data_shndx,
+                                                   reloc.get_r_offset(),
+                                                   reloc.get_r_addend());
+           }
+       }
       break;
 
     case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WPLT30:
     case elfcpp::R_SPARC_WDISP22:
     case elfcpp::R_SPARC_WDISP19:
     case elfcpp::R_SPARC_WDISP16:
+    case elfcpp::R_SPARC_WDISP10:
     case elfcpp::R_SPARC_DISP8:
     case elfcpp::R_SPARC_DISP16:
     case elfcpp::R_SPARC_DISP32:
@@ -1677,13 +2371,20 @@ Target_sparc<size, big_endian>::Scan::local(
     case elfcpp::R_SPARC_PC22:
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+      // We will optimize this into a GOT relative relocation
+      // and code transform the GOT load into an addition.
+      break;
+
     case elfcpp::R_SPARC_GOT10:
     case elfcpp::R_SPARC_GOT13:
     case elfcpp::R_SPARC_GOT22:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got<size, big_endian>* got;
-        unsigned int r_sym;
+       // The symbol requires a GOT entry.
+       Output_data_got<size, big_endian>* got;
+       unsigned int r_sym;
 
        got = target->got_section(symtab, layout);
        r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
@@ -1695,13 +2396,11 @@ Target_sparc<size, big_endian>::Scan::local(
            if (!object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD))
              {
                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-               unsigned int off;
-
-               off = got->add_constant(0);
+               unsigned int off = got->add_constant(0);
                object->set_local_got_offset(r_sym, GOT_TYPE_STANDARD, off);
                rela_dyn->add_local_relative(object, r_sym,
                                             elfcpp::R_SPARC_RELATIVE,
-                                            got, off, 0);
+                                            got, off, 0, is_ifunc);
              }
          }
        else
@@ -1726,12 +2425,13 @@ Target_sparc<size, big_endian>::Scan::local(
     case elfcpp::R_SPARC_TLS_IE_LO10:
     case elfcpp::R_SPARC_TLS_IE_LD:
     case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
     case elfcpp::R_SPARC_TLS_LE_HIX22: // Local-exec
     case elfcpp::R_SPARC_TLS_LE_LOX10:
       {
        bool output_is_shared = parameters->options().shared();
        const tls::Tls_optimization optimized_type
-            = optimize_tls_reloc(!output_is_shared, r_type);
+           = optimize_tls_reloc(!output_is_shared, r_type);
        switch (r_type)
          {
          case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
@@ -1740,11 +2440,11 @@ Target_sparc<size, big_endian>::Scan::local(
          case elfcpp::R_SPARC_TLS_GD_CALL:
            if (optimized_type == tls::TLSOPT_NONE)
              {
-               // Create a pair of GOT entries for the module index and
-               // dtv-relative offset.
-                Output_data_got<size, big_endian>* got
-                    = target->got_section(symtab, layout);
-                unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+               // Create a pair of GOT entries for the module index and
+               // dtv-relative offset.
+               Output_data_got<size, big_endian>* got
+                   = target->got_section(symtab, layout);
+               unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                unsigned int shndx = lsym.get_st_shndx();
                bool is_ordinary;
                shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
@@ -1752,14 +2452,13 @@ Target_sparc<size, big_endian>::Scan::local(
                  object->error(_("local symbol %u has bad shndx %u"),
                                r_sym, shndx);
                else
-                 got->add_local_pair_with_rela(object, r_sym, 
-                                               lsym.get_st_shndx(),
-                                               GOT_TYPE_TLS_PAIR,
-                                               target->rela_dyn_section(layout),
-                                               (size == 64
-                                                ? elfcpp::R_SPARC_TLS_DTPMOD64
-                                                : elfcpp::R_SPARC_TLS_DTPMOD32),
-                                                0);
+                 got->add_local_pair_with_rel(object, r_sym,
+                                              lsym.get_st_shndx(),
+                                              GOT_TYPE_TLS_PAIR,
+                                              target->rela_dyn_section(layout),
+                                              (size == 64
+                                               ? elfcpp::R_SPARC_TLS_DTPMOD64
+                                               : elfcpp::R_SPARC_TLS_DTPMOD32));
                if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
                  generate_tls_call(symtab, layout, target);
              }
@@ -1792,6 +2491,7 @@ Target_sparc<size, big_endian>::Scan::local(
          case elfcpp::R_SPARC_TLS_IE_LO10:
          case elfcpp::R_SPARC_TLS_IE_LD:
          case elfcpp::R_SPARC_TLS_IE_LDX:
+         case elfcpp::R_SPARC_TLS_IE_ADD:
            layout->set_has_static_tls();
            if (optimized_type == tls::TLSOPT_NONE)
              {
@@ -1805,13 +2505,13 @@ Target_sparc<size, big_endian>::Scan::local(
                    Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                    unsigned int off = got->add_constant(0);
 
-                   object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET,
-                                                off);
-                   rela_dyn->add_local_relative(object, r_sym,
-                                                (size == 64 ?
-                                                 elfcpp::R_SPARC_TLS_TPOFF64 :
-                                                 elfcpp::R_SPARC_TLS_TPOFF32),
-                                                got, off, 0);
+                   object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET, off);
+
+                   rela_dyn->add_symbolless_local_addend(object, r_sym,
+                                                         (size == 64 ?
+                                                          elfcpp::R_SPARC_TLS_TPOFF64 :
+                                                          elfcpp::R_SPARC_TLS_TPOFF32),
+                                                         got, off, 0);
                  }
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
@@ -1823,13 +2523,13 @@ Target_sparc<size, big_endian>::Scan::local(
            layout->set_has_static_tls();
            if (output_is_shared)
              {
-               // We need to create a dynamic relocation.
-                gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
-                unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
-                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-                rela_dyn->add_local_relative(object, r_sym, r_type,
-                                            output_section, data_shndx,
-                                            reloc.get_r_offset(), 0);
+               // We need to create a dynamic relocation.
+               gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+               unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
+                                                     output_section, data_shndx,
+                                                     reloc.get_r_offset(), 0);
              }
            break;
          }
@@ -1841,7 +2541,9 @@ Target_sparc<size, big_endian>::Scan::local(
     case elfcpp::R_SPARC_COPY:
     case elfcpp::R_SPARC_GLOB_DAT:
     case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_JMP_IREL:
     case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_IRELATIVE:
     case elfcpp::R_SPARC_TLS_DTPMOD64:
     case elfcpp::R_SPARC_TLS_DTPMOD32:
     case elfcpp::R_SPARC_TLS_DTPOFF64:
@@ -1863,7 +2565,7 @@ Target_sparc<size, big_endian>::Scan::local(
 template<int size, bool big_endian>
 void
 Target_sparc<size, big_endian>::Scan::unsupported_reloc_global(
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int r_type,
                        Symbol* gsym)
 {
@@ -1876,11 +2578,10 @@ Target_sparc<size, big_endian>::Scan::unsupported_reloc_global(
 template<int size, bool big_endian>
 inline void
 Target_sparc<size, big_endian>::Scan::global(
-                               const General_options&,
                                Symbol_table* symtab,
                                Layout* layout,
                                Target_sparc<size, big_endian>* target,
-                               Sized_relobj<size, big_endian>* object,
+                               Sized_relobj_file<size, big_endian>* object,
                                unsigned int data_shndx,
                                Output_section* output_section,
                                const elfcpp::Rela<size, big_endian>& reloc,
@@ -1888,8 +2589,22 @@ Target_sparc<size, big_endian>::Scan::global(
                                Symbol* gsym)
 {
   unsigned int orig_r_type = r_type;
+  bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC;
+
+  // A reference to _GLOBAL_OFFSET_TABLE_ implies that we need a got
+  // section.  We check here to avoid creating a dynamic reloc against
+  // _GLOBAL_OFFSET_TABLE_.
+  if (!target->has_got_section()
+      && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
+    target->got_section(symtab, layout);
 
   r_type &= 0xff;
+
+  // A STT_GNU_IFUNC symbol may require a PLT entry.
+  if (is_ifunc
+      && this->reloc_needs_plt_for_ifunc(object, r_type))
+    target->make_plt_entry(symtab, layout, gsym);
+
   switch (r_type)
     {
     case elfcpp::R_SPARC_NONE:
@@ -1914,8 +2629,8 @@ Target_sparc<size, big_endian>::Scan::global(
       // 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())
+         && !gsym->is_from_dynobj()
+         && !gsym->is_preemptible())
        break;
       target->make_plt_entry(symtab, layout, gsym);
       break;
@@ -1933,16 +2648,15 @@ Target_sparc<size, big_endian>::Scan::global(
     case elfcpp::R_SPARC_WDISP22:
     case elfcpp::R_SPARC_WDISP19:
     case elfcpp::R_SPARC_WDISP16:
+    case elfcpp::R_SPARC_WDISP10:
       {
        if (gsym->needs_plt_entry())
          target->make_plt_entry(symtab, layout, gsym);
        // Make a dynamic relocation if necessary.
-       int flags = Symbol::NON_PIC_REF;
-       if (gsym->type() == elfcpp::STT_FUNC)
-         flags |= Symbol::FUNCTION_CALL;
-       if (gsym->needs_dynamic_reloc(flags))
+       if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
          {
-           if (target->may_need_copy_reloc(gsym))
+           if (parameters->options().output_is_executable()
+               && gsym->may_need_copy_reloc())
              {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym,
@@ -1964,6 +2678,7 @@ Target_sparc<size, big_endian>::Scan::global(
     case elfcpp::R_SPARC_64:
     case elfcpp::R_SPARC_HIX22:
     case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H34:
     case elfcpp::R_SPARC_H44:
     case elfcpp::R_SPARC_M44:
     case elfcpp::R_SPARC_L44:
@@ -1984,38 +2699,92 @@ Target_sparc<size, big_endian>::Scan::global(
     case elfcpp::R_SPARC_6:
     case elfcpp::R_SPARC_5:
       {
-        // 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(Symbol::ABSOLUTE_REF))
-          {
-            if (target->may_need_copy_reloc(gsym))
-              {
-               target->copy_reloc(symtab, layout, object,
-                                  data_shndx, output_section, gsym, reloc);
-              }
-            else if ((r_type == elfcpp::R_SPARC_32
-                     || r_type == elfcpp::R_SPARC_64)
-                     && gsym->can_use_relative_reloc(false))
-              {
-                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-                rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
+       // 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)))
+         {
+           unsigned int r_off = reloc.get_r_offset();
+
+           // The assembler can sometimes emit unaligned relocations
+           // for dwarf2 cfi directives.
+           switch (r_type)
+             {
+             case elfcpp::R_SPARC_16:
+               if (r_off & 0x1)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA16;
+               break;
+             case elfcpp::R_SPARC_32:
+               if (r_off & 0x3)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA32;
+               break;
+             case elfcpp::R_SPARC_64:
+               if (r_off & 0x7)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA64;
+               break;
+             case elfcpp::R_SPARC_UA16:
+               if (!(r_off & 0x1))
+                 orig_r_type = r_type = elfcpp::R_SPARC_16;
+               break;
+             case elfcpp::R_SPARC_UA32:
+               if (!(r_off & 0x3))
+                 orig_r_type = r_type = elfcpp::R_SPARC_32;
+               break;
+             case elfcpp::R_SPARC_UA64:
+               if (!(r_off & 0x7))
+                 orig_r_type = r_type = elfcpp::R_SPARC_64;
+               break;
+             }
+
+           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_SPARC_64)
+                     || (size == 32 && r_type == elfcpp::R_SPARC_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_ifunc_section(layout);
+               unsigned int r_type = elfcpp::R_SPARC_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_SPARC_64)
+                     || (size == 32 && r_type == elfcpp::R_SPARC_32))
+                    && gsym->can_use_relative_reloc(false))
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
                                              output_section, object,
                                              data_shndx, reloc.get_r_offset(),
-                                             reloc.get_r_addend());
-              }
-            else
-              {
-                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+                                             reloc.get_r_addend(), is_ifunc);
+             }
+           else
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
 
                check_non_pic(object, r_type);
                if (gsym->is_from_dynobj()
@@ -2026,45 +2795,102 @@ Target_sparc<size, big_endian>::Scan::global(
                                       reloc.get_r_offset(),
                                       reloc.get_r_addend());
                else
-                 rela_dyn->add_global_relative(gsym, orig_r_type,
-                                               output_section, object,
-                                               data_shndx,
-                                               reloc.get_r_offset(),
-                                               reloc.get_r_addend());
-              }
-          }
+                 rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+                                                        output_section,
+                                                        object, data_shndx,
+                                                        reloc.get_r_offset(),
+                                                        reloc.get_r_addend());
+             }
+         }
       }
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+      if (gsym->is_defined()
+         && !gsym->is_from_dynobj()
+         && !gsym->is_preemptible()
+         && !is_ifunc)
+       {
+         // We will optimize this into a GOT relative relocation
+         // and code transform the GOT load into an addition.
+         break;
+       }
+      // Fall through.
     case elfcpp::R_SPARC_GOT10:
     case elfcpp::R_SPARC_GOT13:
     case elfcpp::R_SPARC_GOT22:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got<size, big_endian>* got;
+       // The symbol requires a GOT entry.
+       Output_data_got<size, big_endian>* got;
 
        got = target->got_section(symtab, layout);
-        if (gsym->final_value_is_known())
-          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);
-            if (gsym->is_from_dynobj()
-                || gsym->is_undefined()
-                || gsym->is_preemptible())
-              got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,
-                                        elfcpp::R_SPARC_GLOB_DAT);
-            else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
-              {
+       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
+           // GOT entry with a dynamic relocation.
+           bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC;
+
+           // 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.
+           Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+           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()
+                   && !gsym->is_forced_local()))
+             {
+               unsigned int r_type = elfcpp::R_SPARC_GLOB_DAT;
+
+               // If this symbol is forced local, this relocation will
+               // not work properly.  That's because ld.so on sparc
+               // (and 32-bit powerpc) expects st_value in the r_addend
+               // of relocations for STB_LOCAL symbols.  Curiously the
+               // BFD linker does not promote global hidden symbols to be
+               // STB_LOCAL in the dynamic symbol table like Gold does.
+               gold_assert(!gsym->is_forced_local());
+               got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
+                                        r_type);
+             }
+           else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
+             {
                unsigned int off = got->add_constant(0);
 
                gsym->set_got_offset(GOT_TYPE_STANDARD, off);
+               if (is_ifunc)
+                 {
+                   // 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();
+                 }
                rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
-                                             got, off, 0);
+                                             got, off, 0, is_ifunc);
              }
-          }
+         }
       }
       break;
 
@@ -2087,10 +2913,11 @@ Target_sparc<size, big_endian>::Scan::global(
     case elfcpp::R_SPARC_TLS_IE_LO10:
     case elfcpp::R_SPARC_TLS_IE_LD:
     case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
       {
        const bool is_final = gsym->final_value_is_known();
        const tls::Tls_optimization optimized_type
-            = optimize_tls_reloc(is_final, r_type);
+           = optimize_tls_reloc(is_final, r_type);
        switch (r_type)
          {
          case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
@@ -2099,18 +2926,18 @@ Target_sparc<size, big_endian>::Scan::global(
          case elfcpp::R_SPARC_TLS_GD_CALL:
            if (optimized_type == tls::TLSOPT_NONE)
              {
-                // Create a pair of GOT entries for the module index and
-                // dtv-relative offset.
-                Output_data_got<size, big_endian>* got
-                    = target->got_section(symtab, layout);
-                got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_PAIR,
-                                               target->rela_dyn_section(layout),
-                                              (size == 64 ?
-                                               elfcpp::R_SPARC_TLS_DTPMOD64 :
-                                               elfcpp::R_SPARC_TLS_DTPMOD32),
-                                              (size == 64 ?
-                                               elfcpp::R_SPARC_TLS_DTPOFF64 :
-                                               elfcpp::R_SPARC_TLS_DTPOFF32));
+               // Create a pair of GOT entries for the module index and
+               // dtv-relative offset.
+               Output_data_got<size, big_endian>* got
+                   = target->got_section(symtab, layout);
+               got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+                                             target->rela_dyn_section(layout),
+                                             (size == 64
+                                              ? elfcpp::R_SPARC_TLS_DTPMOD64
+                                              : elfcpp::R_SPARC_TLS_DTPMOD32),
+                                             (size == 64
+                                              ? elfcpp::R_SPARC_TLS_DTPOFF64
+                                              : elfcpp::R_SPARC_TLS_DTPOFF32));
 
                // Emit R_SPARC_WPLT30 against "__tls_get_addr"
                if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
@@ -2118,14 +2945,14 @@ Target_sparc<size, big_endian>::Scan::global(
              }
            else if (optimized_type == tls::TLSOPT_TO_IE)
              {
-                // Create a GOT entry for the tp-relative offset.
-                Output_data_got<size, big_endian>* got
-                    = target->got_section(symtab, layout);
-                got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
-                                          target->rela_dyn_section(layout),
-                                         (size == 64 ?
-                                          elfcpp::R_SPARC_TLS_TPOFF64 :
-                                          elfcpp::R_SPARC_TLS_TPOFF32));
+               // Create a GOT entry for the tp-relative offset.
+               Output_data_got<size, big_endian>* got
+                   = target->got_section(symtab, layout);
+               got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                                        target->rela_dyn_section(layout),
+                                        (size == 64 ?
+                                         elfcpp::R_SPARC_TLS_TPOFF64 :
+                                         elfcpp::R_SPARC_TLS_TPOFF32));
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
@@ -2158,10 +2985,10 @@ Target_sparc<size, big_endian>::Scan::global(
            if (parameters->options().shared())
              {
                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-               rela_dyn->add_global_relative(gsym, orig_r_type,
-                                             output_section, object,
-                                             data_shndx, reloc.get_r_offset(),
-                                             0);
+               rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+                                                      output_section, object,
+                                                      data_shndx, reloc.get_r_offset(),
+                                                      0);
              }
            break;
 
@@ -2169,17 +2996,18 @@ Target_sparc<size, big_endian>::Scan::global(
          case elfcpp::R_SPARC_TLS_IE_LO10:
          case elfcpp::R_SPARC_TLS_IE_LD:
          case elfcpp::R_SPARC_TLS_IE_LDX:
+         case elfcpp::R_SPARC_TLS_IE_ADD:
            layout->set_has_static_tls();
            if (optimized_type == tls::TLSOPT_NONE)
              {
                // Create a GOT entry for the tp-relative offset.
                Output_data_got<size, big_endian>* got
                  = target->got_section(symtab, layout);
-               got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
-                                         target->rela_dyn_section(layout),
-                                         (size == 64 ?
-                                          elfcpp::R_SPARC_TLS_TPOFF64 :
-                                          elfcpp::R_SPARC_TLS_TPOFF32));
+               got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                                        target->rela_dyn_section(layout),
+                                        (size == 64
+                                         ? elfcpp::R_SPARC_TLS_TPOFF64
+                                         : elfcpp::R_SPARC_TLS_TPOFF32));
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
@@ -2193,7 +3021,9 @@ Target_sparc<size, big_endian>::Scan::global(
     case elfcpp::R_SPARC_COPY:
     case elfcpp::R_SPARC_GLOB_DAT:
     case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_JMP_IREL:
     case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_IRELATIVE:
     case elfcpp::R_SPARC_TLS_DTPMOD64:
     case elfcpp::R_SPARC_TLS_DTPMOD32:
     case elfcpp::R_SPARC_TLS_DTPOFF64:
@@ -2210,15 +3040,112 @@ Target_sparc<size, big_endian>::Scan::global(
     }
 }
 
+// Make a new symbol table entry.
+// STT_SPARC_REGISTER symbols require special handling,
+// so we intercept these symbols and keep track of them separately.
+// We will resolve register symbols here and output them at symbol
+// finalization time.
+
+template<int size, bool big_endian>
+Sized_symbol<size>*
+Target_sparc<size, big_endian>::make_symbol(const char* name,
+                                           elfcpp::STT type,
+                                           Object* object,
+                                           unsigned int shndx,
+                                           uint64_t value)
+{
+  // REGISTER symbols are used only on SPARC-64.
+  if (size == 64 && type == elfcpp::STT_SPARC_REGISTER)
+    {
+      // Ignore REGISTER symbols in dynamic objects.
+      if (object->is_dynamic())
+       return NULL;
+      // Only registers 2, 3, 6, and 7 can be declared global.
+      int reg = value;
+      switch (reg)
+       {
+       case 2: case 3:
+         reg -= 2;
+         break;
+       case 6: case 7:
+         reg -= 4;
+         break;
+       default:
+         gold_error(_("%s: only registers %%g[2367] can be declared "
+                      "using STT_REGISTER"),
+                    object->name().c_str());
+         return NULL;
+       }
+      Register_symbol& rsym = this->register_syms_[reg];
+      if (rsym.name == NULL)
+       {
+         rsym.name = name;
+         rsym.shndx = shndx;
+         rsym.obj = object;
+       }
+      else
+       {
+         if (strcmp(rsym.name, name) != 0)
+           {
+             gold_error(_("%s: register %%g%d declared as '%s'; "
+                          "previously declared as '%s' in %s"),
+                        object->name().c_str(),
+                        static_cast<int>(value),
+                        *name ? name : "#scratch",
+                        *rsym.name ? rsym.name : "#scratch",
+                        rsym.obj->name().c_str());
+             return NULL;
+           }
+       }
+      return NULL;
+    }
+  return new Sized_symbol<size>();
+}
+
+// Process relocations for gc.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::gc_process_relocs(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Sized_relobj_file<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       unsigned int,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       size_t local_symbol_count,
+                       const unsigned char* plocal_symbols)
+{
+  typedef Target_sparc<size, big_endian> Sparc;
+  typedef typename Target_sparc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
+  gold::gc_process_relocs<size, big_endian, Sparc, Scan, Classify_reloc>(
+    symtab,
+    layout,
+    this,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols);
+}
+
 // Scan relocations for a section.
 
 template<int size, bool big_endian>
 void
 Target_sparc<size, big_endian>::scan_relocs(
-                       const General_options& options,
                        Symbol_table* symtab,
                        Layout* layout,
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int data_shndx,
                        unsigned int sh_type,
                        const unsigned char* prelocs,
@@ -2229,7 +3156,8 @@ Target_sparc<size, big_endian>::scan_relocs(
                        const unsigned char* plocal_symbols)
 {
   typedef Target_sparc<size, big_endian> Sparc;
-  typedef typename Target_sparc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   if (sh_type == elfcpp::SHT_REL)
     {
@@ -2238,8 +3166,7 @@ Target_sparc<size, big_endian>::scan_relocs(
       return;
     }
 
-  gold::scan_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan>(
-    options,
+  gold::scan_relocs<size, big_endian, Sparc, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -2257,43 +3184,87 @@ Target_sparc<size, big_endian>::scan_relocs(
 
 template<int size, bool big_endian>
 void
-Target_sparc<size, big_endian>::do_finalize_sections(Layout* layout)
+Target_sparc<size, big_endian>::do_finalize_sections(
+    Layout* layout,
+    const Input_objects*,
+    Symbol_table* symtab)
 {
+  if (this->plt_)
+    this->plt_->emit_pending_ifunc_relocs();
+
   // Fill in some more dynamic tags.
-  Output_data_dynamic* const odyn = layout->dynamic_data();
-  if (odyn != NULL)
-    {
-      if (this->plt_ != NULL)
-       {
-         const Output_data* od = this->plt_->rel_plt();
-         odyn->add_section_size(elfcpp::DT_PLTRELSZ, od);
-         odyn->add_section_address(elfcpp::DT_JMPREL, od);
-         odyn->add_constant(elfcpp::DT_PLTREL, elfcpp::DT_RELA);
+  const Reloc_section* rel_plt = (this->plt_ == NULL
+                                 ? NULL
+                                 : this->plt_->rel_plt());
+  layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
+                                 this->rela_dyn_, true, true);
 
-         odyn->add_section_address(elfcpp::DT_PLTGOT, this->plt_);
-       }
+  // 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));
 
-      if (this->rela_dyn_ != NULL)
+  if (parameters->doing_static_link()
+      && (this->plt_ == NULL || !this->plt_->has_ifunc_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[] =
        {
-         const Output_data* od = this->rela_dyn_;
-         odyn->add_section_address(elfcpp::DT_RELA, od);
-         odyn->add_section_size(elfcpp::DT_RELASZ, od);
-         odyn->add_constant(elfcpp::DT_RELAENT,
-                            elfcpp::Elf_sizes<size>::rela_size);
-       }
+         {
+           "__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
+         }
+       };
 
-      if (!parameters->options().shared())
+      symtab->define_symbols(layout, 2, syms,
+                            layout->script_options()->saw_sections_clause());
+    }
+
+  for (int reg = 0; reg < 4; ++reg)
+    {
+      Register_symbol& rsym = this->register_syms_[reg];
+      if (rsym.name != NULL)
        {
-         // The value of the DT_DEBUG tag is filled in by the dynamic
-         // linker at run time, and used by the debugger.
-         odyn->add_constant(elfcpp::DT_DEBUG, 0);
+         int value = reg < 3 ? reg + 2 : reg + 4;
+         Sized_symbol<size>* sym = new Sized_symbol<size>();
+         if (rsym.shndx == elfcpp::SHN_UNDEF)
+           sym->init_undefined(rsym.name, NULL, value,
+                               elfcpp::STT_SPARC_REGISTER, elfcpp::STB_GLOBAL,
+                               elfcpp::STV_DEFAULT, 0);
+         else
+           sym->init_constant(rsym.name, NULL, value, 0,
+                              elfcpp::STT_SPARC_REGISTER, elfcpp::STB_GLOBAL,
+                              elfcpp::STV_DEFAULT, 0, false);
+         symtab->add_target_global_symbol(sym);
+         layout->add_target_specific_dynamic_tag(elfcpp::DT_SPARC_REGISTER,
+                                                 value);
        }
     }
-
-  // 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));
 }
 
 // Perform a relocation.
@@ -2302,16 +3273,20 @@ template<int size, bool big_endian>
 inline bool
 Target_sparc<size, big_endian>::Relocate::relocate(
                        const Relocate_info<size, big_endian>* relinfo,
+                       unsigned int,
                        Target_sparc* target,
+                       Output_section*,
                        size_t relnum,
-                       const elfcpp::Rela<size, big_endian>& rela,
-                       unsigned int r_type,
+                       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)
 {
+  const elfcpp::Rela<size, big_endian> rela(preloc);
+  unsigned int r_type = elfcpp::elf_r_type<size>(rela.get_r_info());
+  bool orig_is_ifunc = psymval->is_ifunc_symbol();
   r_type &= 0xff;
 
   if (this->ignore_gd_add_)
@@ -2326,50 +3301,77 @@ Target_sparc<size, big_endian>::Relocate::relocate(
        }
     }
 
+  if (view == NULL)
+    return true;
+
+  if (this->reloc_adjust_addr_ == view)
+    view -= 4;
+
   typedef Sparc_relocate_functions<size, big_endian> Reloc;
+  const Sized_relobj_file<size, big_endian>* object = relinfo->object;
 
   // Pick the value to use for symbols defined in shared objects.
   Symbol_value<size> symval;
   if (gsym != NULL
-      && (gsym->is_from_dynobj()
-          || (parameters->options().shared()
-              && (gsym->is_undefined() || gsym->is_preemptible())))
-      && gsym->has_plt_offset())
+      && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
       elfcpp::Elf_Xword value;
 
-      value = target->plt_section()->address() + gsym->plt_offset();
+      value = target->plt_address_for_global(gsym);
 
       symval.set_output_value(value);
 
       psymval = &symval;
     }
+  else if (gsym == NULL && orig_is_ifunc)
+    {
+      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 Sized_relobj<size, big_endian>* object = relinfo->object;
   const elfcpp::Elf_Xword addend = rela.get_r_addend();
 
   // Get the GOT offset if needed.  Unlike i386 and x86_64, our GOT
   // pointer points to the beginning, not the end, of the table.
   // So we just use the plain offset.
-  bool have_got_offset = false;
   unsigned int got_offset = 0;
+  bool gdop_valid = false;
   switch (r_type)
     {
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+      // If this is local, we did not create a GOT entry because we
+      // intend to transform this into a GOT relative relocation.
+      if (gsym == NULL
+         || (gsym->is_defined()
+             && !gsym->is_from_dynobj()
+             && !gsym->is_preemptible()
+             && !orig_is_ifunc))
+       {
+         got_offset = psymval->value(object, addend) - target->got_address();
+         gdop_valid = true;
+         break;
+       }
+      // Fall through.
     case elfcpp::R_SPARC_GOT10:
     case elfcpp::R_SPARC_GOT13:
     case elfcpp::R_SPARC_GOT22:
       if (gsym != NULL)
-        {
-          gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
-          got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
-        }
+       {
+         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);
-        }
-      have_got_offset = true;
+       {
+         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);
+       }
       break;
 
     default:
@@ -2390,14 +3392,30 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       break;
 
     case elfcpp::R_SPARC_16:
-      Relocate_functions<size, big_endian>::rela16(view, object,
-                                                  psymval, addend);
+      if (rela.get_r_offset() & 0x1)
+       {
+         // The assembler can sometimes emit unaligned relocations
+         // for dwarf2 cfi directives.
+         Reloc::ua16(view, object, psymval, addend);
+       }
+      else
+       Relocate_functions<size, big_endian>::rela16(view, object,
+                                                    psymval, addend);
       break;
 
     case elfcpp::R_SPARC_32:
       if (!parameters->options().output_is_position_independent())
-             Relocate_functions<size, big_endian>::rela32(view, object,
-                                                          psymval, addend);
+       {
+         if (rela.get_r_offset() & 0x3)
+           {
+             // The assembler can sometimes emit unaligned relocations
+             // for dwarf2 cfi directives.
+             Reloc::ua32(view, object, psymval, addend);
+           }
+         else
+           Relocate_functions<size, big_endian>::rela32(view, object,
+                                                        psymval, addend);
+       }
       break;
 
     case elfcpp::R_SPARC_DISP8:
@@ -2419,6 +3437,8 @@ Target_sparc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_SPARC_WDISP30:
     case elfcpp::R_SPARC_WPLT30:
       Reloc::wdisp30(view, object, psymval, addend, address);
+      if (target->may_relax())
+       relax_call(target, view, rela, view_size);
       break;
 
     case elfcpp::R_SPARC_WDISP22:
@@ -2433,6 +3453,10 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       Reloc::wdisp16(view, object, psymval, addend, address);
       break;
 
+    case elfcpp::R_SPARC_WDISP10:
+      Reloc::wdisp10(view, object, psymval, addend, address);
+      break;
+
     case elfcpp::R_SPARC_HI22:
       Reloc::hi22(view, object, psymval, addend);
       break;
@@ -2449,14 +3473,42 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       Reloc::lo10(view, object, psymval, addend);
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+      if (gdop_valid)
+       {
+         Reloc::gdop_lox10(view, got_offset);
+         break;
+       }
+      // Fall through.
     case elfcpp::R_SPARC_GOT10:
       Reloc::lo10(view, got_offset, addend);
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP:
+      if (gdop_valid)
+       {
+         typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
+         Insntype* wv = reinterpret_cast<Insntype*>(view);
+         Insntype val;
+
+         // {ld,ldx} [%rs1 + %rs2], %rd --> add %rs1, %rs2, %rd
+         val = elfcpp::Swap<32, true>::readval(wv);
+         val = 0x80000000 | (val & 0x3e07c01f);
+         elfcpp::Swap<32, true>::writeval(wv, val);
+       }
+      break;
+
     case elfcpp::R_SPARC_GOT13:
       Reloc::rela32_13(view, got_offset, addend);
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+      if (gdop_valid)
+       {
+         Reloc::gdop_hix22(view, got_offset);
+         break;
+       }
+      // Fall through.
     case elfcpp::R_SPARC_GOT22:
       Reloc::hi22(view, got_offset, addend);
       break;
@@ -2506,8 +3558,17 @@ Target_sparc<size, big_endian>::Relocate::relocate(
 
     case elfcpp::R_SPARC_64:
       if (!parameters->options().output_is_position_independent())
-             Relocate_functions<size, big_endian>::rela64(view, object,
-                                                          psymval, addend);
+       {
+         if (rela.get_r_offset() & 0x7)
+           {
+             // The assembler can sometimes emit unaligned relocations
+             // for dwarf2 cfi directives.
+             Reloc::ua64(view, object, psymval, addend);
+           }
+         else
+           Relocate_functions<size, big_endian>::rela64(view, object,
+                                                        psymval, addend);
+       }
       break;
 
     case elfcpp::R_SPARC_OLO10:
@@ -2570,6 +3631,10 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       Reloc::lox10(view, object, psymval, addend);
       break;
 
+    case elfcpp::R_SPARC_H34:
+      Reloc::h34(view, object, psymval, addend);
+      break;
+
     case elfcpp::R_SPARC_H44:
       Reloc::h44(view, object, psymval, addend);
       break;
@@ -2606,6 +3671,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_SPARC_TLS_IE_LO10:
     case elfcpp::R_SPARC_TLS_IE_LD:
     case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
     case elfcpp::R_SPARC_TLS_LE_HIX22:
     case elfcpp::R_SPARC_TLS_LE_LOX10:
       this->relocate_tls(relinfo, target, relnum, rela,
@@ -2616,7 +3682,9 @@ Target_sparc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_SPARC_COPY:
     case elfcpp::R_SPARC_GLOB_DAT:
     case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_JMP_IREL:
     case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_IRELATIVE:
       // These are outstanding tls relocs, which are unexpected when
       // linking.
     case elfcpp::R_SPARC_TLS_DTPMOD64:
@@ -2656,7 +3724,7 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
 {
   Output_segment* tls_segment = relinfo->layout->tls_segment();
   typedef Sparc_relocate_functions<size, big_endian> Reloc;
-  const Sized_relobj<size, big_endian>* object = relinfo->object;
+  const Sized_relobj_file<size, big_endian>* object = relinfo->object;
   typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
 
   const elfcpp::Elf_Xword addend = rela.get_r_addend();
@@ -2664,7 +3732,7 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
 
   const bool is_final =
     (gsym == NULL
-     ? !parameters->options().output_is_position_independent()
+     ? !parameters->options().shared()
      : gsym->final_value_is_known());
   const tls::Tls_optimization optimized_type
       = optimize_tls_reloc(is_final, r_type);
@@ -2708,22 +3776,22 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
          break;
        }
       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));
-              value = gsym->got_offset(got_type);
-            }
-          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));
-              value = object->local_got_offset(r_sym, got_type);
-            }
-          if (optimized_type == tls::TLSOPT_TO_IE)
+       {
+         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));
+             value = gsym->got_offset(got_type);
+           }
+         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));
+             value = object->local_got_offset(r_sym, got_type);
+           }
+         if (optimized_type == tls::TLSOPT_TO_IE)
            {
              Insntype* wv = reinterpret_cast<Insntype*>(view);
              Insntype val;
@@ -2756,7 +3824,7 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
                  // The compiler can put the TLS_GD_ADD instruction
                  // into the delay slot of the call.  If so, we need
                  // to transpose the two instructions so that the
-                 // the new sequence works properly.
+                 // new sequence works properly.
                  //
                  // The test we use is if the instruction in the
                  // delay slot is an add with destination register
@@ -2775,15 +3843,23 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
                      wv += 1;
                      this->ignore_gd_add_ = true;
                    }
-
+                 else
+                   {
+                     // Even if the delay slot isn't the TLS_GD_ADD
+                     // instruction, we still have to handle the case
+                     // where it sets up %o0 in some other way.
+                     elfcpp::Swap<32, true>::writeval(wv, val);
+                     wv += 1;
+                     this->reloc_adjust_addr_ = view + 4;
+                   }
                  // call __tls_get_addr --> add %g7, %o0, %o0
                  elfcpp::Swap<32, true>::writeval(wv, 0x9001c008);
                  break;
                }
-              break;
+             break;
            }
-          else if (optimized_type == tls::TLSOPT_NONE)
-            {
+         else if (optimized_type == tls::TLSOPT_NONE)
+           {
              switch (r_type)
                {
                case elfcpp::R_SPARC_TLS_GD_HI22:
@@ -2810,8 +3886,8 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
                  break;
                }
              break;
-            }
-        }
+           }
+       }
       gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                             _("unsupported reloc %u"),
                             r_type);
@@ -2840,10 +3916,10 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
          break;
        }
       else if (optimized_type == tls::TLSOPT_NONE)
-        {
-          // Relocate the field with the offset of the GOT entry for
-          // the module index.
-          unsigned int got_offset;
+       {
+         // Relocate the field with the offset of the GOT entry for
+         // the module index.
+         unsigned int got_offset;
 
          got_offset = target->got_mod_index_entry(NULL, NULL, NULL);
          switch (r_type)
@@ -2871,8 +3947,8 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
              }
              break;
            }
-          break;
-        }
+         break;
+       }
       gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
                             _("unsupported reloc %u"),
                             r_type);
@@ -2985,6 +4061,12 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
                             r_type);
       break;
 
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+      // This seems to be mainly so that we can find the addition
+      // instruction if there is one.  There doesn't seem to be any
+      // actual relocation to apply.
+      break;
+
     case elfcpp::R_SPARC_TLS_LE_HIX22:
       // If we're creating a shared library, a dynamic relocation will
       // have been created for this location, so do not apply it now.
@@ -3007,6 +4089,150 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
     }
 }
 
+// Relax a call instruction.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Relocate::relax_call(
+    Target_sparc<size, big_endian>* target,
+    unsigned char* view,
+    const elfcpp::Rela<size, big_endian>& rela,
+    section_size_type view_size)
+{
+  typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
+  Insntype *wv = reinterpret_cast<Insntype*>(view);
+  Insntype call_insn, delay_insn, set_insn;
+  uint32_t op3, reg, off;
+
+  // This code tries to relax call instructions that meet
+  // certain criteria.
+  //
+  // The first criteria is that the call must be such that the return
+  // address which the call writes into %o7 is unused.  Two sequences
+  // meet this criteria, and are used to implement tail calls.
+  //
+  // Leaf function tail call:
+  //
+  // or %o7, %g0, %ANY_REG
+  // call FUNC
+  //  or %ANY_REG, %g0, %o7
+  //
+  // Non-leaf function tail call:
+  //
+  // call FUNC
+  //  restore
+  //
+  // The second criteria is that the call destination is close.  If
+  // the displacement can fit in a signed 22-bit immediate field of a
+  // pre-V9 branch, we can do it.  If we are generating a 64-bit
+  // object or a 32-bit object with ELF machine type EF_SPARC32PLUS,
+  // and the displacement fits in a signed 19-bit immediate field,
+  // then we can use a V9 branch.
+
+  // Make sure the delay instruction can be safely accessed.
+  if (rela.get_r_offset() + 8 > view_size)
+    return;
+
+  call_insn = elfcpp::Swap<32, true>::readval(wv);
+  delay_insn = elfcpp::Swap<32, true>::readval(wv + 1);
+
+  // Make sure it is really a call instruction.
+  if (((call_insn >> 30) & 0x3) != 1)
+    return;
+
+  if (((delay_insn >> 30) & 0x3) != 2)
+    return;
+
+  // Accept only a restore or an integer arithmetic operation whose
+  // sole side effect is to write the %o7 register (and perhaps set
+  // the condition codes, which are considered clobbered across
+  // function calls).
+  //
+  // For example, we don't want to match a tagged addition or
+  // subtraction.  We also don't want to match something like a
+  // divide.
+  //
+  // Specifically we accept add{,cc}, and{,cc}, or{,cc},
+  // xor{,cc}, sub{,cc}, andn{,cc}, orn{,cc}, and xnor{,cc}.
+
+  op3 = (delay_insn >> 19) & 0x3f;
+  reg = (delay_insn >> 25) & 0x1f;
+  if (op3 != 0x3d
+      && ((op3 & 0x28) != 0 || reg != 15))
+    return;
+
+  // For non-restore instructions, make sure %o7 isn't
+  // an input.
+  if (op3 != 0x3d)
+    {
+      // First check RS1
+      reg = (delay_insn >> 14) & 0x1f;
+      if (reg == 15)
+       return;
+
+      // And if non-immediate, check RS2
+      if (((delay_insn >> 13) & 1) == 0)
+       {
+         reg = (delay_insn & 0x1f);
+         if (reg == 15)
+           return;
+       }
+    }
+
+  // Now check the branch distance.  We are called after the
+  // call has been relocated, so we just have to peek at the
+  // offset contained in the instruction.
+  off = call_insn & 0x3fffffff;
+  if ((off & 0x3fe00000) != 0
+      && (off & 0x3fe00000) != 0x3fe00000)
+    return;
+
+  if ((size == 64 || target->elf_machine_ == elfcpp::EM_SPARC32PLUS)
+      && ((off & 0x3c0000) == 0
+         || (off & 0x3c0000) == 0x3c0000))
+    {
+      // ba,pt %xcc, FUNC
+      call_insn = 0x10680000 | (off & 0x07ffff);
+    }
+  else
+    {
+      // ba FUNC
+      call_insn = 0x10800000 | (off & 0x3fffff);
+    }
+  elfcpp::Swap<32, true>::writeval(wv, call_insn);
+
+  // See if we can NOP out the delay slot instruction.  We peek
+  // at the instruction before the call to make sure we're dealing
+  // with exactly the:
+  //
+  // or %o7, %g0, %ANY_REG
+  // call
+  //  or %ANY_REG, %g0, %o7
+  //
+  // case.  Otherwise this might be a tricky piece of hand written
+  // assembler calculating %o7 in some non-trivial way, and therefore
+  // we can't be sure that NOP'ing out the delay slot is safe.
+  if (op3 == 0x02
+      && rela.get_r_offset() >= 4)
+    {
+      if ((delay_insn & ~(0x1f << 14)) != 0x9e100000)
+       return;
+
+      set_insn = elfcpp::Swap<32, true>::readval(wv - 1);
+      if ((set_insn & ~(0x1f << 25)) != 0x8013c000)
+       return;
+
+      reg = (set_insn >> 25) & 0x1f;
+      if (reg == 0 || reg == 15)
+       return;
+      if (reg != ((delay_insn >> 14) & 0x1f))
+       return;
+
+      // All tests pass, nop it out.
+      elfcpp::Swap<32, true>::writeval(wv + 1, sparc_nop);
+    }
+}
+
 // Relocate section data.
 
 template<int size, bool big_endian>
@@ -3020,15 +4246,18 @@ Target_sparc<size, big_endian>::relocate_section(
                        bool needs_special_offset_handling,
                        unsigned char* view,
                        typename elfcpp::Elf_types<size>::Elf_Addr address,
-                       section_size_type view_size)
+                       section_size_type view_size,
+                       const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef Target_sparc<size, big_endian> Sparc;
   typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_section<size, big_endian, Sparc, elfcpp::SHT_RELA,
-    Sparc_relocate>(
+  gold::relocate_section<size, big_endian, Sparc, Sparc_relocate,
+                        gold::Default_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
@@ -3037,21 +4266,8 @@ Target_sparc<size, big_endian>::relocate_section(
     needs_special_offset_handling,
     view,
     address,
-    view_size);
-}
-
-// Return the size of a relocation while scanning during a relocatable
-// link.
-
-template<int size, bool big_endian>
-unsigned int
-Target_sparc<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
-    unsigned int,
-    Relobj*)
-{
-  // We are always SHT_RELA, so we should never get here.
-  gold_unreachable();
-  return 0;
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Scan the relocs during a relocatable link.
@@ -3059,10 +4275,9 @@ Target_sparc<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
 template<int size, bool big_endian>
 void
 Target_sparc<size, big_endian>::scan_relocatable_relocs(
-                       const General_options& options,
                        Symbol_table* symtab,
                        Layout* layout,
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int data_shndx,
                        unsigned int sh_type,
                        const unsigned char* prelocs,
@@ -3073,14 +4288,14 @@ Target_sparc<size, big_endian>::scan_relocatable_relocs(
                        const unsigned char* plocal_symbols,
                        Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_RELA);
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
-      Scan_relocatable_relocs>(
-    options,
+  gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -3094,33 +4309,73 @@ Target_sparc<size, big_endian>::scan_relocatable_relocs(
     rr);
 }
 
-// Relocate a section during a relocatable link.
+// Scan the relocs for --emit-relocs.
 
 template<int size, bool big_endian>
 void
-Target_sparc<size, big_endian>::relocate_for_relocatable(
+Target_sparc<size, big_endian>::emit_relocs_scan(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object,
+    unsigned int data_shndx,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_syms,
+    Relocatable_relocs* rr)
+{
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
+// Emit relocations for a section.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::relocate_relocs(
     const Relocate_info<size, big_endian>* relinfo,
     unsigned int sh_type,
     const unsigned char* prelocs,
     size_t reloc_count,
     Output_section* output_section,
-    off_t offset_in_output_section,
-    const Relocatable_relocs* rr,
+    typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
     section_size_type view_size,
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_for_relocatable<size, big_endian, elfcpp::SHT_RELA>(
+  gold::relocate_relocs<size, big_endian, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
     output_section,
     offset_in_output_section,
-    rr,
     view,
     view_address,
     view_size,
@@ -3141,6 +4396,100 @@ Target_sparc<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
   return this->plt_section()->address() + gsym->plt_offset();
 }
 
+// do_make_elf_object to override the same function in the base class.
+// We need to use a target-specific sub-class of
+// Sized_relobj_file<size, big_endian> to process SPARC specific bits
+// of the ELF headers.  Hence we need to have our own ELF object creation.
+
+template<int size, bool big_endian>
+Object*
+Target_sparc<size, big_endian>::do_make_elf_object(
+    const std::string& name,
+    Input_file* input_file,
+    off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
+{
+  elfcpp::Elf_Half machine = ehdr.get_e_machine();
+  elfcpp::Elf_Word flags = ehdr.get_e_flags();
+  elfcpp::Elf_Word omm, mm;
+
+  switch (machine)
+    {
+    case elfcpp::EM_SPARC32PLUS:
+      this->elf_machine_ = elfcpp::EM_SPARC32PLUS;
+      break;
+
+    case elfcpp::EM_SPARC:
+    case elfcpp::EM_SPARCV9:
+      break;
+
+    default:
+      break;
+    }
+
+  if (!this->elf_flags_set_)
+    {
+      this->elf_flags_ = flags;
+      this->elf_flags_set_ = true;
+    }
+  else
+    {
+      // Accumulate cpu feature bits.
+      this->elf_flags_ |= (flags & (elfcpp::EF_SPARC_32PLUS
+                                   | elfcpp::EF_SPARC_SUN_US1
+                                   | elfcpp::EF_SPARC_HAL_R1
+                                   | elfcpp::EF_SPARC_SUN_US3));
+
+      // Bump the memory model setting to the most restrictive
+      // one we encounter.
+      omm = (this->elf_flags_ & elfcpp::EF_SPARCV9_MM);
+      mm = (flags & elfcpp::EF_SPARCV9_MM);
+      if (omm != mm)
+       {
+         if (mm == elfcpp::EF_SPARCV9_TSO)
+           {
+             this->elf_flags_ &= ~elfcpp::EF_SPARCV9_MM;
+             this->elf_flags_ |= elfcpp::EF_SPARCV9_TSO;
+           }
+         else if (mm == elfcpp::EF_SPARCV9_PSO
+                  && omm == elfcpp::EF_SPARCV9_RMO)
+           {
+             this->elf_flags_ &= ~elfcpp::EF_SPARCV9_MM;
+             this->elf_flags_ |= elfcpp::EF_SPARCV9_PSO;
+           }
+       }
+    }
+
+  // Validate that the little-endian flag matches how we've
+  // been instantiated.
+  if (!(flags & elfcpp::EF_SPARC_LEDATA) != big_endian)
+    {
+      if (big_endian)
+       gold_error(_("%s: little endian elf flag set on BE object"),
+                    name.c_str());
+      else
+       gold_error(_("%s: little endian elf flag clear on LE object"),
+                    name.c_str());
+    }
+
+  return Target::do_make_elf_object(name, input_file, offset, ehdr);
+}
+
+// Adjust ELF file header.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::do_adjust_elf_header(
+    unsigned char* view,
+    int len)
+{
+  elfcpp::Ehdr_write<size, big_endian> oehdr(view);
+
+  oehdr.put_e_machine(this->elf_machine_);
+  oehdr.put_e_flags(this->elf_flags_);
+
+  Sized_target<size, big_endian>::do_adjust_elf_header(view, len);
+}
+
 // The selector for sparc object files.
 
 template<int size, bool big_endian>
@@ -3149,12 +4498,12 @@ class Target_selector_sparc : public Target_selector
 public:
   Target_selector_sparc()
     : Target_selector(elfcpp::EM_NONE, size, big_endian,
-                     (size == 64 ? "elf64-sparc" : "elf32-sparc"))
+                     (size == 64 ? "elf64-sparc" : "elf32-sparc"),
+                     (size == 64 ? "elf64_sparc" : "elf32_sparc"))
   { }
 
-  Target* instantiated_target_;
-
-  Target* do_recognize(int machine, int, int)
+  virtual Target*
+  do_recognize(Input_file*, off_t, int machine, int, int)
   {
     switch (size)
       {
@@ -3173,15 +4522,12 @@ public:
        return NULL;
       }
 
-    return do_instantiate_target();
+    return this->instantiate_target();
   }
 
-  Target* do_instantiate_target()
-  {
-    if (this->instantiated_target_ == NULL)
-      this->instantiated_target_ = new Target_sparc<size, big_endian>();
-    return this->instantiated_target_;
-  }
+  virtual Target*
+  do_instantiate_target()
+  { return new Target_sparc<size, big_endian>(); }
 };
 
 Target_selector_sparc<32, true> target_selector_sparc32;
This page took 0.065891 seconds and 4 git commands to generate.