This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v5] gold: Add Mips64 support.


Comments addressed.

Regards,
Vladimir.

ChangeLog -

    * gold/mips.cc (enum Special_relocation_symbol): New enum type.
    (is_readonly_section): New function.
    (eh_reloc): Likewise.
    (Mips_got_entry::is_section_symbol_): New member.
    (Mips_got_entry::is_section_symbol): New method.
    (Mips_got_info::record_local_got_symbol): Add is_section_symbol
    argument.
    (Mips_relobj::mips_elf_options_section_name): New method.
    (Mips_output_data_got::record_local_got_symbol): Add
    is_section_symbol argument, and pass it to 
    Mips_got_info::record_local_got_symbol.
    (Mips_output_data_got::got_offset): Add addend argument, and pass
    it to Relobj::local_got_offset.
    (struct Mips_output_reloc_writer): New type.
    (class Mips_output_data_reloc): New class.
    (Mips_output_data_plt::Reloc_section): Change type to
    Mips_output_data_reloc.
    (Target_mips::Reloc_section): Likewise.
    (Mips_reloc_types::get_r_addend): Remove unsigned from return type.
    (Mips_classify_reloc::get_r_type2): New method.
    (Mips_classify_reloc::get_r_type3): Likewise.
    (Mips_classify_reloc::get_r_ssym): Likewise.
    (Target_mips::Reloca_section): Remove.
    (Relocate::should_apply_static_reloc): Rename from
    should_apply_r_mips_32_reloc.
    (Target_mips::copy_reloc): Replace Reltype parameter with r_type
    and r_offset.
    (Mips_relocate_functions::Valtype): New type.
    (Mips_relocate_functions::Valtype64): New type.
    (Mips_relocate_functions::check_overflow): New method.
    (Mips_relocate_functions::mips_reloc_unshuffle): Move to public
    interface.
    (Mips_relocate_functions::mips_reloc_shuffle): Likewise.
    (Mips_relocate_functions::rel16): Add support for resolving
    relocations for Mips64.
    (Mips_relocate_functions::rel32): Likewise.
    (Mips_relocate_functions::reljalr): Likewise.
    (Mips_relocate_functions::relpc32): Likewise.
    (Mips_relocate_functions::rel26): Likewise.
    (Mips_relocate_functions::relpc16): Likewise.
    (Mips_relocate_functions::relmicromips_pc7_s1): Likewise.
    (Mips_relocate_functions::relmicromips_pc10_s1): Likewise.
    (Mips_relocate_functions::relmicromips_pc16_s1): Likewise.
    (Mips_relocate_functions::do_relhi16): Likewise.
    (Mips_relocate_functions::do_relgot16_local): Likewise.
    (Mips_relocate_functions::rello16): Likewise.
    (Mips_relocate_functions::relgot): Likewise.
    (Mips_relocate_functions::relgotpage): Likewise.
    (Mips_relocate_functions::relgotofst): Likewise.
    (Mips_relocate_functions::relgot_hi16): Likewise.
    (Mips_relocate_functions::relgot_lo16): Likewise.
    (Mips_relocate_functions::relgprel): Likewise.
    (Mips_relocate_functions::relgprel32): Likewise.
    (Mips_relocate_functions::tlsrelhi16): Likewise.
    (Mips_relocate_functions::tlsrello16): Likewise.
    (Mips_relocate_functions::tlsrel32): Likewise.
    (Mips_relocate_functions::relsub): Likewise.
    (Mips_relocate_functions::releh): New method.
    (Mips_relocate_functions::rel64): Likewise.
    (Mips_got_info::record_local_got_symbol): Add is_section_symbol and
    pass it to Mips_got_entry.
    (Mips_got_info::add_local_entries): Pass addend argument
    to code functions, and for STT_SECTION symbols call 
    add_symbolless_local_addend.
    (Mips_got_info::add_tls_entries): Pass addend argument to code
    functions.
    (Mips_relobj::do_read_symbols): Read gp value that was used to
    create object.
    (Mips_output_data_plt::plt_entry): Remove opcode from l[wd]
    instruction. Opcode for instruction will be selected later.
    (Target_mips::gc_process_relocs): Add case for SHT_RELA.
    (Target_mips::scan_relocatable_relocs): Likewise.
    (Target_mips::emit_relocs_scan): Likewise.
    (Target_mips::relocate_relocs): Likewise.
    (Target_mips::do_finalize_sections): Skip objects for merging
    processor specific flags in which all input sections will be
    discarded.
    (mips_get_size_for_reloc): Add case for R_MIPS_EH.
    (Target_mips::Scan::get_reference_flags): Likewise.
    (Target_mips::relocate_special_relocatable): Call rel26 method with
    calculate_only and calculated_value arguments.
    (Target_mips::Scan::local): Add case for R_MIPS_EH. Don't create a
    dynamic relocation against a readonly sections, and pass
    is_section_symbol to Mips_got_info::record_local_got_symbol.
    (Target_mips::Scan::global): Add case for R_MIPS_EH. Don't create a
    dynamic relocation against a readonly sections, and pass r_type
    and r_offset to Target_mips::copy_reloc.
    (Target_mips::Relocate::relocate): Add support for resolving
    relocations for Mips64.
    (Target_mips::mips_info): Add case for Mips64 default dynamic
    linker name.
    (Target_selector_mips): Correct emulation names.
diff --git a/gold/mips.cc b/gold/mips.cc
index 6f66fe9..f905d83 100644
--- a/gold/mips.cc
+++ b/gold/mips.cc
@@ -132,6 +132,31 @@ enum Got_tls_type
   GOT_TLS_IE = 4
 };
 
+// Values found in the r_ssym field of a relocation entry.
+enum Special_relocation_symbol
+{
+  RSS_UNDEF = 0,    // None - value is zero.
+  RSS_GP = 1,       // Value of GP.
+  RSS_GP0 = 2,      // Value of GP in object being relocated.
+  RSS_LOC = 3       // Address of location being relocated.
+};
+
+// Whether the section is readonly.
+static inline bool
+is_readonly_section(Output_section* output_section)
+{
+  elfcpp::Elf_Xword section_flags = output_section->flags();
+  elfcpp::Elf_Word section_type = output_section->type();
+
+  if (section_type == elfcpp::SHT_NOBITS)
+    return false;
+
+  if (section_flags & elfcpp::SHF_WRITE)
+    return false;
+
+  return true;
+}
+
 // Return TRUE if a relocation of type R_TYPE from OBJECT might
 // require an la25 stub.  See also local_pic_function, which determines
 // whether the destination function ever requires a stub.
@@ -232,6 +257,12 @@ got_lo16_reloc(unsigned int r_type)
 }
 
 static inline bool
+eh_reloc(unsigned int r_type)
+{
+  return (r_type == elfcpp::R_MIPS_EH);
+}
+
+static inline bool
 got_disp_reloc(unsigned int r_type)
 {
   return (r_type == elfcpp::R_MIPS_GOT_DISP
@@ -401,13 +432,15 @@ class Mips_got_entry
  public:
   Mips_got_entry(Mips_relobj<size, big_endian>* object, unsigned int symndx,
                  Mips_address addend, unsigned char tls_type,
-                 unsigned int shndx)
-    : object_(object), symndx_(symndx), tls_type_(tls_type), shndx_(shndx)
+                 unsigned int shndx, bool is_section_symbol)
+    : object_(object), symndx_(symndx), tls_type_(tls_type),
+      is_section_symbol_(is_section_symbol), shndx_(shndx)
   { this->d.addend = addend; }
 
   Mips_got_entry(Mips_relobj<size, big_endian>* object, Mips_symbol<size>* sym,
                  unsigned char tls_type)
-    : object_(object), symndx_(-1U), tls_type_(tls_type), shndx_(-1U)
+    : object_(object), symndx_(-1U), tls_type_(tls_type),
+      is_section_symbol_(false), shndx_(-1U)
   { this->d.sym = sym; }
 
   // Return whether this entry is for a local symbol.
@@ -501,6 +534,11 @@ class Mips_got_entry
   shndx() const
   { return this->shndx_; }
 
+  // Return whether this is a STT_SECTION symbol.
+  bool
+  is_section_symbol() const
+  { return this->is_section_symbol_; }
+
  private:
   // The input object that needs the GOT entry.
   Mips_relobj<size, big_endian>* object_;
@@ -522,6 +560,9 @@ class Mips_got_entry
   // symbol entry with r_symndx == 0.
   unsigned char tls_type_;
 
+  // Whether this is a STT_SECTION symbol.
+  bool is_section_symbol_;
+
   // For local GOT entries, section index of the local symbol.
   unsigned int shndx_;
 };
@@ -645,7 +686,8 @@ class Mips_got_info
   void
   record_local_got_symbol(Mips_relobj<size, big_endian>* object,
                           unsigned int symndx, Mips_address addend,
-                          unsigned int r_type, unsigned int shndx);
+                          unsigned int r_type, unsigned int shndx,
+                          bool is_section_symbol);
 
   // Reserve GOT entry for a GOT relocation of type R_TYPE against MIPS_SYM,
   // in OBJECT.  FOR_CALL is true if the caller is only interested in
@@ -1764,6 +1806,10 @@ class Mips_relobj : public Sized_relobj_file<size, big_endian>
   do_read_symbols(Read_symbols_data* sd);
 
  private:
+  // The name of the options section.
+  const char* mips_elf_options_section_name()
+  { return this->is_newabi() ? ".MIPS.options" : ".options"; }
+
   // processor-specific flags in ELF file header.
   elfcpp::Elf_Word processor_specific_flags_;
 
@@ -1861,10 +1907,12 @@ class Mips_output_data_got : public Output_data_got<size, big_endian>
   void
   record_local_got_symbol(Mips_relobj<size, big_endian>* object,
                           unsigned int symndx, Mips_address addend,
-                          unsigned int r_type, unsigned int shndx)
+                          unsigned int r_type, unsigned int shndx,
+                          bool is_section_symbol)
   {
     this->master_got_info_->record_local_got_symbol(object, symndx, addend,
-                                                    r_type, shndx);
+                                                    r_type, shndx,
+                                                    is_section_symbol);
   }
 
   // Reserve GOT entry for a GOT relocation of type R_TYPE against MIPS_SYM,
@@ -2002,8 +2050,9 @@ class Mips_output_data_got : public Output_data_got<size, big_endian>
   // SYMNDX.
   unsigned int
   got_offset(unsigned int symndx, unsigned int got_type,
-             Sized_relobj_file<size, big_endian>* object) const
-  { return object->local_got_offset(symndx, got_type); }
+             Sized_relobj_file<size, big_endian>* object,
+             uint64_t addend) const
+  { return object->local_got_offset(symndx, got_type, addend); }
 
   // Return the offset of TLS LDM entry.  For multi-GOT links, use OBJECT's GOT.
   unsigned int
@@ -2254,14 +2303,73 @@ class Mips_output_data_la25_stub : public Output_section_data
   Unordered_set<Mips_symbol<size>*> symbols_;
 };
 
