Refactor gold to enable support for MIPS-64 relocation format.
[deliverable/binutils-gdb.git] / gold / mips.cc
index 450883efdfa02222065866a5dd2acc75f717bbd7..c57ef4f807f4a51ade8a46ed822ef1267acc80a1 100644 (file)
@@ -1,6 +1,6 @@
 // mips.cc -- mips target support for gold.
 
-// Copyright (C) 2011-2014 Free Software Foundation, Inc.
+// Copyright (C) 2011-2016 Free Software Foundation, Inc.
 // Written by Sasa Stankovic <sasa.stankovic@imgtec.com>
 //        and Aleksandar Simeonov <aleksandar.simeonov@rt-rk.com>.
 // This file contains borrowed and adapted code from bfd/elfxx-mips.c.
@@ -44,6 +44,7 @@
 #include "tls.h"
 #include "errors.h"
 #include "gc.h"
+#include "nacl.h"
 
 namespace
 {
@@ -2641,9 +2642,9 @@ class Mips_output_section_reginfo : public Output_section
 // The MIPS target has relocation types which default handling of relocatable
 // relocation cannot process.  So we have to extend the default code.
 
-template<bool big_endian, int sh_type, typename Classify_reloc>
+template<bool big_endian, typename Classify_reloc>
 class Mips_scan_relocatable_relocs :
-  public Default_scan_relocatable_relocs<sh_type, Classify_reloc>
+  public Default_scan_relocatable_relocs<Classify_reloc>
 {
  public:
   // Return the strategy to use for a local symbol which is a section
@@ -2651,7 +2652,7 @@ class Mips_scan_relocatable_relocs :
   inline Relocatable_relocs::Reloc_strategy
   local_section_strategy(unsigned int r_type, Relobj* object)
   {
-    if (sh_type == elfcpp::SHT_RELA)
+    if (Classify_reloc::sh_type == elfcpp::SHT_RELA)
       return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
     else
       {
@@ -2661,7 +2662,7 @@ class Mips_scan_relocatable_relocs :
             return Relocatable_relocs::RELOC_SPECIAL;
 
           default:
-            return Default_scan_relocatable_relocs<sh_type, Classify_reloc>::
+            return Default_scan_relocatable_relocs<Classify_reloc>::
                 local_section_strategy(r_type, object);
           }
       }
@@ -2859,6 +2860,182 @@ class Symbol_visitor_check_symbols
   Symbol_table* symtab_;
 };
 
+// Relocation types, parameterized by SHT_REL vs. SHT_RELA, size,
+// and endianness. The relocation format for MIPS-64 is non-standard.
+
+template<int sh_type, int size, bool big_endian>
+struct Mips_reloc_types;
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_REL, 32, big_endian>
+{
+  typedef typename elfcpp::Rel<32, big_endian> Reloc;
+  typedef typename elfcpp::Rel_write<32, big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<32>::Elf_Swxword
+  get_r_addend(const Reloc*)
+  { return 0; }
+
+  static inline void
+  set_reloc_addend(Reloc_write*,
+                  typename elfcpp::Elf_types<32>::Elf_Swxword)
+  { gold_unreachable(); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_RELA, 32, big_endian>
+{
+  typedef typename elfcpp::Rela<32, big_endian> Reloc;
+  typedef typename elfcpp::Rela_write<32, big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<32>::Elf_Swxword
+  get_r_addend(const Reloc* reloc)
+  { return reloc->get_r_addend(); }
+
+  static inline void
+  set_reloc_addend(Reloc_write* p,
+                  typename elfcpp::Elf_types<32>::Elf_Swxword val)
+  { p->put_r_addend(val); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_REL, 64, big_endian>
+{
+  typedef typename elfcpp::Mips64_rel<big_endian> Reloc;
+  typedef typename elfcpp::Mips64_rel_write<big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<64>::Elf_Swxword
+  get_r_addend(const Reloc*)
+  { return 0; }
+
+  static inline void
+  set_reloc_addend(Reloc_write*,
+                  typename elfcpp::Elf_types<64>::Elf_Swxword)
+  { gold_unreachable(); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_RELA, 64, big_endian>
+{
+  typedef typename elfcpp::Mips64_rela<big_endian> Reloc;
+  typedef typename elfcpp::Mips64_rela_write<big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<64>::Elf_Swxword
+  get_r_addend(const Reloc* reloc)
+  { return reloc->get_r_addend(); }
+
+  static inline void
+  set_reloc_addend(Reloc_write* p,
+                  typename elfcpp::Elf_types<64>::Elf_Swxword val)
+  { p->put_r_addend(val); }
+};
+
+// Forward declaration.
+static unsigned int
+mips_get_size_for_reloc(unsigned int, Relobj*);
+
+// A class for inquiring about properties of a relocation,
+// used while scanning relocs during a relocatable link and
+// garbage collection.
+
+template<int sh_type_, int size, bool big_endian>
+class Mips_classify_reloc;
+
+template<int sh_type_, bool big_endian>
+class Mips_classify_reloc<sh_type_, 32, big_endian> :
+    public gold::Default_classify_reloc<sh_type_, 32, big_endian>
+{
+ public:
+  typedef typename Mips_reloc_types<sh_type_, 32, big_endian>::Reloc
+      Reltype;
+  typedef typename Mips_reloc_types<sh_type_, 32, big_endian>::Reloc_write
+      Reltype_write;
+
+  // Return the symbol referred to by the relocation.
+  static inline unsigned int
+  get_r_sym(const Reltype* reloc)
+  { return elfcpp::elf_r_sym<32>(reloc->get_r_info()); }
+
+  // Return the type of the relocation.
+  static inline unsigned int
+  get_r_type(const Reltype* reloc)
+  { return elfcpp::elf_r_type<32>(reloc->get_r_info()); }
+
+  // Return the explicit addend of the relocation (return 0 for SHT_REL).
+  static inline unsigned int
+  get_r_addend(const Reltype* reloc)
+  { return Mips_reloc_types<sh_type_, 32, big_endian>::get_r_addend(reloc); }
+
+  // Write the r_info field to a new reloc, using the r_info field from
+  // the original reloc, replacing the r_sym field with R_SYM.
+  static inline void
+  put_r_info(Reltype_write* new_reloc, Reltype* reloc, unsigned int r_sym)
+  {
+    unsigned int r_type = elfcpp::elf_r_type<32>(reloc->get_r_info());
+    new_reloc->put_r_info(elfcpp::elf_r_info<64>(r_sym, r_type));
+  }
+
+  // Write the r_addend field to a new reloc.
+  static inline void
+  put_r_addend(Reltype_write* to,
+              typename elfcpp::Elf_types<32>::Elf_Swxword addend)
+  { Mips_reloc_types<sh_type_, 32, big_endian>::set_reloc_addend(to, addend); }
+
+  // Return the size of the addend of the relocation (only used for SHT_REL).
+  static unsigned int
+  get_size_for_reloc(unsigned int r_type, Relobj* obj)
+  { return mips_get_size_for_reloc(r_type, obj); }
+};
+
+template<int sh_type_, bool big_endian>
+class Mips_classify_reloc<sh_type_, 64, big_endian> :
+    public gold::Default_classify_reloc<sh_type_, 64, big_endian>
+{
+ public:
+  typedef typename Mips_reloc_types<sh_type_, 64, big_endian>::Reloc
+      Reltype;
+  typedef typename Mips_reloc_types<sh_type_, 64, big_endian>::Reloc_write
+      Reltype_write;
+
+  // Return the symbol referred to by the relocation.
+  static inline unsigned int
+  get_r_sym(const Reltype* reloc)
+  { return reloc->get_r_sym(); }
+
+  // Return the type of the relocation.
+  static inline unsigned int
+  get_r_type(const Reltype* reloc)
+  { return reloc->get_r_type(); }
+
+  // Return the explicit addend of the relocation (return 0 for SHT_REL).
+  static inline typename elfcpp::Elf_types<64>::Elf_Swxword
+  get_r_addend(const Reltype* reloc)
+  { return Mips_reloc_types<sh_type_, 64, big_endian>::get_r_addend(reloc); }
+
+  // Write the r_info field to a new reloc, using the r_info field from
+  // the original reloc, replacing the r_sym field with R_SYM.
+  static inline void
+  put_r_info(Reltype_write* new_reloc, Reltype* reloc, unsigned int r_sym)
+  {
+    new_reloc->put_r_sym(r_sym);
+    new_reloc->put_r_ssym(reloc->get_r_ssym());
+    new_reloc->put_r_type3(reloc->get_r_type3());
+    new_reloc->put_r_type2(reloc->get_r_type2());
+    new_reloc->put_r_type(reloc->get_r_type());
+  }
+
+  // Write the r_addend field to a new reloc.
+  static inline void
+  put_r_addend(Reltype_write* to,
+              typename elfcpp::Elf_types<64>::Elf_Swxword addend)
+  { Mips_reloc_types<sh_type_, 64, big_endian>::set_reloc_addend(to, addend); }
+
+  // Return the size of the addend of the relocation (only used for SHT_REL).
+  static unsigned int
+  get_size_for_reloc(unsigned int r_type, Relobj* obj)
+  { return mips_get_size_for_reloc(r_type, obj); }
+};
+
 template<int size, bool big_endian>
 class Target_mips : public Sized_target<size, big_endian>
 {
@@ -2869,6 +3046,10 @@ class Target_mips : public Sized_target<size, big_endian>
     Reloca_section;
   typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype32;
   typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
+  typedef typename Mips_reloc_types<elfcpp::SHT_REL, size, big_endian>::Reloc
+      Reltype;
+  typedef typename Mips_reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+      Relatype;
 
  public:
   Target_mips(const Target::Target_info* info = &mips_info)
@@ -2954,6 +3135,21 @@ class Target_mips : public Sized_target<size, big_endian>
                           const unsigned char* plocal_symbols,
                           Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+                  Layout* layout,
+                  Sized_relobj_file<size, big_endian>* object,
+                  unsigned int data_shndx,
+                  unsigned int sh_type,
+                  const unsigned char* prelocs,
+                  size_t reloc_count,
+                  Output_section* output_section,
+                  bool needs_special_offset_handling,
+                  size_t local_symbol_count,
+                  const unsigned char* plocal_syms,
+                  Relocatable_relocs* rr);
+
   // Emit relocations for a section.
   void
   relocate_relocs(const Relocate_info<size, big_endian>*,
@@ -2963,7 +3159,6 @@ class Target_mips : public Sized_target<size, big_endian>
                   Output_section* output_section,
                   typename elfcpp::Elf_types<size>::Elf_Off
                     offset_in_output_section,
-                  const Relocatable_relocs*,
                   unsigned char* view,
                   Mips_address view_address,
                   section_size_type view_size,
@@ -3164,6 +3359,17 @@ class Target_mips : public Sized_target<size, big_endian>
   use_32bit_micromips_instructions() const
   { return this->insn32_; }
 
+  // Return the r_sym field from a relocation.
+  unsigned int
+  get_r_sym(const unsigned char* preloc) const
+  {
+    // Since REL and RELA relocs share the same structure through
+    // the r_info field, we can just use REL here.
+    Reltype rel(preloc);
+    return Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+       get_r_sym(&rel);
+  }
+
  protected:
   // Return the value to use for a dynamic symbol which requires special
   // treatment.  This is how we support equality comparisons of function
@@ -3268,7 +3474,7 @@ class Target_mips : public Sized_target<size, big_endian>
           Sized_relobj_file<size, big_endian>* object,
           unsigned int data_shndx,
           Output_section* output_section,
-          const elfcpp::Rel<size, big_endian>& reloc, unsigned int r_type,
+          const Reltype& reloc, unsigned int r_type,
           const elfcpp::Sym<size, big_endian>& lsym,
           bool is_discarded);
 
@@ -3277,7 +3483,7 @@ class Target_mips : public Sized_target<size, big_endian>
           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 Relatype& reloc, unsigned int r_type,
           const elfcpp::Sym<size, big_endian>& lsym,
           bool is_discarded);
 
@@ -3286,8 +3492,8 @@ class Target_mips : public Sized_target<size, big_endian>
           Sized_relobj_file<size, big_endian>* object,
           unsigned int data_shndx,
           Output_section* output_section,
-          const elfcpp::Rela<size, big_endian>* rela,
-          const elfcpp::Rel<size, big_endian>* rel,
+          const Relatype* rela,
+          const Reltype* rel,
           unsigned int rel_type,
           unsigned int r_type,
           const elfcpp::Sym<size, big_endian>& lsym,
@@ -3298,7 +3504,7 @@ class Target_mips : public Sized_target<size, big_endian>
            Sized_relobj_file<size, big_endian>* object,
            unsigned int data_shndx,
            Output_section* output_section,
-           const elfcpp::Rel<size, big_endian>& reloc, unsigned int r_type,
+           const Reltype& reloc, unsigned int r_type,
            Symbol* gsym);
 
     inline void
@@ -3306,7 +3512,7 @@ class Target_mips : public Sized_target<size, big_endian>
            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 Relatype& reloc, unsigned int r_type,
            Symbol* gsym);
 
     inline void
@@ -3314,8 +3520,8 @@ class Target_mips : public Sized_target<size, big_endian>
            Sized_relobj_file<size, big_endian>* object,
            unsigned int data_shndx,
            Output_section* output_section,
-           const elfcpp::Rela<size, big_endian>* rela,
-           const elfcpp::Rel<size, big_endian>* rel,
+           const Relatype* rela,
+           const Reltype* rel,
            unsigned int rel_type,
            unsigned int r_type,
            Symbol* gsym);
@@ -3326,7 +3532,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                         Sized_relobj_file<size, big_endian>*,
                                         unsigned int,
                                         Output_section*,
-                                        const elfcpp::Rel<size, big_endian>&,
+                                        const Reltype&,
                                         unsigned int,
                                         const elfcpp::Sym<size, big_endian>&)
     { return false; }
@@ -3337,7 +3543,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                          Sized_relobj_file<size, big_endian>*,
                                          unsigned int,
                                          Output_section*,
-                                         const elfcpp::Rel<size, big_endian>&,
+                                         const Reltype&,
                                          unsigned int, Symbol*)
     { return false; }
 
@@ -3347,7 +3553,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                         Sized_relobj_file<size, big_endian>*,
                                         unsigned int,
                                         Output_section*,
-                                        const elfcpp::Rela<size, big_endian>&,
+                                        const Relatype&,
                                         unsigned int,
                                         const elfcpp::Sym<size, big_endian>&)
     { return false; }