+// MIPS-specific relocation writer.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+struct Mips_output_reloc_writer;
+
+template<int sh_type, bool dynamic, bool big_endian>
+struct Mips_output_reloc_writer<sh_type, dynamic, 32, big_endian>
+{
+  typedef Output_reloc<sh_type, dynamic, 32, big_endian> Output_reloc_type;
+  typedef std::vector<Output_reloc_type> Relocs;
+
+  static void
+  write(typename Relocs::const_iterator p, unsigned char* pov)
+  { p->write(pov); }
+};
+
+template<int sh_type, bool dynamic, bool big_endian>
+struct Mips_output_reloc_writer<sh_type, dynamic, 64, big_endian>
+{
+  typedef Output_reloc<sh_type, dynamic, 64, big_endian> Output_reloc_type;
+  typedef std::vector<Output_reloc_type> Relocs;
+
+  static void
+  write(typename Relocs::const_iterator p, unsigned char* pov)
+  {
+    elfcpp::Mips64_rel_write<big_endian> orel(pov);
+    orel.put_r_offset(p->get_address());
+    orel.put_r_sym(p->get_symbol_index());
+    orel.put_r_ssym(RSS_UNDEF);
+    orel.put_r_type(p->type());
+    if (p->type() == elfcpp::R_MIPS_REL32)
+      orel.put_r_type2(elfcpp::R_MIPS_64);
+    else
+      orel.put_r_type2(elfcpp::R_MIPS_NONE);
+    orel.put_r_type3(elfcpp::R_MIPS_NONE);
+  }
+};
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+class Mips_output_data_reloc : public Output_data_reloc<sh_type, dynamic,
+                                                        size, big_endian>
+{
+ public:
+  Mips_output_data_reloc(bool sort_relocs)
+    : Output_data_reloc<sh_type, dynamic, size, big_endian>(sort_relocs)
+  { }
+
+ protected:
+  // Write out the data.
+  void
+  do_write(Output_file* of)
+  {
+    typedef Mips_output_reloc_writer<sh_type, dynamic, size,
+        big_endian> Writer;
+    this->template do_write_generic<Writer>(of);
+  }
+};
+
+
 // A class to handle the PLT data.
 
 template<int size, bool big_endian>
 class Mips_output_data_plt : public Output_section_data
 {
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Mips_address;
-  typedef Output_data_reloc<elfcpp::SHT_REL, true,
-                            size, big_endian> Reloc_section;
+  typedef Mips_output_data_reloc<elfcpp::SHT_REL, true,
+                                 size, big_endian> Reloc_section;
 
  public:
   // Create the PLT section.  The ordinary .got section is an argument,
@@ -2872,7 +2980,7 @@ 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
+  static typename elfcpp::Elf_types<32>::Elf_Swxword
   get_r_addend(const Reloc*)
   { return 0; }
 
@@ -2888,7 +2996,7 @@ 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
+  static typename elfcpp::Elf_types<32>::Elf_Swxword
   get_r_addend(const Reloc* reloc)
   { return reloc->get_r_addend(); }
 
@@ -2904,7 +3012,7 @@ 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
+  static typename elfcpp::Elf_types<64>::Elf_Swxword
   get_r_addend(const Reloc*)
   { return 0; }
 
@@ -2920,7 +3028,7 @@ 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
+  static typename elfcpp::Elf_types<64>::Elf_Swxword
   get_r_addend(const Reloc* reloc)
   { return reloc->get_r_addend(); }
 
@@ -2961,6 +3069,18 @@ class Mips_classify_reloc<sh_type_, 32, big_endian> :
   get_r_type(const Reltype* reloc)
   { return elfcpp::elf_r_type<32>(reloc->get_r_info()); }
 
+  static inline unsigned int
+  get_r_type2(const Reltype*)
+  { return 0; }
+
+  static inline unsigned int
+  get_r_type3(const Reltype*)
+  { return 0; }
+
+  static inline unsigned int
+  get_r_ssym(const Reltype*)
+  { return 0; }
+
   // Return the explicit addend of the relocation (return 0 for SHT_REL).
   static inline unsigned int
   get_r_addend(const Reltype* reloc)
@@ -3006,11 +3126,26 @@ class Mips_classify_reloc<sh_type_, 64, big_endian> :
   get_r_sym(const Reltype* reloc)
   { return reloc->get_r_sym(); }
 
-  // Return the type of the relocation.
+  // Return the r_type of the relocation.
   static inline unsigned int
   get_r_type(const Reltype* reloc)
   { return reloc->get_r_type(); }
 
+  // Return the r_type2 of the relocation.
+  static inline unsigned int
+  get_r_type2(const Reltype* reloc)
+  { return reloc->get_r_type2(); }
+
+  // Return the r_type3 of the relocation.
+  static inline unsigned int
+  get_r_type3(const Reltype* reloc)
+  { return reloc->get_r_type3(); }
+
+  // Return the special symbol of the relocation.
+  static inline unsigned int
+  get_r_ssym(const Reltype* reloc)
+  { return reloc->get_r_ssym(); }
+
   // 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)
@@ -3048,10 +3183,8 @@ template<int size, bool big_endian>
 class Target_mips : public Sized_target<size, big_endian>
 {
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Mips_address;
-  typedef Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>
+  typedef Mips_output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>
     Reloc_section;
-  typedef Output_data_reloc<elfcpp::SHT_RELA, true, 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
@@ -3595,12 +3728,12 @@ class Target_mips : public Sized_target<size, big_endian>
     ~Relocate()
     { }
 
-    // Return whether the R_MIPS_32 relocation needs to be applied.
+    // Return whether a R_MIPS_32/R_MIPS_64 relocation needs to be applied.
     inline bool
-    should_apply_r_mips_32_reloc(const Mips_symbol<size>* gsym,
-                                 unsigned int r_type,
-                                 Output_section* output_section,
-                                 Target_mips* target);
+    should_apply_static_reloc(const Mips_symbol<size>* gsym,
+                              unsigned int r_type,
+                              Output_section* output_section,
+                              Target_mips* target);
 
     // Do a relocation.  Return false if the caller should not issue
     // any warnings about this relocation.
@@ -3778,15 +3911,12 @@ 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 Reltype& reloc)
+             Symbol* sym, unsigned int r_type, Mips_address r_offset)
   {
-    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,
-				  r_type, reloc.get_r_offset(), 0,
+                                  r_type, r_offset, 0,
                                   this->rel_dyn_section(layout));
   }
 
@@ -3964,8 +4094,10 @@ template<int size, bool big_endian>
 class Mips_relocate_functions : public Relocate_functions<size, big_endian>
 {
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Mips_address;
+  typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
   typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype16;
   typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype32;
+  typedef typename elfcpp::Swap<64, big_endian>::Valtype Valtype64;
 
  public:
   typedef enum
@@ -3982,6 +4114,29 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static typename std::list<reloc_high<size, big_endian> > hi16_relocs;
   static typename std::list<reloc_high<size, big_endian> > got16_relocs;
 
+  template<int valsize>
+  static inline typename This::Status
+  check_overflow(Valtype value)
+  {
+    if (size == 32)
+      return (Bits<valsize>::has_overflow32(value)
+              ? This::STATUS_OVERFLOW
+              : This::STATUS_OKAY);
+
+    return (Bits<valsize>::has_overflow(value)
+            ? This::STATUS_OVERFLOW
+            : This::STATUS_OKAY);
+  }
+
+  static inline bool
+  should_shuffle_micromips_reloc(unsigned int r_type)
+  {
+    return (micromips_reloc(r_type)
+            && r_type != elfcpp::R_MICROMIPS_PC7_S1
+            && r_type != elfcpp::R_MICROMIPS_PC10_S1);
+  }
+
+ public:
   //   R_MIPS16_26 is used for the mips16 jal and jalx instructions.
   //   Most mips16 instructions are 16 bits, but these instructions
   //   are 32 bits.
@@ -4071,14 +4226,6 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   // on a little-endian system.  This does not apply to R_MICROMIPS_PC7_S1
   // and R_MICROMIPS_PC10_S1 relocs that apply to 16-bit instructions.
 
-  static inline bool
-  should_shuffle_micromips_reloc(unsigned int r_type)
-  {
-    return (micromips_reloc(r_type)
-            && r_type != elfcpp::R_MICROMIPS_PC7_S1
-            && r_type != elfcpp::R_MICROMIPS_PC10_S1);
-  }
-
   static void
   mips_reloc_unshuffle(unsigned char* view, unsigned int r_type,
                        bool jal_shuffle)
@@ -4137,43 +4284,49 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
     elfcpp::Swap<16, big_endian>::writeval(view, first);
   }
 
- public:
   // R_MIPS_16: S + sign-extend(A)
   static inline typename This::Status
   rel16(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, bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype16* wv = reinterpret_cast<Valtype16*>(view);
     Valtype16 val = elfcpp::Swap<16, big_endian>::readval(wv);
 
-    Valtype32 addend = (extract_addend ? Bits<16>::sign_extend32(val)
-                                       : Bits<16>::sign_extend32(addend_a));
+    Valtype addend = (extract_addend ? Bits<16>::sign_extend32(val)
+                                     : addend_a);
 
-    Valtype32 x = psymval->value(object, addend);
+    Valtype x = psymval->value(object, addend);
     val = Bits<16>::bit_select32(val, x, 0xffffU);
-    elfcpp::Swap<16, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<16>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<16, big_endian>::writeval(wv, val);
+
+    return check_overflow<16>(x);
   }
 
   // R_MIPS_32: S + A
   static inline typename This::Status
   rel32(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, bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
-    Valtype32 addend = (extract_addend
+    Valtype addend = (extract_addend
                         ? elfcpp::Swap<32, big_endian>::readval(wv)
-                        : Bits<32>::sign_extend32(addend_a));
-    Valtype32 x = psymval->value(object, addend);
-    elfcpp::Swap<32, big_endian>::writeval(wv, x);
-    mips_reloc_shuffle(view, r_type, false);
+                        : addend_a);
+    Valtype x = psymval->value(object, addend);
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
     return This::STATUS_OKAY;
   }
 
@@ -4182,11 +4335,11 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   reljalr(unsigned char* view, const Mips_relobj<size, big_endian>* object,
           const Symbol_value<size>* psymval, Mips_address address,
           Mips_address addend_a, bool extract_addend, bool cross_mode_jump,
-          unsigned int r_type, bool jalr_to_bal, bool jr_to_b)
+          unsigned int r_type, bool jalr_to_bal, bool jr_to_b,
+          bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
-    Valtype32 addend = extract_addend ? 0 : addend_a;
+    Valtype addend = extract_addend ? 0 : addend_a;
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
     // Try converting J(AL)R to B(AL), if the target is in range.
@@ -4206,8 +4359,11 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
           }
       }
 
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
+    if (calculate_only)
+      *calculated_value = val;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     return This::STATUS_OKAY;
   }
 
@@ -4215,16 +4371,20 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static inline typename This::Status
   relpc32(unsigned char* view, const Mips_relobj<size, big_endian>* object,
           const Symbol_value<size>* psymval, Mips_address address,
-          Mips_address addend_a, bool extract_addend, unsigned int r_type)
+          Mips_address addend_a, bool extract_addend, bool calculate_only,
+          Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
-    Valtype32 addend = (extract_addend
+    Valtype addend = (extract_addend
                         ? elfcpp::Swap<32, big_endian>::readval(wv)
-                        : Bits<32>::sign_extend32(addend_a));
-    Valtype32 x = psymval->value(object, addend) - address;
-    elfcpp::Swap<32, big_endian>::writeval(wv, x);
-    mips_reloc_shuffle(view, r_type, false);
+                        : addend_a);
+    Valtype x = psymval->value(object, addend) - address;
+
+    if (calculate_only)
+       *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
     return This::STATUS_OKAY;
   }
 
@@ -4234,13 +4394,12 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
         const Symbol_value<size>* psymval, Mips_address address,
         bool local, Mips_address addend_a, bool extract_addend,
         const Symbol* gsym, bool cross_mode_jump, unsigned int r_type,
-        bool jal_to_bal)
+        bool jal_to_bal, bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend;
+    Valtype addend;
     if (extract_addend)
       {
         if (r_type == elfcpp::R_MICROMIPS_26_S1)
@@ -4253,11 +4412,10 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
 
     // Make sure the target of JALX is word-aligned.  Bit 0 must be
     // the correct ISA mode selector and bit 1 must be 0.
-    if (cross_mode_jump
+    if (!calculate_only && cross_mode_jump
         && (psymval->value(object, 0) & 3) != (r_type == elfcpp::R_MIPS_26))
       {
         gold_warning(_("JALX to a non-word-aligned address"));
-        mips_reloc_shuffle(view, r_type, !parameters->options().relocatable());
         return This::STATUS_BAD_RELOC;
       }
 
@@ -4265,7 +4423,7 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
     unsigned int shift =
         (!cross_mode_jump && r_type == elfcpp::R_MICROMIPS_26_S1) ? 1 : 2;
 
-    Valtype32 x;
+    Valtype x;
     if (local)
       x = addend | ((address + 4) & (0xfc000000 << shift));
     else
@@ -4277,7 +4435,7 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
       }
     x = psymval->value(object, x) >> shift;
 
-    if (!local && !gsym->is_weak_undefined())
+    if (!calculate_only && !local && !gsym->is_weak_undefined())
       {
         if ((x >> 26) != ((address + 4) >> (26 + shift)))
           {
@@ -4315,7 +4473,7 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
 
         // If the opcode is not JAL or JALX, there's a problem.  We cannot
         // convert J or JALS to JALX.
-        if (!ok)
+        if (!calculate_only && !ok)
           {
             gold_error(_("Unsupported jump between ISA modes; consider "
                          "recompiling with interlinking enabled."));
@@ -4344,8 +4502,11 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
           }
       }
 
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, !parameters->options().relocatable());
+    if (calculate_only)
+      *calculated_value = val;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     return This::STATUS_OKAY;
   }
 
@@ -4353,22 +4514,28 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static inline typename This::Status
   relpc16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
           const Symbol_value<size>* psymval, Mips_address address,