@@ -3358,7 +3564,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                          Sized_relobj_file<size, big_endian>*,
                                          unsigned int,
                                          Output_section*,
-                                         const elfcpp::Rela<size, big_endian>&,
+                                         const Relatype&,
                                          unsigned int, Symbol*)
     { return false; }
    private:
@@ -3391,45 +3597,10 @@ class Target_mips : 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_mips*,
-             Output_section*, size_t relnum,
-             const elfcpp::Rela<size, big_endian>*,
-             const elfcpp::Rel<size, big_endian>*,
-             unsigned int,
-             unsigned int,  const Sized_symbol<size>*,
-             const Symbol_value<size>*,
-             unsigned char*,
-             Mips_address,
-             section_size_type);
-
-    inline bool
-    relocate(const Relocate_info<size, big_endian>*, Target_mips*,
-             Output_section*, size_t relnum,
-             const elfcpp::Rel<size, big_endian>&,
-             unsigned int, const Sized_symbol<size>*,
-             const Symbol_value<size>*,
-             unsigned char*,
-             Mips_address,
-             section_size_type);
-
-    inline bool
-    relocate(const Relocate_info<size, big_endian>*, Target_mips*,
-             Output_section*, size_t relnum,
-             const elfcpp::Rela<size, big_endian>&,
-             unsigned int, const Sized_symbol<size>*,
-             const Symbol_value<size>*,
-             unsigned char*,
-             Mips_address,
-             section_size_type);
-  };
-
-  // 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*);
+    relocate(const Relocate_info<size, big_endian>*, unsigned int,
+            Target_mips*, Output_section*, size_t, const unsigned char*,
+            const Sized_symbol<size>*, const Symbol_value<size>*,
+            unsigned char*, Mips_address, section_size_type);
   };
 
   // This POD class holds the dynamic relocations that should be emitted instead