-          Mips_address addend_a, bool extract_addend, unsigned int r_type)
+          Mips_address addend_a, bool extract_addend, bool calculate_only,
+          Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend = extract_addend ? (val & 0xffff) << 2 : addend_a;
-    addend = Bits<18>::sign_extend32(addend);
+    Valtype addend = (extract_addend
+                      ? Bits<18>::sign_extend32((val & 0xffff) << 2)
+                      : addend_a);
 
-    Valtype32 x = psymval->value(object, addend) - address;
+    Valtype x = psymval->value(object, addend) - address;
     val = Bits<16>::bit_select32(val, x >> 2, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<18>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x >> 2;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<18>(x);
   }
 
   // R_MICROMIPS_PC7_S1
@@ -4377,22 +4544,26 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
                       const Mips_relobj<size, big_endian>* object,
                       const Symbol_value<size>* psymval, Mips_address address,
                       Mips_address addend_a, bool extract_addend,
-                      unsigned int r_type)
+                      bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend = extract_addend ? (val & 0x7f) << 1 : addend_a;
-    addend = Bits<8>::sign_extend32(addend);
+    Valtype addend = extract_addend ? Bits<8>::sign_extend32((val & 0x7f) << 1)
+                                    : addend_a;
 
-    Valtype32 x = psymval->value(object, addend) - address;
+    Valtype x = psymval->value(object, addend) - address;
     val = Bits<16>::bit_select32(val, x >> 1, 0x7f);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<8>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x >> 1;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<8>(x);
   }
 
   // R_MICROMIPS_PC10_S1
@@ -4401,22 +4572,27 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
                        const Mips_relobj<size, big_endian>* object,
                        const Symbol_value<size>* psymval, Mips_address address,
                        Mips_address addend_a, bool extract_addend,
-                       unsigned int r_type)
+                       bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend = extract_addend ? (val & 0x3ff) << 1 : addend_a;
-    addend = Bits<11>::sign_extend32(addend);
+    Valtype addend = (extract_addend
+                      ? Bits<11>::sign_extend32((val & 0x3ff) << 1)
+                      : addend_a);
 
-    Valtype32 x = psymval->value(object, addend) - address;
+    Valtype x = psymval->value(object, addend) - address;
     val = Bits<16>::bit_select32(val, x >> 1, 0x3ff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<11>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x >> 1;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<11>(x);
   }
 
   // R_MICROMIPS_PC16_S1
@@ -4425,22 +4601,27 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
                        const Mips_relobj<size, big_endian>* object,
                        const Symbol_value<size>* psymval, Mips_address address,
                        Mips_address addend_a, bool extract_addend,
-                       unsigned int r_type)
+                       bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend = extract_addend ? (val & 0xffff) << 1 : addend_a;
-    addend = Bits<17>::sign_extend32(addend);
+    Valtype addend = (extract_addend
+                      ? Bits<17>::sign_extend32((val & 0xffff) << 1)
+                      : addend_a);
 
-    Valtype32 x = psymval->value(object, addend) - address;
+    Valtype x = psymval->value(object, addend) - address;
     val = Bits<16>::bit_select32(val, x >> 1, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<17>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x >> 1;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<17>(x);
   }
 
   // R_MIPS_HI16, R_MIPS16_HI16, R_MICROMIPS_HI16,
@@ -4463,13 +4644,13 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
              const Symbol_value<size>* psymval, Mips_address addend_hi,
              Mips_address address, bool is_gp_disp, unsigned int r_type,
              bool extract_addend, Valtype32 addend_lo,
-             Target_mips<size, big_endian>* target)
+             Target_mips<size, big_endian>* target, bool calculate_only,
+             Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo
+    Valtype addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo
                                        : addend_hi);
 
     Valtype32 value;
@@ -4500,13 +4681,19 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
           gp_disp = target->adjusted_gp_value(object) - address;
         value = gp_disp + addend;
       }
-    Valtype32 x = ((value + 0x8000) >> 16) & 0xffff;
+    Valtype x = ((value + 0x8000) >> 16) & 0xffff;
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (is_gp_disp && Bits<16>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return (is_gp_disp ? check_overflow<16>(x)
+                       : This::STATUS_OKAY);
   }
 
   // R_MIPS_GOT16, R_MIPS16_GOT16, R_MICROMIPS_GOT16
@@ -4527,14 +4714,14 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   do_relgot16_local(unsigned char* view,
                     const Mips_relobj<size, big_endian>* object,
                     const Symbol_value<size>* psymval, Mips_address addend_hi,
-                    unsigned int r_type, bool extract_addend,
-                    Valtype32 addend_lo, Target_mips<size, big_endian>* target)
+                    bool extract_addend, Valtype32 addend_lo,
+                    Target_mips<size, big_endian>* target, bool calculate_only,
+                    Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo
+    Valtype addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo
                                        : addend_hi);
 
     // Find GOT page entry.
@@ -4545,13 +4732,18 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
       target->got_section()->get_got_page_offset(value, object);
 
     // Resolve the relocation.
-    Valtype32 x = target->got_section()->gp_offset(got_offset, object);
+    Valtype x = target->got_section()->gp_offset(got_offset, object);
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<16>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<16>(x);
   }
 
   // R_MIPS_LO16, R_MIPS16_LO16, R_MICROMIPS_LO16, R_MICROMIPS_HI0_LO16
@@ -4560,57 +4752,69 @@ 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_sym)
+          unsigned int r_type, unsigned int r_sym, unsigned int rel_type,
+          bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend = (extract_addend ? Bits<16>::sign_extend32(val & 0xffff)
-                                       : addend_a);
+    Valtype addend = (extract_addend ? Bits<16>::sign_extend32(val & 0xffff)
+                                     : addend_a);
 
-    // Resolve pending R_MIPS_HI16 relocations.
-    typename std::list<reloc_high<size, big_endian> >::iterator it =
-      hi16_relocs.begin();
-    while (it != hi16_relocs.end())
+    if (rel_type == elfcpp::SHT_REL)
       {
-        reloc_high<size, big_endian> hi16 = *it;
-        if (hi16.r_sym == r_sym
-            && is_matching_lo16_reloc(hi16.r_type, r_type))
+        typename This::Status reloc_status = This::STATUS_OKAY;
+        // Resolve pending R_MIPS_HI16 relocations.
+        typename std::list<reloc_high<size, big_endian> >::iterator it =
+          hi16_relocs.begin();
+        while (it != hi16_relocs.end())
           {
-            if (do_relhi16(hi16.view, hi16.object, hi16.psymval, hi16.addend,
-                           hi16.address, hi16.gp_disp, hi16.r_type,
-                           hi16.extract_addend, addend, target)
-                == This::STATUS_OVERFLOW)
-              return This::STATUS_OVERFLOW;
-            it = hi16_relocs.erase(it);
+            reloc_high<size, big_endian> hi16 = *it;
+            if (hi16.r_sym == r_sym
+                && is_matching_lo16_reloc(hi16.r_type, r_type))
+              {
+                mips_reloc_unshuffle(hi16.view, hi16.r_type, false);
+                reloc_status = do_relhi16(hi16.view, hi16.object, hi16.psymval,
+                                       hi16.addend, hi16.address, hi16.gp_disp,
+                                       hi16.r_type, hi16.extract_addend, addend,
+                                       target, calculate_only, calculated_value);
+                mips_reloc_shuffle(hi16.view, hi16.r_type, false);
+                if (reloc_status == This::STATUS_OVERFLOW)
+                  return This::STATUS_OVERFLOW;
+                it = hi16_relocs.erase(it);
+              }
+            else
+              ++it;
           }
-        else
-          ++it;
-      }
 
-    // Resolve pending local R_MIPS_GOT16 relocations.
-    typename std::list<reloc_high<size, big_endian> >::iterator it2 =
-      got16_relocs.begin();
-    while (it2 != got16_relocs.end())
-      {
-        reloc_high<size, big_endian> got16 = *it2;
-        if (got16.r_sym == r_sym
-            && is_matching_lo16_reloc(got16.r_type, r_type))
+        // Resolve pending local R_MIPS_GOT16 relocations.
+        typename std::list<reloc_high<size, big_endian> >::iterator it2 =
+          got16_relocs.begin();
+        while (it2 != got16_relocs.end())
           {
-            if (do_relgot16_local(got16.view, got16.object, got16.psymval,
-                                  got16.addend, got16.r_type,
-                                  got16.extract_addend, addend,
-                                  target) == This::STATUS_OVERFLOW)
-              return This::STATUS_OVERFLOW;
-            it2 = got16_relocs.erase(it2);
+            reloc_high<size, big_endian> got16 = *it2;
+            if (got16.r_sym == r_sym
+                && is_matching_lo16_reloc(got16.r_type, r_type))
+              {
+                mips_reloc_unshuffle(got16.view, got16.r_type, false);
+
+                reloc_status = do_relgot16_local(got16.view, got16.object,
+                                     got16.psymval, got16.addend,
+                                     got16.extract_addend, addend, target,
+                                     calculate_only, calculated_value);
+
+                mips_reloc_shuffle(got16.view, got16.r_type, false);
+                if (reloc_status == This::STATUS_OVERFLOW)
+                  return This::STATUS_OVERFLOW;
+                it2 = got16_relocs.erase(it2);
+              }
+            else
+              ++it2;
           }
-        else
-          ++it2;
       }
 
     // Resolve R_MIPS_LO16 relocation.
-    Valtype32 x;
+    Valtype x;
     if (!is_gp_disp)
       x = psymval->value(object, addend);
     else
@@ -4643,8 +4847,12 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
         x = gp_disp + addend;
       }
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     return This::STATUS_OKAY;
   }
 
@@ -4655,18 +4863,42 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   // R_MIPS_TLS_LDM, R_MIPS16_TLS_LDM, R_MICROMIPS_TLS_LDM
   // R_MIPS_GOT_DISP, R_MICROMIPS_GOT_DISP
   static inline typename This::Status
-  relgot(unsigned char* view, int gp_offset, unsigned int r_type)
+  relgot(unsigned char* view, int gp_offset, bool calculate_only,
+         Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 x = gp_offset;
+    Valtype x = gp_offset;
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<16>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<16>(x);
+  }
+
+  // R_MIPS_EH
+  static inline typename This::Status
+  releh(unsigned char* view, int gp_offset, bool calculate_only,
+        Valtype* calculated_value)
+  {
+    Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+    Valtype x = gp_offset;
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
+    return check_overflow<32>(x);
   }
 
   // R_MIPS_GOT_PAGE, R_MICROMIPS_GOT_PAGE
@@ -4674,25 +4906,30 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   relgotpage(Target_mips<size, big_endian>* target, 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, bool calculate_only,
+             Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(view);
-    Valtype32 addend = extract_addend ? val & 0xffff : addend_a;
+    Valtype addend = extract_addend ? val & 0xffff : addend_a;
 
     // Find a GOT page entry that points to within 32KB of symbol + addend.
     Mips_address value = (psymval->value(object, addend) + 0x8000) & ~0xffff;
     unsigned int  got_offset =
       target->got_section()->get_got_page_offset(value, object);
 
-    Valtype32 x = target->got_section()->gp_offset(got_offset, object);
+    Valtype x = target->got_section()->gp_offset(got_offset, object);
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<16>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<16>(x);
   }
 
   // R_MIPS_GOT_OFST, R_MICROMIPS_GOT_OFST
@@ -4700,18 +4937,18 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   relgotofst(Target_mips<size, big_endian>* target, unsigned char* view,
              const Mips_relobj<size, big_endian>* object,
              const Symbol_value<size>* psymval, Mips_address addend_a,
-             bool extract_addend, bool local, unsigned int r_type)
+             bool extract_addend, bool local, bool calculate_only,
+             Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(view);
-    Valtype32 addend = extract_addend ? val & 0xffff : addend_a;
+    Valtype addend = extract_addend ? val & 0xffff : addend_a;
 
     // For a local symbol, find a GOT page entry that points to within 32KB of
     // symbol + addend.  Relocation value is the offset of the GOT page entry's
     // value from symbol + addend.
     // For a global symbol, relocation value is addend.
-    Valtype32 x;
+    Valtype x;
     if (local)
       {
         // Find GOT page entry.
@@ -4724,41 +4961,54 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
     else
       x = addend;
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    return (Bits<16>::has_overflow32(x)
-            ? This::STATUS_OVERFLOW
-            : This::STATUS_OKAY);
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    return check_overflow<16>(x);
   }
 
   // R_MIPS_GOT_HI16, R_MIPS_CALL_HI16,
   // R_MICROMIPS_GOT_HI16, R_MICROMIPS_CALL_HI16
   static inline typename This::Status