@@ -3599,12 +3770,16 @@ class Target_mips : public Sized_target<size, big_endian>
   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::Rel<size, big_endian>& reloc)
+             Symbol* sym, const Reltype& reloc)
   {
+    unsigned int r_type =
+       Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+         get_r_type(&reloc);
     this->copy_relocs_.copy_reloc(symtab, layout,
                                   symtab->get_sized_symbol<size>(sym),
                                   object, shndx, output_section,
-                                  reloc, this->rel_dyn_section(layout));
+                                 r_type, reloc.get_r_offset(), 0,
+                                  this->rel_dyn_section(layout));
   }
 
   void
@@ -3711,7 +3886,7 @@ class Target_mips : public Sized_target<size, big_endian>
 
   // Information about this specific target which we pass to the
   // general Target structure.
-  static Target::Target_info mips_info;
+  static const Target::Target_info mips_info;
   // The GOT section.
   Mips_output_data_got<size, big_endian>* got_;
   // gp symbol.  It has the value of .got + 0x7FF0.
@@ -3749,7 +3924,6 @@ class Target_mips : public Sized_target<size, big_endian>
   bool insn32_;
 };
 
-
 // Helper structure for R_MIPS*_HI16/LO16 and R_MIPS*_GOT16/LO16 relocations.
 // It records high part of the relocation pair.
 
@@ -3760,11 +3934,11 @@ struct reloc_high
 
   reloc_high(unsigned char* _view, const Mips_relobj<size, big_endian>* _object,
              const Symbol_value<size>* _psymval, Mips_address _addend,
-             unsigned int _r_type, bool _extract_addend,
+             unsigned int _r_type, unsigned int _r_sym, bool _extract_addend,
              Mips_address _address = 0, bool _gp_disp = false)
     : view(_view), object(_object), psymval(_psymval), addend(_addend),
-      r_type(_r_type), extract_addend(_extract_addend), address(_address),
-      gp_disp(_gp_disp)
+      r_type(_r_type), r_sym(_r_sym), extract_addend(_extract_addend),
+      address(_address), gp_disp(_gp_disp)
   { }
 
   unsigned char* view;