-  relgot_hi16(unsigned char* view, int gp_offset, unsigned int r_type)
+  relgot_hi16(unsigned char* view, int gp_offset, bool calculate_only,
+              Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 x = gp_offset;
+    Valtype x = gp_offset;
     x = ((x + 0x8000) >> 16) & 0xffff;
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     return This::STATUS_OKAY;
   }
 
   // R_MIPS_GOT_LO16, R_MIPS_CALL_LO16,
   // R_MICROMIPS_GOT_LO16, R_MICROMIPS_CALL_LO16
   static inline typename This::Status
-  relgot_lo16(unsigned char* view, int gp_offset, unsigned int r_type)
+  relgot_lo16(unsigned char* view, int gp_offset, bool calculate_only,
+              Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 x = gp_offset;
+    Valtype x = gp_offset;
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     return This::STATUS_OKAY;
   }
 
@@ -4768,13 +5018,13 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   relgprel(unsigned char* view, const Mips_relobj<size, big_endian>* object,
            const Symbol_value<size>* psymval, Mips_address gp,
            Mips_address addend_a, bool extract_addend, bool local,
-           unsigned int r_type)
+           unsigned int r_type, bool calculate_only,
+           Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
 
-    Valtype32 addend;
+    Valtype addend;
     if (extract_addend)
       {
         if (r_type == elfcpp::R_MICROMIPS_GPREL7_S2)
@@ -4789,7 +5039,7 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
     else
       addend = addend_a;
 
-    Valtype32 x = psymval->value(object, addend) - gp;
+    Valtype x = psymval->value(object, addend) - gp;
 
     // If the symbol was local, any earlier relocatable links will
     // have adjusted its addend with the gp offset, so compensate
@@ -4803,9 +5053,16 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
       val = Bits<32>::bit_select32(val, x, 0x7f);
     else
       val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
-    if (Bits<16>::has_overflow32(x))
+
+    if (calculate_only)
+      {
+        *calculated_value = x;
+        return This::STATUS_OKAY;
+      }
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+    if (check_overflow<16>(x) == This::STATUS_OVERFLOW)
       {
         gold_error(_("small-data section exceeds 64KB; lower small-data size "
                      "limit (see option -G)"));
@@ -4818,17 +5075,21 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static inline typename This::Status
   relgprel32(unsigned char* view, const Mips_relobj<size, big_endian>* object,
              const Symbol_value<size>* psymval, Mips_address gp,
-             Mips_address addend_a, bool extract_addend, unsigned int r_type)
+             Mips_address addend_a, bool extract_addend, bool calculate_only,
+             Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 addend = extract_addend ? val : addend_a;
+    Valtype addend = extract_addend ? val : addend_a;
 
     // R_MIPS_GPREL32 relocations are defined for local symbols only.
-    Valtype32 x = psymval->value(object, addend) + object->gp_value() - gp;
-    elfcpp::Swap<32, big_endian>::writeval(wv, x);
-    mips_reloc_shuffle(view, r_type, false);
+    Valtype x = psymval->value(object, addend) + object->gp_value() - gp;
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
     return This::STATUS_OKAY;
  }
 
@@ -4838,18 +5099,22 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static inline typename This::Status
   tlsrelhi16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
              const Symbol_value<size>* psymval, Valtype32 tp_offset,
-             Mips_address addend_a, bool extract_addend, unsigned int r_type)
+             Mips_address addend_a, bool extract_addend, bool calculate_only,
+             Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 addend = extract_addend ? val & 0xffff : addend_a;
+    Valtype addend = extract_addend ? val & 0xffff : addend_a;
 
     // tls symbol values are relative to tls_segment()->vaddr()
-    Valtype32 x = ((psymval->value(object, addend) - tp_offset) + 0x8000) >> 16;
+    Valtype x = ((psymval->value(object, addend) - tp_offset) + 0x8000) >> 16;
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     return This::STATUS_OKAY;
   }
 
@@ -4859,18 +5124,22 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static inline typename This::Status
   tlsrello16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
              const Symbol_value<size>* psymval, Valtype32 tp_offset,
-             Mips_address addend_a, bool extract_addend, unsigned int r_type)
+             Mips_address addend_a, bool extract_addend, bool calculate_only,
+             Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 addend = extract_addend ? val & 0xffff : addend_a;
+    Valtype addend = extract_addend ? val & 0xffff : addend_a;
 
     // tls symbol values are relative to tls_segment()->vaddr()
-    Valtype32 x = psymval->value(object, addend) - tp_offset;
+    Valtype x = psymval->value(object, addend) - tp_offset;
     val = Bits<32>::bit_select32(val, x, 0xffff);
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
-    mips_reloc_shuffle(view, r_type, false);
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     return This::STATUS_OKAY;
   }
 
@@ -4879,17 +5148,21 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static inline typename This::Status
   tlsrel32(unsigned char* view, const Mips_relobj<size, big_endian>* object,
            const Symbol_value<size>* psymval, Valtype32 tp_offset,
-           Mips_address addend_a, bool extract_addend, unsigned int r_type)
+           Mips_address addend_a, bool extract_addend, bool calculate_only,
+           Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
     Valtype32* wv = reinterpret_cast<Valtype32*>(view);
     Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 addend = extract_addend ? val : addend_a;
+    Valtype addend = extract_addend ? val : addend_a;
 
     // tls symbol values are relative to tls_segment()->vaddr()
-    Valtype32 x = psymval->value(object, addend) - tp_offset;
-    elfcpp::Swap<32, big_endian>::writeval(wv, x);
-    mips_reloc_shuffle(view, r_type, false);
+    Valtype x = psymval->value(object, addend) - tp_offset;
+
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
     return This::STATUS_OKAY;
   }
 
@@ -4897,18 +5170,47 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   static inline typename This::Status
   relsub(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, bool calculate_only, Valtype* calculated_value)
   {
-    mips_reloc_unshuffle(view, r_type, false);
-    Valtype32* wv = reinterpret_cast<Valtype32*>(view);
-    Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
-    Valtype32 addend = extract_addend ? val : addend_a;
+    Valtype64* wv = reinterpret_cast<Valtype64*>(view);
+    Valtype64 addend = (extract_addend
+                        ? elfcpp::Swap<64, big_endian>::readval(wv)
+                        : addend_a);
+
+    Valtype64 x = psymval->value(object, -addend);
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      elfcpp::Swap<64, big_endian>::writeval(wv, x);
 
-    Valtype32 x = psymval->value(object, -addend);
-    elfcpp::Swap<32, big_endian>::writeval(wv, x);
-    mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
- }
+  }
+
+  // R_MIPS_64: S + A
+  static inline typename This::Status
+  rel64(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+        const Symbol_value<size>* psymval, Mips_address addend_a,
+        bool extract_addend, bool calculate_only, Valtype* calculated_value,
+        bool apply_addend_only)
+  {
+    Valtype64* wv = reinterpret_cast<Valtype64*>(view);
+    Valtype64 addend = (extract_addend
+                        ? elfcpp::Swap<64, big_endian>::readval(wv)
+                        : addend_a);
+
+    Valtype64 x = psymval->value(object, addend);
+    if (calculate_only)
+      *calculated_value = x;
+    else
+      {
+        if (apply_addend_only)
+          x = addend;
+        elfcpp::Swap<64, big_endian>::writeval(wv, x);
+      }
+
+    return This::STATUS_OKAY;
+  }
+
 };
 
 template<int size, bool big_endian>
@@ -4928,12 +5230,13 @@ template<int size, bool big_endian>
 void
 Mips_got_info<size, big_endian>::record_local_got_symbol(
     Mips_relobj<size, big_endian>* object, unsigned int symndx,
-    Mips_address addend, unsigned int r_type, unsigned int shndx)
+    Mips_address addend, unsigned int r_type, unsigned int shndx,
+    bool is_section_symbol)
 {
   Mips_got_entry<size, big_endian>* entry =
     new Mips_got_entry<size, big_endian>(object, symndx, addend,
                                          mips_elf_reloc_tls_type(r_type),
-                                         shndx);
+                                         shndx, is_section_symbol);
   this->record_got_entry(entry, object);
 }
 
@@ -5113,13 +5416,20 @@ Mips_got_info<size, big_endian>::add_local_entries(
       if (entry->is_for_local_symbol() && !entry->is_tls_entry())
         {
           got->add_local(entry->object(), entry->symndx(),
-                         GOT_TYPE_STANDARD);
+                         GOT_TYPE_STANDARD, entry->addend());
           unsigned int got_offset = entry->object()->local_got_offset(
-              entry->symndx(), GOT_TYPE_STANDARD);
+              entry->symndx(), GOT_TYPE_STANDARD, entry->addend());
           if (got->multi_got() && this->index_ > 0
               && parameters->options().output_is_position_independent())
-            target->rel_dyn_section(layout)->add_local(entry->object(),
-                entry->symndx(), elfcpp::R_MIPS_REL32, got, got_offset);
+          {
+            if (!entry->is_section_symbol())
+              target->rel_dyn_section(layout)->add_local(entry->object(),
+                  entry->symndx(), elfcpp::R_MIPS_REL32, got, got_offset);
+            else
+              target->rel_dyn_section(layout)->add_symbolless_local_addend(
+                  entry->object(), entry->symndx(), elfcpp::R_MIPS_REL32,
+                  got, got_offset);
+          }
         }
     }
 
@@ -5317,9 +5627,10 @@ Mips_got_info<size, big_endian>::add_tls_entries(
               got->add_local_pair_with_rel(entry->object(), entry->symndx(),
                                            entry->shndx(), got_type,
                                            target->rel_dyn_section(layout),
-                                           r_type1);
+                                           r_type1, entry->addend());
               unsigned int got_offset =
-                entry->object()->local_got_offset(entry->symndx(), got_type);
+                entry->object()->local_got_offset(entry->symndx(), got_type,
+                                                  entry->addend());
               got->add_static_reloc(got_offset + size/8, r_type2,
                                     entry->object(), entry->symndx());
             }
@@ -5329,7 +5640,8 @@ Mips_got_info<size, big_endian>::add_tls_entries(
               // the executable.
               unsigned int got_offset = got->add_constant(1);
               entry->object()->set_local_got_offset(entry->symndx(), got_type,
-                                                    got_offset);
+                                                    got_offset,
+                                                    entry->addend());
               got->add_constant(0);
               got->add_static_reloc(got_offset + size/8, r_type2,
                                     entry->object(), entry->symndx());
@@ -5342,12 +5654,15 @@ Mips_got_info<size, big_endian>::add_tls_entries(
                                             : elfcpp::R_MIPS_TLS_TPREL64);
           if (!parameters->doing_static_link())
             got->add_local_with_rel(entry->object(), entry->symndx(), got_type,
-                                    target->rel_dyn_section(layout), r_type);
+                                    target->rel_dyn_section(layout), r_type,
+                                    entry->addend());
           else
             {
-              got->add_local(entry->object(), entry->symndx(), got_type);
+              got->add_local(entry->object(), entry->symndx(), got_type,
+                             entry->addend());
               unsigned int got_offset =
-                  entry->object()->local_got_offset(entry->symndx(), got_type);
+                  entry->object()->local_got_offset(entry->symndx(), got_type,
+                                                    entry->addend());
               got->add_static_reloc(got_offset, r_type, entry->object(),
                                     entry->symndx());
             }
@@ -6089,21 +6404,104 @@ Mips_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
           this->cprmask4_ = elfcpp::Swap<size, big_endian>::readval(view + 16);
         }
 
-      const char* name = pnames + shdr.get_sh_name();
-      this->section_is_mips16_fn_stub_[i] = is_prefix_of(".mips16.fn", name);
-      this->section_is_mips16_call_stub_[i] =
-        is_prefix_of(".mips16.call.", name);
-      this->section_is_mips16_call_fp_stub_[i] =
-        is_prefix_of(".mips16.call.fp.", name);
+      // In the 64-bit ABI, .MIPS.options section holds register information.
+      // A SHT_MIPS_OPTIONS section contains a series of options, each of which
+      // starts with this header:
+      //
+      // typedef struct
+      // {
+      //   // Type of option.
+      //   unsigned char kind[1];
+      //   // Size of option descriptor, including header.
+      //   unsigned char size[1];
+      //   // Section index of affected section, or 0 for global option.
+      //   unsigned char section[2];
+      //   // Information specific to this kind of option.
+      //   unsigned char info[4];
+      // };
+      //
+      // For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and set
+      // the gp value based on what we find.  We may see both SHT_MIPS_REGINFO
+      // and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case, they should agree.
 