@@ -3772,6 +3946,7 @@ struct reloc_high
   const Symbol_value<size>* psymval;
   Mips_address addend;
   unsigned int r_type;
+  unsigned int r_sym;
   bool extract_addend;
   Mips_address address;
   bool gp_disp;
@@ -4265,11 +4440,12 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   relhi16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
           const Symbol_value<size>* psymval, Mips_address addend,
           Mips_address address, bool gp_disp, unsigned int r_type,
-          bool extract_addend)
+          unsigned int r_sym, bool extract_addend)
   {
     // Record the relocation.  It will be resolved when we find lo16 part.
     hi16_relocs.push_back(reloc_high<size, big_endian>(view, object, psymval,
-                          addend, r_type, extract_addend, address, gp_disp));
+                          addend, r_type, r_sym, extract_addend, address,
+                          gp_disp));
     return This::STATUS_OKAY;
   }
 
@@ -4330,11 +4506,11 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   relgot16_local(unsigned char* view,
                  const Mips_relobj<size, big_endian>* object,
                  const Symbol_value<size>* psymval, Mips_address addend_a,
-                 bool extract_addend, unsigned int r_type)
+                 bool extract_addend, unsigned int r_type, unsigned int r_sym)
   {
     // Record the relocation.  It will be resolved when we find lo16 part.
     got16_relocs.push_back(reloc_high<size, big_endian>(view, object, psymval,
-                           addend_a, r_type, extract_addend));
+                           addend_a, r_type, r_sym, extract_addend));
     return This::STATUS_OKAY;
   }
 
@@ -4376,7 +4552,7 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
           const Mips_relobj<size, big_endian>* object,
           const Symbol_value<size>* psymval, Mips_address addend_a,
           bool extract_addend, Mips_address address, bool is_gp_disp,