-      if (strcmp(name, ".pdr") == 0)
+      if (shdr.get_sh_type() == elfcpp::SHT_MIPS_OPTIONS)
         {
-          gold_assert(this->pdr_shndx_ == -1U);
-          this->pdr_shndx_ = i;
-        }
-    }
-}
-
+          section_offset_type section_offset = shdr.get_sh_offset();
+          section_size_type section_size =
+            convert_to_section_size_type(shdr.get_sh_size());
+          const unsigned char* view =
+             this->get_view(section_offset, section_size, true, false);
+          const unsigned char* end = view + section_size;
+
+          while (view + 8 <= end)
+            {
+              unsigned char kind = elfcpp::Swap<8, big_endian>::readval(view);
+              unsigned char sz = elfcpp::Swap<8, big_endian>::readval(view + 1);
+              if (sz < 8)
+                {
+                  gold_error(_("%s: Warning: bad `%s' option size %u smaller "
+                               "than its header"),
+                             this->name().c_str(),
+                             this->mips_elf_options_section_name(), sz);
+                  break;
+                }
+
+              if (this->is_n64() && kind == elfcpp::ODK_REGINFO)
+                {
+                  // In the 64 bit ABI, an ODK_REGINFO option is the following
+                  // structure.  The info field of the options header is not
+                  // used.
+                  //
+                  // typedef struct
+                  // {
+                  //   // Mask of general purpose registers used.
+                  //   unsigned char ri_gprmask[4];
+                  //   // Padding.
+                  //   unsigned char ri_pad[4];
+                  //   // Mask of co-processor registers used.
+                  //   unsigned char ri_cprmask[4][4];
+                  //   // GP register value for this object file.
+                  //   unsigned char ri_gp_value[8];
+                  // };
+
+                  this->gp_ = elfcpp::Swap<size, big_endian>::readval(view
+                                                                      + 32);
+                }
+              else if (kind == elfcpp::ODK_REGINFO)
+                {
+                  // In the 32 bit ABI, an ODK_REGINFO option is the following
+                  // structure.  The info field of the options header is not
+                  // used.  The same structure is used in .reginfo section.
+                  //
+                  // typedef struct
+                  // {
+                  //   unsigned char ri_gprmask[4];
+                  //   unsigned char ri_cprmask[4][4];
+                  //   unsigned char ri_gp_value[4];
+                  // };
+
+                  this->gp_ = elfcpp::Swap<size, big_endian>::readval(view
+                                                                      + 28);
+                }
+              view += sz;
+            }
+        }
+
+      const char* name = pnames + shdr.get_sh_name();
+      this->section_is_mips16_fn_stub_[i] = is_prefix_of(".mips16.fn", name);
+      this->section_is_mips16_call_stub_[i] =
+        is_prefix_of(".mips16.call.", name);
+      this->section_is_mips16_call_fp_stub_[i] =
+        is_prefix_of(".mips16.call.fp.", name);
+
+      if (strcmp(name, ".pdr") == 0)
+        {
+          gold_assert(this->pdr_shndx_ == -1U);
+          this->pdr_shndx_ = i;
+        }
+    }
+}
+
 // Discard MIPS16 stub secions that are not needed.
 
 template<int size, bool big_endian>
@@ -6421,7 +6819,7 @@ template<int size, bool big_endian>
 const uint32_t Mips_output_data_plt<size, big_endian>::plt_entry[] =
 {
   0x3c0f0000,           // lui $15, %hi(.got.plt entry)
-  0x8df90000,           // l[wd] $25, %lo(.got.plt entry)($15)
+  0x01f90000,           // l[wd] $25, %lo(.got.plt entry)($15)
   0x03200008,           // jr $25
   0x25f80000            // addiu $24, $15, %lo(.got.plt entry)
 };
@@ -7707,7 +8105,7 @@ Target_mips<size, big_endian>::gc_process_relocs(
                         Layout* layout,
                         Sized_relobj_file<size, big_endian>* object,
                         unsigned int data_shndx,
-                        unsigned int,
+                        unsigned int sh_type,
                         const unsigned char* prelocs,
                         size_t reloc_count,
                         Output_section* output_section,
@@ -7716,21 +8114,45 @@ Target_mips<size, big_endian>::gc_process_relocs(
                         const unsigned char* plocal_symbols)
 {
   typedef Target_mips<size, big_endian> Mips;
-  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
-      Classify_reloc;
 
-  gold::gc_process_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);
+  if (sh_type == elfcpp::SHT_REL)
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+          Classify_reloc;
+
+      gold::gc_process_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)
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+          Classify_reloc;
+
+      gold::gc_process_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
+    gold_unreachable();
 }
 
 // Scan relocations for a section.
@@ -8199,9 +8621,20 @@ Target_mips<size, big_endian>::do_finalize_sections(Layout* layout,
           elfcpp::Ehdr<size, big_endian> ehdr(pehdr);
           elfcpp::Elf_Word in_flags = ehdr.get_e_flags();
           unsigned char ei_class = ehdr.get_e_ident()[elfcpp::EI_CLASS];
+          // If all input sections will be discarded, don't use this object
+          // file for merging processor specific flags.
+          bool should_merge_processor_specific_flags = false;
+
+          for (unsigned int i = 1; i < relobj->shnum(); ++i)
+            if (relobj->output_section(i) != NULL)
+              {
+                should_merge_processor_specific_flags = true;
+                break;
+              }
 
-          this->merge_processor_specific_flags(relobj->name(), in_flags,
-                                               ei_class, false);
+          if (should_merge_processor_specific_flags)
+            this->merge_processor_specific_flags(relobj->name(), in_flags,
+                                                 ei_class, false);
         }
     }
 
@@ -8501,6 +8934,7 @@ mips_get_size_for_reloc(unsigned int r_type, Relobj* object)
     case elfcpp::R_MIPS_PC32:
     case elfcpp::R_MIPS_GPREL32:
     case elfcpp::R_MIPS_JALR:
+    case elfcpp::R_MIPS_EH:
       return 4;
 
     case elfcpp::R_MIPS_16:
@@ -8566,25 +9000,48 @@ Target_mips<size, big_endian>::scan_relocatable_relocs(
                         const unsigned char* plocal_symbols,
                         Relocatable_relocs* rr)
 {
-  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
-      Classify_reloc;
-  typedef Mips_scan_relocatable_relocs<big_endian, Classify_reloc>
-      Scan_relocatable_relocs;
-
-  gold_assert(sh_type == elfcpp::SHT_REL);
-
-  gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
-    symtab,
-    layout,
-    object,
-    data_shndx,
-    prelocs,
-    reloc_count,
-    output_section,
-    needs_special_offset_handling,
-    local_symbol_count,
-    plocal_symbols,
-    rr);
+  if (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;
+
+      gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
+        symtab,
+        layout,
+        object,
+        data_shndx,
+        prelocs,
+        reloc_count,
+        output_section,
+        needs_special_offset_handling,
+        local_symbol_count,
+        plocal_symbols,
+        rr);
+    }
+  else if (sh_type == elfcpp::SHT_RELA)
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+          Classify_reloc;
+      typedef Mips_scan_relocatable_relocs<big_endian, Classify_reloc>
+          Scan_relocatable_relocs;
+
+      gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
+        symtab,
+        layout,
+        object,
+        data_shndx,
+        prelocs,
+        reloc_count,
+        output_section,
+        needs_special_offset_handling,
+        local_symbol_count,
+        plocal_symbols,
+        rr);
+    }
+  else
+    gold_unreachable();
 }
 
 // Scan the relocs for --emit-relocs.
@@ -8605,25 +9062,48 @@ Target_mips<size, big_endian>::emit_relocs_scan(
     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);
+  if (sh_type == elfcpp::SHT_REL)
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+          Classify_reloc;
+      typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+          Emit_relocs_strategy;
+
+      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);
+    }
+  else if (sh_type == elfcpp::SHT_RELA)
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+          Classify_reloc;
+      typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+          Emit_relocs_strategy;
+
+      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);
+    }
+  else
+    gold_unreachable();
 }
 
 // Emit relocations for a section.
@@ -8644,22 +9124,42 @@ Target_mips<size, big_endian>::relocate_relocs(
                         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, Classify_reloc>(
-    relinfo,
-    prelocs,
-    reloc_count,
-    output_section,
-    offset_in_output_section,
-    view,
-    view_address,
-    view_size,
-    reloc_view,
-    reloc_view_size);
+  if (sh_type == elfcpp::SHT_REL)
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+          Classify_reloc;
+
+      gold::relocate_relocs<size, big_endian, Classify_reloc>(
+        relinfo,
+        prelocs,
+        reloc_count,
+        output_section,
+        offset_in_output_section,
+        view,
+        view_address,
+        view_size,
+        reloc_view,
+        reloc_view_size);
+    }
+  else if (sh_type == elfcpp::SHT_RELA)
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+          Classify_reloc;
+
+      gold::relocate_relocs<size, big_endian, Classify_reloc>(
+        relinfo,
+        prelocs,
+        reloc_count,
+        output_section,
+        offset_in_output_section,
+        view,
+        view_address,
+        view_size,
+        reloc_view,
+        reloc_view_size);
+    }
+  else
+    gold_unreachable();
 }
 
 // Perform target-specific processing in a relocatable link.  This is
@@ -8757,7 +9257,7 @@ Target_mips<size, big_endian>::relocate_special_relocatable(
   // file to refer to that same address.  This adjustment to
   // the addend is the same calculation we use for a simple
   // absolute relocation for the input section symbol.
-
+  Valtype calculated_value = 0;
   const Symbol_value<size>* psymval = object->local_symbol(r_sym);
 
   unsigned char* paddend = view + offset;
@@ -8767,7 +9267,8 @@ Target_mips<size, big_endian>::relocate_special_relocatable(
     case elfcpp::R_MIPS_26:
       reloc_status = Reloc_funcs::rel26(paddend, object, psymval,
           offset_in_output_section, true, 0, sh_type == elfcpp::SHT_REL, NULL,
-          false /*TODO(sasa): cross mode jump*/, r_type, this->jal_to_bal());
+          false /*TODO(sasa): cross mode jump*/, r_type, this->jal_to_bal(),
+          false, &calculated_value);
       break;
 
     default:
@@ -8900,6 +9401,7 @@ Target_mips<size, big_endian>::Scan::local(
     case elfcpp::R_MICROMIPS_TLS_GOTTPREL:
     case elfcpp::R_MICROMIPS_TLS_GD:
     case elfcpp::R_MICROMIPS_TLS_LDM:
+    case elfcpp::R_MIPS_EH:
       // We need a GOT section.
       target->got_section(symtab, layout);
       break;
@@ -8910,7 +9412,8 @@ Target_mips<size, big_endian>::Scan::local(
 
   if (call_lo16_reloc(r_type)
       || got_lo16_reloc(r_type)
-      || got_disp_reloc(r_type))
+      || got_disp_reloc(r_type)
+      || eh_reloc(r_type))
     {
       // We may need a local GOT entry for this relocation.  We
       // don't count R_MIPS_GOT_PAGE because we can estimate the
@@ -8921,7 +9424,9 @@ 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);
-      got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U);
+      bool is_section_symbol = lsym.get_st_type() == elfcpp::STT_SECTION;
+      got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U,
+                                   is_section_symbol);
     }
 
   switch (r_type)
@@ -9054,6 +9559,8 @@ Target_mips<size, big_endian>::Scan::local(
             // If building a shared library (or a position-independent
             // executable), we need to create a dynamic relocation for
             // this location.
+            if (is_readonly_section(output_section))
+              break;
             Reloc_section* rel_dyn = target->rel_dyn_section(layout);
             rel_dyn->add_symbolless_local_addend(object, r_sym,
                                                  elfcpp::R_MIPS_REL32,
@@ -9098,7 +9605,7 @@ Target_mips<size, big_endian>::Scan::local(
                     break;
                   }
                 got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type,
-                                             shndx);
+                                             shndx, false);
               }
             else
               {
@@ -9115,7 +9622,7 @@ Target_mips<size, big_endian>::Scan::local(
                 // We always record LDM symbols as local with index 0.
                 target->got_section()->record_local_got_symbol(mips_obj, 0,
                                                                r_addend, r_type,
-                                                               -1U);
+                                                               -1U, false);
               }
             else
               {
@@ -9133,7 +9640,7 @@ Target_mips<size, big_endian>::Scan::local(
                 Mips_output_data_got<size, big_endian>* got =
                   target->got_section(symtab, layout);
                 got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type,
-                                             -1U);
+                                             -1U, false);
               }
             else
               {
@@ -9354,6 +9861,7 @@ Target_mips<size, big_endian>::Scan::global(
     case elfcpp::R_MICROMIPS_TLS_GOTTPREL:
     case elfcpp::R_MICROMIPS_TLS_GD:
     case elfcpp::R_MICROMIPS_TLS_LDM:
+    case elfcpp::R_MIPS_EH:
       // We need a GOT section.
       target->got_section(symtab, layout);
       break;
@@ -9380,14 +9888,14 @@ Target_mips<size, big_endian>::Scan::global(
     case elfcpp::R_MIPS_32:
     case elfcpp::R_MIPS_REL32:
     case elfcpp::R_MIPS_64:
-      if (parameters->options().shared()
-          || strcmp(gsym->name(), "__gnu_local_gp") != 0)
+      if ((parameters->options().shared()
+          || (strcmp(gsym->name(), "__gnu_local_gp") != 0
+          && (!is_readonly_section(output_section)
+          || mips_obj->is_pic())))
+          && (output_section->flags() & elfcpp::SHF_ALLOC) != 0)
         {
           if (r_type != elfcpp::R_MIPS_REL32)
-            {
-              static_reloc = true;
-              mips_sym->set_pointer_equality_needed();
-            }
+            mips_sym->set_pointer_equality_needed();
           can_make_dynamic = true;
           break;
         }
@@ -9484,8 +9992,8 @@ Target_mips<size, big_endian>::Scan::global(
         {
           if (gsym->may_need_copy_reloc())
             {
-              target->copy_reloc(symtab, layout, object,
-                                 data_shndx, output_section, gsym, *rel);
+              target->copy_reloc(symtab, layout, object, data_shndx,
+                                 output_section, gsym, r_type, r_offset);
             }
           else if (can_make_dynamic)
             {
@@ -9522,6 +10030,7 @@ Target_mips<size, big_endian>::Scan::global(
     case elfcpp::R_MICROMIPS_GOT_LO16:
     case elfcpp::R_MIPS_GOT_DISP:
     case elfcpp::R_MICROMIPS_GOT_DISP:
+    case elfcpp::R_MIPS_EH:
       {
         // The symbol requires a GOT entry.
         Mips_output_data_got<size, big_endian>* got =
@@ -9609,7 +10118,7 @@ Target_mips<size, big_endian>::Scan::global(
                 // We always record LDM symbols as local with index 0.
                 target->got_section()->record_local_got_symbol(mips_obj, 0,
                                                                r_addend, r_type,
-                                                               -1U);
+                                                               -1U, false);
               }
             else
               {
@@ -9743,11 +10252,14 @@ Target_mips<size, big_endian>::Scan::global(
     gsym);
 }
 
-// Return whether a R_MIPS_32 relocation needs to be applied.
+// Return whether a R_MIPS_32/R_MIPS64 relocation needs to be applied.
+// In cases where Scan::local() or Scan::global() has created
+// a dynamic relocation, the addend of the relocation is carried
+// in the data, and we must not apply the static relocation.
 
 template<int size, bool big_endian>
 inline bool
-Target_mips<size, big_endian>::Relocate::should_apply_r_mips_32_reloc(
+Target_mips<size, big_endian>::Relocate::should_apply_static_reloc(
     const Mips_symbol<size>* gsym,
     unsigned int r_type,
     Output_section* output_section,
@@ -9812,6 +10324,9 @@ Target_mips<size, big_endian>::Relocate::relocate(
   Mips_address r_offset;
   unsigned int r_sym;
   unsigned int r_type;
+  unsigned int r_type2;
+  unsigned int r_type3;
+  unsigned char r_ssym;
   typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
 
   if (rel_type == elfcpp::SHT_RELA)
@@ -9822,17 +10337,25 @@ Target_mips<size, big_endian>::Relocate::relocate(
 	  get_r_sym(&rela);
       r_type = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
 	  get_r_type(&rela);
+      r_type2 = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+          get_r_type2(&rela);
+      r_type3 = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+          get_r_type3(&rela);
+      r_ssym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+          get_r_ssym(&rela);
       r_addend = rela.get_r_addend();
     }
   else
     {
-
       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_ssym = 0;
+      r_type2 = 0;
+      r_type3 = 0;
       r_addend = 0;
     }
 
@@ -10096,320 +10619,479 @@ Target_mips<size, big_endian>::Relocate::relocate(
   unsigned int got_offset = 0;
   int gp_offset = 0;
 
-  bool update_got_entry = false;
+  bool calculate_only = false;
+  Valtype calculated_value = 0;
   bool extract_addend = rel_type == elfcpp::SHT_REL;
-  switch (r_type)
+  unsigned int r_types[3] = { r_type, r_type2, r_type3 };
+
+  Reloc_funcs::mips_reloc_unshuffle(view, r_type, false);
+
+  // For Mips64 N64 ABI, there may be up to three operations specified per
+  // record, by the fields r_type, r_type2, and r_type3. The first operation
+  // takes its addend from the relocation record. Each subsequent operation
+  // takes as its addend the result of the previous operation.
+  // The first operation in a record which references a symbol uses the symbol
+  // implied by r_sym. The next operation in a record which references a symbol
+  // uses the special symbol value given by the r_ssym field. A third operation
+  // in a record which references a symbol will assume a NULL symbol,
+  // i.e. value zero.
+
+  // TODO(Vladimir)
+  // Check if a record references to a symbol.
+  for (unsigned int i = 0; i < 3; ++i)
     {
-    case elfcpp::R_MIPS_NONE:
-      break;
-    case elfcpp::R_MIPS_16:
-      reloc_status = Reloc_funcs::rel16(view, object, psymval, r_addend,
-                                        extract_addend, r_type);
-      break;
+      if (r_types[i] == elfcpp::R_MIPS_NONE)
+        break;
 
-    case elfcpp::R_MIPS_32:
-      if (should_apply_r_mips_32_reloc(mips_sym, r_type, output_section,
-                                       target))
-        reloc_status = Reloc_funcs::rel32(view, object, psymval, r_addend,
-                                          extract_addend, r_type);
-      if (mips_sym != NULL
-          && (mips_sym->is_mips16() || mips_sym->is_micromips())
-          && mips_sym->global_got_area() == GGA_RELOC_ONLY)
+      // TODO(Vladimir)
+      // Check if the next relocation is for the same instruction.
+      calculate_only = i == 2 ? false
+                              : r_types[i+1] != elfcpp::R_MIPS_NONE;
+
+      if (object->is_n64())
         {
-          // If mips_sym->has_mips16_fn_stub() is false, symbol value is
-          // already updated by adding +1.
-          if (mips_sym->has_mips16_fn_stub())
+          if (i == 1)
             {
-              gold_assert(mips_sym->need_fn_stub());
-              Mips16_stub_section<size, big_endian>* fn_stub =
-                mips_sym->template get_mips16_fn_stub<big_endian>();
-
-              symval.set_output_value(fn_stub->output_address());
+              // Handle special symbol for r_type2 relocation type.
+              switch (r_ssym)
+                {
+                case RSS_UNDEF:
+                  symval.set_output_value(0);
+                  break;
+                case RSS_GP:
+                  symval.set_output_value(target->gp_value());
+                  break;
+                case RSS_GP0:
+                  symval.set_output_value(object->gp_value());
+                  break;
+                case RSS_LOC:
+                  symval.set_output_value(address);
+                  break;
+                default:
+                  gold_unreachable();
+                }
               psymval = &symval;
             }
-          got_offset = mips_sym->global_gotoffset();
-          update_got_entry = true;
+          else if (i == 2)
+           {
+            // For r_type3 symbol value is 0.
+            symval.set_output_value(0);
+           }
         }
-      break;
 
-    case elfcpp::R_MIPS_REL32:
-      gold_unreachable();
+      bool update_got_entry = false;
+      switch (r_types[i])
+        {
+        case elfcpp::R_MIPS_NONE:
+          break;
+        case elfcpp::R_MIPS_16:
+          reloc_status = Reloc_funcs::rel16(view, object, psymval, r_addend,
+                                            extract_addend, calculate_only,
+                                            &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_PC32:
-      reloc_status = Reloc_funcs::relpc32(view, object, psymval, address,
-                                          r_addend, extract_addend, r_type);
-      break;
+        case elfcpp::R_MIPS_32:
+          if (should_apply_static_reloc(mips_sym, r_types[i], output_section,
+                                        target))
+            reloc_status = Reloc_funcs::rel32(view, object, psymval, r_addend,
+                                              extract_addend, calculate_only,
+                                              &calculated_value);
+          if (mips_sym != NULL
+              && (mips_sym->is_mips16() || mips_sym->is_micromips())
+              && mips_sym->global_got_area() == GGA_RELOC_ONLY)
+            {
+              // If mips_sym->has_mips16_fn_stub() is false, symbol value is
+              // already updated by adding +1.
+              if (mips_sym->has_mips16_fn_stub())
+                {
+                  gold_assert(mips_sym->need_fn_stub());
+                  Mips16_stub_section<size, big_endian>* fn_stub =
+                    mips_sym->template get_mips16_fn_stub<big_endian>();
 
-    case elfcpp::R_MIPS16_26:
-      // The calculation for R_MIPS16_26 is just the same as for an
-      // R_MIPS_26.  It's only the storage of the relocated field into
-      // the output file that's different.  So, we just fall through to the
-      // R_MIPS_26 case here.
-    case elfcpp::R_MIPS_26:
-    case elfcpp::R_MICROMIPS_26_S1:
-      reloc_status = Reloc_funcs::rel26(view, object, psymval, address,
-          gsym == NULL, r_addend, extract_addend, gsym, cross_mode_jump, r_type,
-          target->jal_to_bal());
-      break;
+                  symval.set_output_value(fn_stub->output_address());
+                  psymval = &symval;
+                }
+              got_offset = mips_sym->global_gotoffset();
+              update_got_entry = true;
+            }
+          break;
 
-    case elfcpp::R_MIPS_HI16:
-    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, r_sym,
-                                          extract_addend);
-      break;
+        case elfcpp::R_MIPS_64:
+          if (should_apply_static_reloc(mips_sym, r_types[i], output_section,
+                                        target))
+            reloc_status = Reloc_funcs::rel64(view, object, psymval, r_addend,
+                                              extract_addend, calculate_only,
+                                              &calculated_value, false);
+          else if (target->is_output_n64() && r_addend != 0)
+            // Only apply the addend.  The static relocation was RELA, but the
+            // dynamic relocation is REL, so we need to apply the addend.
+            reloc_status = Reloc_funcs::rel64(view, object, psymval, r_addend,
+                                              extract_addend, calculate_only,
+                                              &calculated_value, true);
+          break;
+        case elfcpp::R_MIPS_REL32:
+          gold_unreachable();
 
-    case elfcpp::R_MIPS_LO16:
-    case elfcpp::R_MIPS16_LO16:
-    case elfcpp::R_MICROMIPS_LO16:
-    case elfcpp::R_MICROMIPS_HI0_LO16:
-      reloc_status = Reloc_funcs::rello16(target, view, object, psymval,
-                                          r_addend, extract_addend, address,
-                                          gp_disp, r_type, r_sym);
-      break;
+        case elfcpp::R_MIPS_PC32:
+          reloc_status = Reloc_funcs::relpc32(view, object, psymval, address,
+                                              r_addend, extract_addend,
+                                              calculate_only,
+                                              &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_LITERAL:
-    case elfcpp::R_MICROMIPS_LITERAL:
-      // Because we don't merge literal sections, we can handle this
-      // just like R_MIPS_GPREL16.  In the long run, we should merge
-      // shared literals, and then we will need to additional work
-      // here.
+        case elfcpp::R_MIPS16_26:
+          // The calculation for R_MIPS16_26 is just the same as for an
+          // R_MIPS_26.  It's only the storage of the relocated field into
+          // the output file that's different.  So, we just fall through to the
+          // R_MIPS_26 case here.
+        case elfcpp::R_MIPS_26:
+        case elfcpp::R_MICROMIPS_26_S1:
+          reloc_status = Reloc_funcs::rel26(view, object, psymval, address,
+              gsym == NULL, r_addend, extract_addend, gsym, cross_mode_jump,
+              r_types[i], target->jal_to_bal(), calculate_only,
+              &calculated_value);
+          break;
 
-      // Fall through.
+        case elfcpp::R_MIPS_HI16:
+        case elfcpp::R_MIPS16_HI16:
+        case elfcpp::R_MICROMIPS_HI16:
+          if (rel_type == elfcpp::SHT_RELA)
+            reloc_status = Reloc_funcs::do_relhi16(view, object, psymval,
+                                                   r_addend, address,
+                                                   gp_disp, r_types[i],
+                                                   extract_addend, 0,
+                                                   target, calculate_only,
+                                                   &calculated_value);
+          else if (rel_type == elfcpp::SHT_REL)
+            reloc_status = Reloc_funcs::relhi16(view, object, psymval, r_addend,
+                                                address, gp_disp, r_types[i],
+                                                r_sym, extract_addend);
+          else
+            gold_unreachable();
+          break;
 
-    case elfcpp::R_MIPS_GPREL16:
-    case elfcpp::R_MIPS16_GPREL:
-    case elfcpp::R_MICROMIPS_GPREL7_S2:
-    case elfcpp::R_MICROMIPS_GPREL16:
-      reloc_status = Reloc_funcs::relgprel(view, object, psymval,
-                                           target->adjusted_gp_value(object),
-                                           r_addend, extract_addend,
-                                           gsym == NULL, r_type);
-      break;
+        case elfcpp::R_MIPS_LO16:
+        case elfcpp::R_MIPS16_LO16:
+        case elfcpp::R_MICROMIPS_LO16:
+        case elfcpp::R_MICROMIPS_HI0_LO16:
+          reloc_status = Reloc_funcs::rello16(target, view, object, psymval,
+                                              r_addend, extract_addend, address,
+                                              gp_disp, r_types[i], r_sym,
+                                              rel_type, calculate_only,
+                                              &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_PC16:
-      reloc_status = Reloc_funcs::relpc16(view, object, psymval, address,
-                                          r_addend, extract_addend, r_type);
-      break;
-    case elfcpp::R_MICROMIPS_PC7_S1:
-      reloc_status = Reloc_funcs::relmicromips_pc7_s1(view, object, psymval,
-                                                      address, r_addend,
-                                                      extract_addend, r_type);
-      break;
-    case elfcpp::R_MICROMIPS_PC10_S1:
-      reloc_status = Reloc_funcs::relmicromips_pc10_s1(view, object, psymval,
-                                                       address, r_addend,
-                                                       extract_addend, r_type);
-      break;
-    case elfcpp::R_MICROMIPS_PC16_S1:
-      reloc_status = Reloc_funcs::relmicromips_pc16_s1(view, object, psymval,
-                                                       address, r_addend,
-                                                       extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_GPREL32:
-      reloc_status = Reloc_funcs::relgprel32(view, object, psymval,
-                                             target->adjusted_gp_value(object),
-                                             r_addend, extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_GOT_HI16:
-    case elfcpp::R_MIPS_CALL_HI16:
-    case elfcpp::R_MICROMIPS_GOT_HI16:
-    case elfcpp::R_MICROMIPS_CALL_HI16:
-      if (gsym != NULL)
-        got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD,
-                                                       object);
-      else
-        got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_STANDARD,
-                                                       object);
-      gp_offset = target->got_section()->gp_offset(got_offset, object);
-      reloc_status = Reloc_funcs::relgot_hi16(view, gp_offset, r_type);
-      update_got_entry = changed_symbol_value;
-      break;
+        case elfcpp::R_MIPS_LITERAL:
+        case elfcpp::R_MICROMIPS_LITERAL:
+          // Because we don't merge literal sections, we can handle this
+          // just like R_MIPS_GPREL16.  In the long run, we should merge
+          // shared literals, and then we will need to additional work
+          // here.
 
-    case elfcpp::R_MIPS_GOT_LO16:
-    case elfcpp::R_MIPS_CALL_LO16:
-    case elfcpp::R_MICROMIPS_GOT_LO16:
-    case elfcpp::R_MICROMIPS_CALL_LO16:
-      if (gsym != NULL)
-        got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD,
-                                                       object);
-      else
-        got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_STANDARD,
-                                                       object);
-      gp_offset = target->got_section()->gp_offset(got_offset, object);
-      reloc_status = Reloc_funcs::relgot_lo16(view, gp_offset, r_type);
-      update_got_entry = changed_symbol_value;
-      break;
+          // Fall through.
 
-    case elfcpp::R_MIPS_GOT_DISP:
-    case elfcpp::R_MICROMIPS_GOT_DISP:
-      if (gsym != NULL)
-        got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD,
-                                                       object);
-      else
-        got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_STANDARD,
-                                                       object);
-      gp_offset = target->got_section()->gp_offset(got_offset, object);
-      reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type);
-      break;
+        case elfcpp::R_MIPS_GPREL16:
+        case elfcpp::R_MIPS16_GPREL:
+        case elfcpp::R_MICROMIPS_GPREL7_S2:
+        case elfcpp::R_MICROMIPS_GPREL16:
+          reloc_status = Reloc_funcs::relgprel(view, object, psymval,
+                                             target->adjusted_gp_value(object),
+                                             r_addend, extract_addend,
+                                             gsym == NULL, r_types[i],
+                                             calculate_only, &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_CALL16:
-    case elfcpp::R_MIPS16_CALL16:
-    case elfcpp::R_MICROMIPS_CALL16:
-      gold_assert(gsym != NULL);
-      got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD,
-                                                     object);
-      gp_offset = target->got_section()->gp_offset(got_offset, object);
-      reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type);
-      // TODO(sasa): We should also initialize update_got_entry in other places
-      // where relgot is called.
-      update_got_entry = changed_symbol_value;
-      break;
+        case elfcpp::R_MIPS_PC16:
+          reloc_status = Reloc_funcs::relpc16(view, object, psymval, address,
+                                              r_addend, extract_addend,
+                                              calculate_only,
+                                              &calculated_value);
+          break;
+        case elfcpp::R_MICROMIPS_PC7_S1:
+          reloc_status = Reloc_funcs::relmicromips_pc7_s1(view, object, psymval,
+                                                        address, r_addend,
+                                                        extract_addend,
+                                                        calculate_only,
+                                                        &calculated_value);
+          break;
+        case elfcpp::R_MICROMIPS_PC10_S1:
+          reloc_status = Reloc_funcs::relmicromips_pc10_s1(view, object,
+                                                       psymval, address,
+                                                       r_addend, extract_addend,
+                                                       calculate_only,
+                                                       &calculated_value);
+          break;
+        case elfcpp::R_MICROMIPS_PC16_S1:
+          reloc_status = Reloc_funcs::relmicromips_pc16_s1(view, object,
+                                                       psymval, address,
+                                                       r_addend, extract_addend,
+                                                       calculate_only,
+                                                       &calculated_value);
+          break;
+        case elfcpp::R_MIPS_GPREL32:
+          reloc_status = Reloc_funcs::relgprel32(view, object, psymval,
+                                              target->adjusted_gp_value(object),
+                                              r_addend, extract_addend,
+                                              calculate_only,
+                                              &calculated_value);
+          break;
+        case elfcpp::R_MIPS_GOT_HI16:
+        case elfcpp::R_MIPS_CALL_HI16:
+        case elfcpp::R_MICROMIPS_GOT_HI16:
+        case elfcpp::R_MICROMIPS_CALL_HI16:
+          if (gsym != NULL)
+            got_offset = target->got_section()->got_offset(gsym,
+                                                           GOT_TYPE_STANDARD,
+                                                           object);
+          else
+            got_offset = target->got_section()->got_offset(r_sym,
+                                                           GOT_TYPE_STANDARD,
+                                                           object, r_addend);
+          gp_offset = target->got_section()->gp_offset(got_offset, object);
+          reloc_status = Reloc_funcs::relgot_hi16(view, gp_offset,
+                                                  calculate_only,
+                                                  &calculated_value);
+          update_got_entry = changed_symbol_value;
+          break;
 
-    case elfcpp::R_MIPS_GOT16:
-    case elfcpp::R_MIPS16_GOT16:
-    case elfcpp::R_MICROMIPS_GOT16:
-      if (gsym != NULL)
-        {
+        case elfcpp::R_MIPS_GOT_LO16:
+        case elfcpp::R_MIPS_CALL_LO16:
+        case elfcpp::R_MICROMIPS_GOT_LO16:
+        case elfcpp::R_MICROMIPS_CALL_LO16:
+          if (gsym != NULL)
+            got_offset = target->got_section()->got_offset(gsym,
+                                                           GOT_TYPE_STANDARD,
+                                                           object);
+          else
+            got_offset = target->got_section()->got_offset(r_sym,
+                                                           GOT_TYPE_STANDARD,
+                                                           object, r_addend);
+          gp_offset = target->got_section()->gp_offset(got_offset, object);
+          reloc_status = Reloc_funcs::relgot_lo16(view, gp_offset,
+                                                  calculate_only,
+                                                  &calculated_value);
+          update_got_entry = changed_symbol_value;
+          break;
+
+        case elfcpp::R_MIPS_GOT_DISP:
+        case elfcpp::R_MICROMIPS_GOT_DISP:
+        case elfcpp::R_MIPS_EH:
+          if (gsym != NULL)
+            got_offset = target->got_section()->got_offset(gsym,
+                                                           GOT_TYPE_STANDARD,
+                                                           object);
+          else
+            got_offset = target->got_section()->got_offset(r_sym,
+                                                           GOT_TYPE_STANDARD,
+                                                           object, r_addend);
+          gp_offset = target->got_section()->gp_offset(got_offset, object);
+          if (eh_reloc(r_types[i]))
+            reloc_status = Reloc_funcs::releh(view, gp_offset,
+                                              calculate_only,
+                                              &calculated_value);
+          else
+            reloc_status = Reloc_funcs::relgot(view, gp_offset,
+                                               calculate_only,
+                                               &calculated_value);
+          break;
+        case elfcpp::R_MIPS_CALL16:
+        case elfcpp::R_MIPS16_CALL16:
+        case elfcpp::R_MICROMIPS_CALL16:
+          gold_assert(gsym != NULL);
           got_offset = target->got_section()->got_offset(gsym,
                                                          GOT_TYPE_STANDARD,
                                                          object);
           gp_offset = target->got_section()->gp_offset(got_offset, object);
-          reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type);
-        }
-      else
-        reloc_status = Reloc_funcs::relgot16_local(view, object, psymval,
-                                                   r_addend, extract_addend,
-                                                   r_type, r_sym);
-      update_got_entry = changed_symbol_value;
-      break;
+          reloc_status = Reloc_funcs::relgot(view, gp_offset,
+                                             calculate_only, &calculated_value);
+          // TODO(sasa): We should also initialize update_got_entry
+          // in other place swhere relgot is called.
+          update_got_entry = changed_symbol_value;
+          break;
 
-    case elfcpp::R_MIPS_TLS_GD:
-    case elfcpp::R_MIPS16_TLS_GD:
-    case elfcpp::R_MICROMIPS_TLS_GD:
-      if (gsym != NULL)
-        got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_TLS_PAIR,
-                                                       object);
-      else
-        got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_TLS_PAIR,
-                                                       object);
-      gp_offset = target->got_section()->gp_offset(got_offset, object);
-      reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type);
-      break;
+        case elfcpp::R_MIPS_GOT16:
+        case elfcpp::R_MIPS16_GOT16:
+        case elfcpp::R_MICROMIPS_GOT16:
+          if (gsym != NULL)
+            {
+              got_offset = target->got_section()->got_offset(gsym,
+                                                             GOT_TYPE_STANDARD,
+                                                             object);
+              gp_offset = target->got_section()->gp_offset(got_offset, object);
+              reloc_status = Reloc_funcs::relgot(view, gp_offset,
+                                                 calculate_only,
+                                                 &calculated_value);
+            }
+          else
+            {
+              if (rel_type == elfcpp::SHT_RELA)
+                reloc_status = Reloc_funcs::do_relgot16_local(view, object,
+                                                         psymval, r_addend,
+                                                         extract_addend, 0,
+                                                         target,
+                                                         calculate_only,
+                                                         &calculated_value);
+              else if (rel_type == elfcpp::SHT_REL)
+                reloc_status = Reloc_funcs::relgot16_local(view, object,
+                                                           psymval, r_addend,
+                                                           extract_addend,
+                                                           r_types[i], r_sym);
+              else
+                gold_unreachable();
+            }
+          update_got_entry = changed_symbol_value;
+          break;
 
-    case elfcpp::R_MIPS_TLS_GOTTPREL:
-    case elfcpp::R_MIPS16_TLS_GOTTPREL:
-    case elfcpp::R_MICROMIPS_TLS_GOTTPREL:
-      if (gsym != NULL)
-        got_offset = target->got_section()->got_offset(gsym,
-                                                       GOT_TYPE_TLS_OFFSET,
-                                                       object);
-      else
-        got_offset = target->got_section()->got_offset(r_sym,
-                                                       GOT_TYPE_TLS_OFFSET,
-                                                       object);
-      gp_offset = target->got_section()->gp_offset(got_offset, object);
-      reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type);
-      break;
+        case elfcpp::R_MIPS_TLS_GD:
+        case elfcpp::R_MIPS16_TLS_GD:
+        case elfcpp::R_MICROMIPS_TLS_GD:
+          if (gsym != NULL)
+            got_offset = target->got_section()->got_offset(gsym,
+                                                           GOT_TYPE_TLS_PAIR,
+                                                           object);
+          else
+            got_offset = target->got_section()->got_offset(r_sym,
+                                                           GOT_TYPE_TLS_PAIR,
+                                                           object, r_addend);
+          gp_offset = target->got_section()->gp_offset(got_offset, object);
+          reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only,
+                                             &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_TLS_LDM:
-    case elfcpp::R_MIPS16_TLS_LDM:
-    case elfcpp::R_MICROMIPS_TLS_LDM:
-      // Relocate the field with the offset of the GOT entry for
-      // the module index.
-      got_offset = target->got_section()->tls_ldm_offset(object);
-      gp_offset = target->got_section()->gp_offset(got_offset, object);
-      reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type);
-      break;
+        case elfcpp::R_MIPS_TLS_GOTTPREL:
+        case elfcpp::R_MIPS16_TLS_GOTTPREL:
+        case elfcpp::R_MICROMIPS_TLS_GOTTPREL:
+          if (gsym != NULL)
+            got_offset = target->got_section()->got_offset(gsym,
+                                                           GOT_TYPE_TLS_OFFSET,
+                                                           object);
+          else
+            got_offset = target->got_section()->got_offset(r_sym,
+                                                           GOT_TYPE_TLS_OFFSET,
+                                                           object, r_addend);
+          gp_offset = target->got_section()->gp_offset(got_offset, object);
+          reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only,
+                                             &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_GOT_PAGE:
-    case elfcpp::R_MICROMIPS_GOT_PAGE:
-      reloc_status = Reloc_funcs::relgotpage(target, view, object, psymval,
-                                             r_addend, extract_addend, r_type);
-      break;
+        case elfcpp::R_MIPS_TLS_LDM:
+        case elfcpp::R_MIPS16_TLS_LDM:
+        case elfcpp::R_MICROMIPS_TLS_LDM:
+          // Relocate the field with the offset of the GOT entry for
+          // the module index.
+          got_offset = target->got_section()->tls_ldm_offset(object);
+          gp_offset = target->got_section()->gp_offset(got_offset, object);
+          reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only,
+                                             &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_GOT_OFST:
-    case elfcpp::R_MICROMIPS_GOT_OFST:
-      reloc_status = Reloc_funcs::relgotofst(target, view, object, psymval,
-                                             r_addend, extract_addend, local,
-                                             r_type);
-      break;
+        case elfcpp::R_MIPS_GOT_PAGE:
+        case elfcpp::R_MICROMIPS_GOT_PAGE:
+          reloc_status = Reloc_funcs::relgotpage(target, view, object, psymval,
+                                                 r_addend, extract_addend,
+                                                 calculate_only,
+                                                 &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_JALR:
-    case elfcpp::R_MICROMIPS_JALR:
-      // This relocation is only a hint.  In some cases, we optimize
-      // it into a bal instruction.  But we don't try to optimize
-      // when the symbol does not resolve locally.
-      if (gsym == NULL || symbol_calls_local(gsym, gsym->has_dynsym_index()))
-        reloc_status = Reloc_funcs::reljalr(view, object, psymval, address,
-                                            r_addend, extract_addend,
-                                            cross_mode_jump, r_type,
-                                            target->jalr_to_bal(),
-                                            target->jr_to_b());
-      break;
+        case elfcpp::R_MIPS_GOT_OFST:
+        case elfcpp::R_MICROMIPS_GOT_OFST:
+          reloc_status = Reloc_funcs::relgotofst(target, view, object, psymval,
+                                                 r_addend, extract_addend,
+                                                 local, calculate_only,
+                                                 &calculated_value);
+          break;
 
-    case elfcpp::R_MIPS_TLS_DTPREL_HI16:
-    case elfcpp::R_MIPS16_TLS_DTPREL_HI16:
-    case elfcpp::R_MICROMIPS_TLS_DTPREL_HI16:
-      reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval,
-                                             elfcpp::DTP_OFFSET, r_addend,
-                                             extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_TLS_DTPREL_LO16:
-    case elfcpp::R_MIPS16_TLS_DTPREL_LO16:
-    case elfcpp::R_MICROMIPS_TLS_DTPREL_LO16:
-      reloc_status = Reloc_funcs::tlsrello16(view, object, psymval,
-                                             elfcpp::DTP_OFFSET, r_addend,
-                                             extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_TLS_DTPREL32:
-    case elfcpp::R_MIPS_TLS_DTPREL64:
-      reloc_status = Reloc_funcs::tlsrel32(view, object, psymval,
-                                           elfcpp::DTP_OFFSET, r_addend,
-                                           extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_TLS_TPREL_HI16:
-    case elfcpp::R_MIPS16_TLS_TPREL_HI16:
-    case elfcpp::R_MICROMIPS_TLS_TPREL_HI16:
-      reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval,
-                                             elfcpp::TP_OFFSET, r_addend,
-                                             extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_TLS_TPREL_LO16:
-    case elfcpp::R_MIPS16_TLS_TPREL_LO16:
-    case elfcpp::R_MICROMIPS_TLS_TPREL_LO16:
-      reloc_status = Reloc_funcs::tlsrello16(view, object, psymval,
-                                             elfcpp::TP_OFFSET, r_addend,
-                                             extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_TLS_TPREL32:
-    case elfcpp::R_MIPS_TLS_TPREL64:
-      reloc_status = Reloc_funcs::tlsrel32(view, object, psymval,
-                                           elfcpp::TP_OFFSET, r_addend,
-                                           extract_addend, r_type);
-      break;
-    case elfcpp::R_MIPS_SUB:
-    case elfcpp::R_MICROMIPS_SUB:
-      reloc_status = Reloc_funcs::relsub(view, object, psymval, r_addend,
-                                         extract_addend, r_type);
-      break;
-    default:
-      gold_error_at_location(relinfo, relnum, r_offset,
-                             _("unsupported reloc %u"), r_type);
-      break;
-    }
+        case elfcpp::R_MIPS_JALR:
+        case elfcpp::R_MICROMIPS_JALR:
+          // This relocation is only a hint.  In some cases, we optimize
+          // it into a bal instruction.  But we don't try to optimize
+          // when the symbol does not resolve locally.
+          if (gsym == NULL
+              || symbol_calls_local(gsym, gsym->has_dynsym_index()))
+            reloc_status = Reloc_funcs::reljalr(view, object, psymval, address,
+                                                r_addend, extract_addend,
+                                                cross_mode_jump, r_types[i],
+                                                target->jalr_to_bal(),
+                                                target->jr_to_b(),
+                                                calculate_only,
+                                                &calculated_value);
+          break;
 
-  if (update_got_entry)
-    {
-      Mips_output_data_got<size, big_endian>* got = target->got_section();
-      if (mips_sym != NULL && mips_sym->get_applied_secondary_got_fixup())
-        got->update_got_entry(got->get_primary_got_offset(mips_sym),
-                              psymval->value(object, 0));
-      else
-        got->update_got_entry(got_offset, psymval->value(object, 0));
+        case elfcpp::R_MIPS_TLS_DTPREL_HI16:
+        case elfcpp::R_MIPS16_TLS_DTPREL_HI16:
+        case elfcpp::R_MICROMIPS_TLS_DTPREL_HI16:
+          reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval,
+                                                 elfcpp::DTP_OFFSET, r_addend,
+                                                 extract_addend, calculate_only,
+                                                 &calculated_value);
+          break;
+        case elfcpp::R_MIPS_TLS_DTPREL_LO16:
+        case elfcpp::R_MIPS16_TLS_DTPREL_LO16:
+        case elfcpp::R_MICROMIPS_TLS_DTPREL_LO16:
+          reloc_status = Reloc_funcs::tlsrello16(view, object, psymval,
+                                                 elfcpp::DTP_OFFSET, r_addend,
+                                                 extract_addend, calculate_only,
+                                                 &calculated_value);
+          break;
+        case elfcpp::R_MIPS_TLS_DTPREL32:
+        case elfcpp::R_MIPS_TLS_DTPREL64:
+          reloc_status = Reloc_funcs::tlsrel32(view, object, psymval,
+                                               elfcpp::DTP_OFFSET, r_addend,
+                                               extract_addend, calculate_only,
+                                               &calculated_value);
+          break;
+        case elfcpp::R_MIPS_TLS_TPREL_HI16:
+        case elfcpp::R_MIPS16_TLS_TPREL_HI16:
+        case elfcpp::R_MICROMIPS_TLS_TPREL_HI16:
+          reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval,
+                                                 elfcpp::TP_OFFSET, r_addend,
+                                                 extract_addend, calculate_only,
+                                                 &calculated_value);
+          break;
+        case elfcpp::R_MIPS_TLS_TPREL_LO16:
+        case elfcpp::R_MIPS16_TLS_TPREL_LO16:
+        case elfcpp::R_MICROMIPS_TLS_TPREL_LO16:
+          reloc_status = Reloc_funcs::tlsrello16(view, object, psymval,
+                                                 elfcpp::TP_OFFSET, r_addend,
+                                                 extract_addend, calculate_only,
+                                                 &calculated_value);
+          break;
+        case elfcpp::R_MIPS_TLS_TPREL32:
+        case elfcpp::R_MIPS_TLS_TPREL64:
+          reloc_status = Reloc_funcs::tlsrel32(view, object, psymval,
+                                               elfcpp::TP_OFFSET, r_addend,
+                                               extract_addend, calculate_only,
+                                               &calculated_value);
+          break;
+        case elfcpp::R_MIPS_SUB:
+        case elfcpp::R_MICROMIPS_SUB:
+          reloc_status = Reloc_funcs::relsub(view, object, psymval, r_addend,
+                                             extract_addend,
+                                             calculate_only, &calculated_value);
+          break;
+        default:
+          gold_error_at_location(relinfo, relnum, r_offset,
+                                 _("unsupported reloc %u"), r_types[i]);
+          break;
+        }
+
+      if (update_got_entry)
+        {
+          Mips_output_data_got<size, big_endian>* got = target->got_section();
+          if (mips_sym != NULL && mips_sym->get_applied_secondary_got_fixup())
+            got->update_got_entry(got->get_primary_got_offset(mips_sym),
+                                  psymval->value(object, 0));
+          else
+            got->update_got_entry(got_offset, psymval->value(object, 0));
+        }
+
+      r_addend = calculated_value;
     }
 
+  bool jal_shuffle = jal_reloc(r_type) ? !parameters->options().relocatable()
+                                       : false;
+  Reloc_funcs::mips_reloc_shuffle(view, r_type, jal_shuffle);
+
   // Report any errors.
   switch (reloc_status)
     {
@@ -10489,6 +11171,7 @@ Target_mips<size, big_endian>::Scan::get_reference_flags(
     case elfcpp::R_MICROMIPS_GOT_LO16:
     case elfcpp::R_MICROMIPS_CALL_HI16:
     case elfcpp::R_MICROMIPS_CALL_LO16:
+    case elfcpp::R_MIPS_EH:
       // Absolute in GOT.
       return Symbol::RELATIVE_REF;
 
@@ -10660,7 +11343,7 @@ const Target::Target_info Target_mips<size, big_endian>::mips_info =
   true,                 // is_default_stack_executable
   false,                // can_icf_inline_merge_sections
   '\0',                 // wrap_char
-  "/lib/ld.so.1",       // dynamic_linker
+  size == 32 ? "/lib/ld.so.1" : "/lib64/ld.so.1",      // dynamic_linker
   0x400000,             // default_text_segment_address
   64 * 1024,            // abi_pagesize (overridable by -z max-page-size)
   4 * 1024,             // common_pagesize (overridable by -z common-page-size)
@@ -10729,8 +11412,8 @@ public:
                   (big_endian ? "elf64-tradbigmips" : "elf64-tradlittlemips") :
                   (big_endian ? "elf32-tradbigmips" : "elf32-tradlittlemips")),
                 (size == 64 ?
-                  (big_endian ? "elf64-tradbigmips" : "elf64-tradlittlemips") :
-                  (big_endian ? "elf32-tradbigmips" : "elf32-tradlittlemips")))
+                  (big_endian ? "elf64btsmip" : "elf64ltsmip") :
+                  (big_endian ? "elf32btsmip" : "elf32ltsmip")))
   { }
 
   Target* do_instantiate_target()

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]