-          unsigned int r_type)
+          unsigned int r_type, unsigned int r_sym)
   {
     mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
@@ -4391,7 +4567,8 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
     while (it != hi16_relocs.end())
       {
         reloc_high<size, big_endian> hi16 = *it;
-        if (hi16.psymval->value(hi16.object, 0) == psymval->value(object, 0))
+        if (hi16.r_sym == r_sym
+            && is_matching_lo16_reloc(hi16.r_type, r_type))
           {
             if (do_relhi16(hi16.view, hi16.object, hi16.psymval, hi16.addend,
                            hi16.address, hi16.gp_disp, hi16.r_type,
@@ -4410,7 +4587,8 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
     while (it2 != got16_relocs.end())
       {
         reloc_high<size, big_endian> got16 = *it2;
-        if (got16.psymval->value(got16.object, 0) == psymval->value(object, 0))
+        if (got16.r_sym == r_sym
+            && is_matching_lo16_reloc(got16.r_type, r_type))
           {
             if (do_relgot16_local(got16.view, got16.object, got16.psymval,
                                   got16.addend, got16.r_type,
@@ -6157,7 +6335,7 @@ const uint32_t Mips_output_data_plt<size, big_endian>::plt0_entry_o32[] =
   0x8f990000,         // lw $25, %lo(&GOTPLT[0])($28)
   0x279c0000,         // addiu $28, $28, %lo(&GOTPLT[0])
   0x031cc023,         // subu $24, $24, $28
-  0x03e07821,         // move $15, $31        # 32-bit move (addu)
+  0x03e07825,         // or $15, $31, zero
   0x0018c082,         // srl $24, $24, 2
   0x0320f809,         // jalr $25
   0x2718fffe          // subu $24, $24, 2
@@ -6172,7 +6350,7 @@ const uint32_t Mips_output_data_plt<size, big_endian>::plt0_entry_n32[] =
   0x8dd90000,         // lw $25, %lo(&GOTPLT[0])($14)
   0x25ce0000,         // addiu $14, $14, %lo(&GOTPLT[0])
   0x030ec023,         // subu $24, $24, $14
-  0x03e07821,         // move $15, $31        # 32-bit move (addu)
+  0x03e07825,         // or $15, $31, zero
   0x0018c082,         // srl $24, $24, 2
   0x0320f809,         // jalr $25
   0x2718fffe          // subu $24, $24, 2
@@ -6187,7 +6365,7 @@ const uint32_t Mips_output_data_plt<size, big_endian>::plt0_entry_n64[] =
   0xddd90000,         // ld $25, %lo(&GOTPLT[0])($14)
   0x25ce0000,         // addiu $14, $14, %lo(&GOTPLT[0])
   0x030ec023,         // subu $24, $24, $14
-  0x03e07821,         // move $15, $31        # 64-bit move (daddu)
+  0x03e07825,         // or $15, $31, zero
   0x0018c0c2,         // srl $24, $24, 3
   0x0320f809,         // jalr $25
   0x2718fffe          // subu $24, $24, 2
@@ -6224,7 +6402,7 @@ plt0_entry_micromips32_o32[] =
   0xff3c, 0x0000,      // lw $25, %lo(&GOTPLT[0])($28)
   0x339c, 0x0000,      // addiu $28, $28, %lo(&GOTPLT[0])
   0x0398, 0xc1d0,      // subu $24, $24, $28
-  0x001f, 0x7950,      // move $15, $31
+  0x001f, 0x7a90,      // or $15, $31, zero
   0x0318, 0x1040,      // srl $24, $24, 2
   0x03f9, 0x0f3c,      // jalr $25
   0x3318, 0xfffe       // subu $24, $24, 2
@@ -6626,7 +6804,7 @@ const uint32_t
 Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_1[4] =
 {
   0x8f998010,         // lw t9,0x8010(gp)
-  0x03e07821,         // addu t7,ra,zero
+  0x03e07825,         // or t7,ra,zero
   0x0320f809,         // jalr t9,ra
   0x24180000          // addiu t8,zero,DYN_INDEX sign extended
 };
@@ -6638,7 +6816,7 @@ const uint32_t
 Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_1_n64[4] =
 {
   0xdf998010,         // ld t9,0x8010(gp)
-  0x03e0782d,         // daddu t7,ra,zero
+  0x03e07825,         // or t7,ra,zero
   0x0320f809,         // jalr t9,ra
   0x64180000          // daddiu t8,zero,DYN_INDEX sign extended
 };
@@ -6650,7 +6828,7 @@ const uint32_t
 Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_2[4] =
 {
   0x8f998010,         // lw t9,0x8010(gp)
-  0x03e07821,         // addu t7,ra,zero
+  0x03e07825,         // or t7,ra,zero
   0x0320f809,         // jalr t9,ra
   0x34180000          // ori t8,zero,DYN_INDEX unsigned
 };
@@ -6662,7 +6840,7 @@ const uint32_t
 Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_2_n64[4] =
 {
   0xdf998010,         // ld t9,0x8010(gp)
-  0x03e0782d,         // daddu t7,ra,zero
+  0x03e07825,         // or t7,ra,zero
   0x0320f809,         // jalr t9,ra
   0x34180000          // ori t8,zero,DYN_INDEX unsigned
 };
@@ -6673,7 +6851,7 @@ template<int size, bool big_endian>
 const uint32_t Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_big[5] =
 {
   0x8f998010,         // lw t9,0x8010(gp)
-  0x03e07821,         // addu t7,ra,zero
+  0x03e07825,         // or t7,ra,zero
   0x3c180000,         // lui t8,DYN_INDEX
   0x0320f809,         // jalr t9,ra
   0x37180000          // ori t8,t8,DYN_INDEX
@@ -6686,7 +6864,7 @@ const uint32_t
 Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_big_n64[5] =
 {
   0xdf998010,         // ld t9,0x8010(gp)
-  0x03e0782d,         // daddu t7,ra,zero
+  0x03e07825,         // or t7,ra,zero
   0x3c180000,         // lui t8,DYN_INDEX
   0x0320f809,         // jalr t9,ra
   0x37180000          // ori t8,t8,DYN_INDEX
@@ -6783,7 +6961,7 @@ Mips_output_data_mips_stubs<size, big_endian>::
 lazy_stub_micromips32_normal_1[] =
 {
   0xff3c, 0x8010,     // lw t9,0x8010(gp)
-  0x001f, 0x7950,     // addu t7,ra,zero
+  0x001f, 0x7a90,     // or t7,ra,zero
   0x03f9, 0x0f3c,     // jalr ra,t9
   0x3300, 0x0000      // addiu t8,zero,DYN_INDEX sign extended
 };
@@ -6797,7 +6975,7 @@ Mips_output_data_mips_stubs<size, big_endian>::
 lazy_stub_micromips32_normal_1_n64[] =
 {
   0xdf3c, 0x8010,     // ld t9,0x8010(gp)
-  0x581f, 0x7950,     // daddu t7,ra,zero
+  0x001f, 0x7a90,     // or t7,ra,zero
   0x03f9, 0x0f3c,     // jalr ra,t9
   0x5f00, 0x0000      // daddiu t8,zero,DYN_INDEX sign extended
 };
@@ -6811,7 +6989,7 @@ Mips_output_data_mips_stubs<size, big_endian>::
 lazy_stub_micromips32_normal_2[] =
 {
   0xff3c, 0x8010,     // lw t9,0x8010(gp)
-  0x001f, 0x7950,     // addu t7,ra,zero
+  0x001f, 0x7a90,     // or t7,ra,zero
   0x03f9, 0x0f3c,     // jalr ra,t9
   0x5300, 0x0000      // ori t8,zero,DYN_INDEX unsigned
 };
@@ -6825,7 +7003,7 @@ Mips_output_data_mips_stubs<size, big_endian>::
 lazy_stub_micromips32_normal_2_n64[] =
 {
   0xdf3c, 0x8010,     // ld t9,0x8010(gp)
-  0x581f, 0x7950,     // daddu t7,ra,zero
+  0x001f, 0x7a90,     // or t7,ra,zero
   0x03f9, 0x0f3c,     // jalr ra,t9
   0x5300, 0x0000      // ori t8,zero,DYN_INDEX unsigned
 };
@@ -6837,7 +7015,7 @@ const uint32_t
 Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_micromips32_big[] =
 {
   0xff3c, 0x8010,     // lw t9,0x8010(gp)
-  0x001f, 0x7950,     // addu t7,ra,zero
+  0x001f, 0x7a90,     // or t7,ra,zero
   0x41b8, 0x0000,     // lui t8,DYN_INDEX
   0x03f9, 0x0f3c,     // jalr ra,t9
   0x5318, 0x0000      // ori t8,t8,DYN_INDEX
@@ -6850,7 +7028,7 @@ const uint32_t
 Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_micromips32_big_n64[] =
 {
   0xdf3c, 0x8010,     // ld t9,0x8010(gp)
-  0x581f, 0x7950,     // daddu t7,ra,zero
+  0x001f, 0x7a90,     // or t7,ra,zero
   0x41b8, 0x0000,     // lui t8,DYN_INDEX
   0x03f9, 0x0f3c,     // jalr ra,t9
   0x5318, 0x0000      // ori t8,t8,DYN_INDEX
@@ -7530,10 +7708,10 @@ Target_mips<size, big_endian>::gc_process_relocs(
                         const unsigned char* plocal_symbols)
 {
   typedef Target_mips<size, big_endian> Mips;
-  typedef typename Target_mips<size, big_endian>::Scan Scan;
+  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
 
-  gold::gc_process_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan,
-                          typename Target_mips::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -7565,34 +7743,43 @@ Target_mips<size, big_endian>::scan_relocs(
                         const unsigned char* plocal_symbols)
 {
   typedef Target_mips<size, big_endian> Mips;
-  typedef typename Target_mips<size, big_endian>::Scan Scan;
 
   if (sh_type == elfcpp::SHT_REL)
-    gold::scan_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan>(
-      symtab,
-      layout,
-      this,
-      object,
-      data_shndx,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      local_symbol_count,
-      plocal_symbols);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+         Classify_reloc;
+
+      gold::scan_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
+       symtab,
+       layout,
+       this,
+       object,
+       data_shndx,
+       prelocs,
+       reloc_count,
+       output_section,
+       needs_special_offset_handling,
+       local_symbol_count,
+       plocal_symbols);
+    }
   else if (sh_type == elfcpp::SHT_RELA)
-    gold::scan_relocs<size, big_endian, Mips, elfcpp::SHT_RELA, Scan>(
-      symtab,
-      layout,
-      this,
-      object,
-      data_shndx,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      local_symbol_count,
-      plocal_symbols);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+         Classify_reloc;
+
+      gold::scan_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
+       symtab,
+       layout,
+       this,
+       object,
+       data_shndx,
+       prelocs,
+       reloc_count,
+       output_section,
+       needs_special_offset_handling,
+       local_symbol_count,
+       plocal_symbols);
+    }
 }
 
 template<int size, bool big_endian>
@@ -8247,41 +8434,48 @@ Target_mips<size, big_endian>::relocate_section(
   typedef typename Target_mips<size, big_endian>::Relocate Mips_relocate;
 
   if (sh_type == elfcpp::SHT_REL)
-    gold::relocate_section<size, big_endian, Mips, elfcpp::SHT_REL,
-      Mips_relocate, gold::Default_comdat_behavior>(
-      relinfo,
-      this,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      view,
-      address,
-      view_size,
-      reloc_symbol_changes);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+         Classify_reloc;
+
+      gold::relocate_section<size, big_endian, Mips, Mips_relocate,
+                            gold::Default_comdat_behavior, Classify_reloc>(
+       relinfo,
+       this,
+       prelocs,
+       reloc_count,
+       output_section,
+       needs_special_offset_handling,
+       view,
+       address,
+       view_size,
+       reloc_symbol_changes);
+    }
   else if (sh_type == elfcpp::SHT_RELA)
-    gold::relocate_section<size, big_endian, Mips, elfcpp::SHT_RELA,
-      Mips_relocate, gold::Default_comdat_behavior>(
-      relinfo,
-      this,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      view,
-      address,
-      view_size,
-     reloc_symbol_changes);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+         Classify_reloc;
+
+      gold::relocate_section<size, big_endian, Mips, Mips_relocate,
+                            gold::Default_comdat_behavior, Classify_reloc>(
+       relinfo,
+       this,
+       prelocs,
+       reloc_count,
+       output_section,
+       needs_special_offset_handling,
+       view,
+       address,
+       view_size,
+       reloc_symbol_changes);
+    }
 }
 
 // Return the size of a relocation while scanning during a relocatable
 // link.
 
-template<int size, bool big_endian>
 unsigned int
-Target_mips<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
-    unsigned int r_type,
-    Relobj* object)
+mips_get_size_for_reloc(unsigned int r_type, Relobj* object)
 {
   switch (r_type)
     {
@@ -8364,13 +8558,14 @@ Target_mips<size, big_endian>::scan_relocatable_relocs(
                         const unsigned char* plocal_symbols,
                         Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_REL);
+  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
+  typedef Mips_scan_relocatable_relocs<big_endian, Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef Mips_scan_relocatable_relocs<big_endian, elfcpp::SHT_REL,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_REL,
-    Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -8384,6 +8579,45 @@ Target_mips<size, big_endian>::scan_relocatable_relocs(
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_mips<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 Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_REL);
+
+  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>
@@ -8396,22 +8630,23 @@ Target_mips<size, big_endian>::relocate_relocs(
                         Output_section* output_section,
                         typename elfcpp::Elf_types<size>::Elf_Off
                           offset_in_output_section,
-                        const Relocatable_relocs* rr,
                         unsigned char* view,
                         Mips_address view_address,
                         section_size_type view_size,
                         unsigned char* reloc_view,
                         section_size_type reloc_view_size)
 {
+  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::relocate_relocs<size, big_endian, elfcpp::SHT_REL>(
+  gold::relocate_relocs<size, big_endian, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
     output_section,
     offset_in_output_section,
-    rr,
     view,
     view_address,
     view_size,
@@ -8572,8 +8807,8 @@ Target_mips<size, big_endian>::Scan::local(
                         Sized_relobj_file<size, big_endian>* object,
                         unsigned int data_shndx,
                         Output_section* output_section,
-                        const elfcpp::Rela<size, big_endian>* rela,
-                        const elfcpp::Rel<size, big_endian>* rel,
+                        const Relatype* rela,
+                        const Reltype* rel,
                         unsigned int rel_type,
                         unsigned int r_type,
                         const elfcpp::Sym<size, big_endian>& lsym,
@@ -8583,23 +8818,24 @@ Target_mips<size, big_endian>::Scan::local(
     return;
 
   Mips_address r_offset;
-  typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+  unsigned int r_sym;
   typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
 
   if (rel_type == elfcpp::SHT_RELA)
     {
       r_offset = rela->get_r_offset();
-      r_info = rela->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+         get_r_sym(rela);
       r_addend = rela->get_r_addend();
     }
   else
     {
       r_offset = rel->get_r_offset();
-      r_info = rel->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+         get_r_sym(rel);
       r_addend = 0;
     }
 
-  unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
   Mips_relobj<size, big_endian>* mips_obj =
     Mips_relobj<size, big_endian>::as_mips_relobj(object);
 
@@ -8677,7 +8913,6 @@ Target_mips<size, big_endian>::Scan::local(
       // R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
       Mips_output_data_got<size, big_endian>* got =
         target->got_section(symtab, layout);
-      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
       got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U);
     }
 
@@ -8812,7 +9047,6 @@ Target_mips<size, big_endian>::Scan::local(
             // executable), we need to create a dynamic relocation for
             // this location.
             Reloc_section* rel_dyn = target->rel_dyn_section(layout);
-            unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
             rel_dyn->add_symbolless_local_addend(object, r_sym,
                                                  elfcpp::R_MIPS_REL32,
                                                  output_section, data_shndx,
@@ -8831,7 +9065,6 @@ Target_mips<size, big_endian>::Scan::local(
     case elfcpp::R_MIPS16_TLS_GD:
     case elfcpp::R_MICROMIPS_TLS_GD:
       {
-        unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
         bool output_is_shared = parameters->options().shared();
         const tls::Tls_optimization optimized_type
             = Target_mips<size, big_endian>::optimize_tls_reloc(
@@ -8951,7 +9184,7 @@ Target_mips<size, big_endian>::Scan::local(
                         Sized_relobj_file<size, big_endian>* object,
                         unsigned int data_shndx,
                         Output_section* output_section,
-                        const elfcpp::Rel<size, big_endian>& reloc,
+                        const Reltype& reloc,
                         unsigned int r_type,
                         const elfcpp::Sym<size, big_endian>& lsym,
                         bool is_discarded)
@@ -8966,7 +9199,7 @@ Target_mips<size, big_endian>::Scan::local(
     object,
     data_shndx,
     output_section,
-    (const elfcpp::Rela<size, big_endian>*) NULL,
+    (const Relatype*) NULL,
     &reloc,
     elfcpp::SHT_REL,
     r_type,
@@ -8983,7 +9216,7 @@ Target_mips<size, big_endian>::Scan::local(
                         Sized_relobj_file<size, big_endian>* object,
                         unsigned int data_shndx,
                         Output_section* output_section,
-                        const elfcpp::Rela<size, big_endian>& reloc,
+                        const Relatype& reloc,
                         unsigned int r_type,
                         const elfcpp::Sym<size, big_endian>& lsym,
                         bool is_discarded)
@@ -8999,7 +9232,7 @@ Target_mips<size, big_endian>::Scan::local(
     data_shndx,
     output_section,
     &reloc,
-    (const elfcpp::Rel<size, big_endian>*) NULL,
+    (const Reltype*) NULL,
     elfcpp::SHT_RELA,
     r_type,
     lsym, is_discarded);
@@ -9016,30 +9249,31 @@ Target_mips<size, big_endian>::Scan::global(
                                 Sized_relobj_file<size, big_endian>* object,
                                 unsigned int data_shndx,
                                 Output_section* output_section,
-                                const elfcpp::Rela<size, big_endian>* rela,
-                                const elfcpp::Rel<size, big_endian>* rel,
+                                const Relatype* rela,
+                                const Reltype* rel,
                                 unsigned int rel_type,
                                 unsigned int r_type,
                                 Symbol* gsym)
 {
   Mips_address r_offset;
-  typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+  unsigned int r_sym;
   typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
 
   if (rel_type == elfcpp::SHT_RELA)
     {
       r_offset = rela->get_r_offset();
-      r_info = rela->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+         get_r_sym(rela);
       r_addend = rela->get_r_addend();
     }
   else
     {
       r_offset = rel->get_r_offset();
-      r_info = rel->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+         get_r_sym(rel);
       r_addend = 0;
     }
 
-  unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
   Mips_relobj<size, big_endian>* mips_obj =
     Mips_relobj<size, big_endian>::as_mips_relobj(object);
   Mips_symbol<size>* mips_sym = Mips_symbol<size>::as_mips_sym(gsym);
@@ -9456,7 +9690,7 @@ Target_mips<size, big_endian>::Scan::global(
                                 Sized_relobj_file<size, big_endian>* object,
                                 unsigned int data_shndx,
                                 Output_section* output_section,
-                                const elfcpp::Rela<size, big_endian>& reloc,
+                                const Relatype& reloc,
                                 unsigned int r_type,
                                 Symbol* gsym)
 {
@@ -9468,7 +9702,7 @@ Target_mips<size, big_endian>::Scan::global(
     data_shndx,
     output_section,
     &reloc,
-    (const elfcpp::Rel<size, big_endian>*) NULL,
+    (const Reltype*) NULL,
     elfcpp::SHT_RELA,
     r_type,
     gsym);
@@ -9483,7 +9717,7 @@ Target_mips<size, big_endian>::Scan::global(
                                 Sized_relobj_file<size, big_endian>* object,
                                 unsigned int data_shndx,
                                 Output_section* output_section,
-                                const elfcpp::Rel<size, big_endian>& reloc,
+                                const Reltype& reloc,
                                 unsigned int r_type,
                                 Symbol* gsym)
 {
@@ -9494,7 +9728,7 @@ Target_mips<size, big_endian>::Scan::global(
     object,
     data_shndx,
     output_section,
-    (const elfcpp::Rela<size, big_endian>*) NULL,
+    (const Relatype*) NULL,
     &reloc,
     elfcpp::SHT_REL,
     r_type,
@@ -9556,13 +9790,11 @@ template<int size, bool big_endian>
 inline bool
 Target_mips<size, big_endian>::Relocate::relocate(
                         const Relocate_info<size, big_endian>* relinfo,
+                        unsigned int rel_type,
                         Target_mips* target,
                         Output_section* output_section,
                         size_t relnum,
-                        const elfcpp::Rela<size, big_endian>* rela,
-                        const elfcpp::Rel<size, big_endian>* rel,
-                        unsigned int rel_type,
-                        unsigned int r_type,
+                        const unsigned char* preloc,
                         const Sized_symbol<size>* gsym,
                         const Symbol_value<size>* psymval,
                         unsigned char* view,
@@ -9570,19 +9802,29 @@ Target_mips<size, big_endian>::Relocate::relocate(
                         section_size_type)
 {
   Mips_address r_offset;
-  typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+  unsigned int r_sym;
+  unsigned int r_type;
   typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
 
   if (rel_type == elfcpp::SHT_RELA)
     {
-      r_offset = rela->get_r_offset();
-      r_info = rela->get_r_info();
-      r_addend = rela->get_r_addend();
+      const Relatype rela(preloc);
+      r_offset = rela.get_r_offset();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+         get_r_sym(&rela);
+      r_type = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+         get_r_type(&rela);
+      r_addend = rela.get_r_addend();
     }
   else
     {
-      r_offset = rel->get_r_offset();
-      r_info = rel->get_r_info();
+
+      const Reltype rel(preloc);
+      r_offset = rel.get_r_offset();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+         get_r_sym(&rel);
+      r_type = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+         get_r_type(&rel);
       r_addend = 0;
     }
 
@@ -9590,9 +9832,8 @@ Target_mips<size, big_endian>::Relocate::relocate(
   typename Reloc_funcs::Status reloc_status = Reloc_funcs::STATUS_OKAY;
 
   Mips_relobj<size, big_endian>* object =
-    Mips_relobj<size, big_endian>::as_mips_relobj(relinfo->object);
+      Mips_relobj<size, big_endian>::as_mips_relobj(relinfo->object);
 
-  unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
   bool target_is_16_bit_code = false;
   bool target_is_micromips_code = false;
   bool cross_mode_jump;
@@ -9907,7 +10148,7 @@ Target_mips<size, big_endian>::Relocate::relocate(
     case elfcpp::R_MIPS16_HI16:
     case elfcpp::R_MICROMIPS_HI16:
       reloc_status = Reloc_funcs::relhi16(view, object, psymval, r_addend,
-                                          address, gp_disp, r_type,
+                                          address, gp_disp, r_type, r_sym,
                                           extract_addend);
       break;
 
@@ -9917,7 +10158,7 @@ Target_mips<size, big_endian>::Relocate::relocate(
     case elfcpp::R_MICROMIPS_HI0_LO16:
       reloc_status = Reloc_funcs::rello16(target, view, object, psymval,
                                           r_addend, extract_addend, address,
-                                          gp_disp, r_type);
+                                          gp_disp, r_type, r_sym);
       break;
 
     case elfcpp::R_MIPS_LITERAL:
@@ -10032,7 +10273,7 @@ Target_mips<size, big_endian>::Relocate::relocate(
       else
         reloc_status = Reloc_funcs::relgot16_local(view, object, psymval,
                                                    r_addend, extract_addend,
-                                                   r_type);
+                                                   r_type, r_sym);
       update_got_entry = changed_symbol_value;
       break;
 
@@ -10181,68 +10422,6 @@ Target_mips<size, big_endian>::Relocate::relocate(
   return true;
 }
 
-template<int size, bool big_endian>
-inline bool
-Target_mips<size, big_endian>::Relocate::relocate(
-                        const Relocate_info<size, big_endian>* relinfo,
-                        Target_mips* target,
-                        Output_section* output_section,
-                        size_t relnum,
-                        const elfcpp::Rela<size, big_endian>& reloc,
-                        unsigned int r_type,
-                        const Sized_symbol<size>* gsym,
-                        const Symbol_value<size>* psymval,
-                        unsigned char* view,
-                        Mips_address address,
-                        section_size_type view_size)
-{
-  return relocate(
-    relinfo,
-    target,
-    output_section,
-    relnum,
-    &reloc,
-    (const elfcpp::Rel<size, big_endian>*) NULL,
-    elfcpp::SHT_RELA,
-    r_type,
-    gsym,
-    psymval,
-    view,
-    address,
-    view_size);
-}
-
-template<int size, bool big_endian>
-inline bool
-Target_mips<size, big_endian>::Relocate::relocate(
-                        const Relocate_info<size, big_endian>* relinfo,
-                        Target_mips* target,
-                        Output_section* output_section,
-                        size_t relnum,
-                        const elfcpp::Rel<size, big_endian>& reloc,
-                        unsigned int r_type,
-                        const Sized_symbol<size>* gsym,
-                        const Symbol_value<size>* psymval,
-                        unsigned char* view,
-                        Mips_address address,
-                        section_size_type view_size)
-{
-  return relocate(
-    relinfo,
-    target,
-    output_section,
-    relnum,
-    (const elfcpp::Rela<size, big_endian>*) NULL,
-    &reloc,
-    elfcpp::SHT_REL,
-    r_type,
-    gsym,
-    psymval,
-    view,
-    address,
-    view_size);
-}
-
 // Get the Reference_flags for a particular relocation.
 
 template<int size, bool big_endian>
@@ -10462,7 +10641,7 @@ Target_mips<size, big_endian>::elf_mips_mach_name(elfcpp::Elf_Word e_flags)
 }
 
 template<int size, bool big_endian>
-Target::Target_info Target_mips<size, big_endian>::mips_info =
+const Target::Target_info Target_mips<size, big_endian>::mips_info =
 {
   size,                 // size
   big_endian,           // is_big_endian
@@ -10485,10 +10664,52 @@ Target::Target_info Target_mips<size, big_endian>::mips_info =
   0,                    // large_common_section_flags
   NULL,                 // attributes_section
   NULL,                 // attributes_vendor
-  "__start"            // entry_symbol_name
+  "__start",           // entry_symbol_name
+  32,                  // hash_entry_size
+};
+
+template<int size, bool big_endian>
+class Target_mips_nacl : public Target_mips<size, big_endian>
+{
+ public:
+  Target_mips_nacl()
+    : Target_mips<size, big_endian>(&mips_nacl_info)
+  { }
+
+ private:
+  static const Target::Target_info mips_nacl_info;
+};
+
+template<int size, bool big_endian>
+const Target::Target_info Target_mips_nacl<size, big_endian>::mips_nacl_info =
+{
+  size,                 // size
+  big_endian,           // is_big_endian
+  elfcpp::EM_MIPS,      // machine_code
+  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
+  "/lib/ld.so.1",       // dynamic_linker
+  0x20000,              // default_text_segment_address
+  0x10000,              // abi_pagesize (overridable by -z max-page-size)
+  0x10000,              // common_pagesize (overridable by -z common-page-size)
+  true,                 // isolate_execinstr
+  0x10000000,           // 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
 };
 
-// The selector for mips object files.
+// Target selector for Mips.  Note this is never instantiated directly.
+// It's only used in Target_selector_mips_nacl, below.
 
 template<int size, bool big_endian>
 class Target_selector_mips : public Target_selector
@@ -10508,10 +10729,23 @@ public:
   { return new Target_mips<size, big_endian>(); }
 };
 
-Target_selector_mips<32, true> target_selector_mips32be;
-Target_selector_mips<32, false> target_selector_mips32;
-Target_selector_mips<64, true> target_selector_mips64be;
-Target_selector_mips<64, false> target_selector_mips64;
+template<int size, bool big_endian>
+class Target_selector_mips_nacl
+  : public Target_selector_nacl<Target_selector_mips<size, big_endian>,
+                                Target_mips_nacl<size, big_endian> >
+{
+ public:
+  Target_selector_mips_nacl()
+    : Target_selector_nacl<Target_selector_mips<size, big_endian>,
+                           Target_mips_nacl<size, big_endian> >(
+        // NaCl currently supports only MIPS32 little-endian.
+        "mipsel", "elf32-tradlittlemips-nacl", "elf32-tradlittlemips-nacl")
+  { }
+};
 
+Target_selector_mips_nacl<32, true> target_selector_mips32;
+Target_selector_mips_nacl<32, false> target_selector_mips32el;
+Target_selector_mips_nacl<64, true> target_selector_mips64;
+Target_selector_mips_nacl<64, false> target_selector_mips64el;
 
 } // End anonymous namespace.
This page took 0.043636 seconds and 4 git commands to generate.