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 v2 3/4] gold: Add Mips64 support.


Changes for output.h is moved from PATCH 3, and there are also some small changes in mips.cc in this patch.

Regards,
Vladimir.

Changelog -

        * mips.cc: Add Mips64 support.
	* output.h (Output_reloc<SHT_REL>::get_address): Change from private to public.
	(Output_reloc<SHT_REL>::get_symbol_index): Likewise.
	(Output_data_reloc_base::add): Make virtual.

diff --git a/gold/mips.cc b/gold/mips.cc
index 051d49a..f616321 100644
--- a/gold/mips.cc
+++ b/gold/mips.cc
@@ -132,6 +132,48 @@ 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.
+template<int size, bool big_endian>
+static inline bool
+is_readonly_section(Mips_relobj<size, big_endian>* object,
+                    unsigned int data_shndx)
+{
+  if (object->section_flags(data_shndx) & elfcpp::SHF_ALLOC)
+    return false;
+
+  if (object->section_flags(data_shndx) & elfcpp::SHF_WRITE)
+    return false;
+
+  if (object->section_type(data_shndx) & elfcpp::SHT_NOBITS)
+    return false;
+
+  return true;
+}
+
+// Get r_ssym.
+static inline unsigned char
+get_r_ssym(unsigned int r_type)
+{
+  return (r_type >> 24) & 0xff;
+}
+
+// Extract r_type.
+static inline unsigned int
+get_r_type(unsigned int r_type, unsigned int num) {
+  if (num > 2)
+    return elfcpp::R_MIPS_NONE;
+  return (r_type >> num * 8) & 0xff;
+}
+
 // 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 +274,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 +449,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), shndx_(shndx),
+      is_section_symbol_(is_section_symbol)
   { 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), shndx_(-1U),
+      is_section_symbol_(false)
   { this->d.sym = sym; }
 
   // Return whether this entry is for a local symbol.
@@ -501,6 +551,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_;
@@ -524,6 +579,9 @@ class Mips_got_entry
 
   // For local GOT entries, section index of the local symbol.
   unsigned int shndx_;
+
+  // Whether this is a STT_SECTION symbol.
+  bool is_section_symbol_;
 };
 
 // Hash for Mips_got_entry.
@@ -645,7 +703,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
@@ -1754,6 +1813,10 @@ class Mips_relobj : public Sized_relobj_file<size, big_endian>
   { return this->cprmask4_; }
 
  protected:
+  // The name of the options section.
+  const char* mips_elf_options_section_name()
+  { return this->is_newabi() ? ".MIPS.options" : ".options"; }
+
   // Count the local symbols.
   void
   do_count_local_symbols(Stringpool_template<char>*,
@@ -1861,10 +1924,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 +2067,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 +2320,139 @@ class Mips_output_data_la25_stub : public Output_section_data
   Unordered_set<Mips_symbol<size>*> symbols_;
 };
 
+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:
+  typedef Output_reloc<sh_type, dynamic, size, big_endian> Output_reloc_type;
+  static const int reloc_size =
+    Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+  Mips_output_data_reloc(bool sort_relocs, Target_mips<size, big_endian>* target)
+    : Output_data_reloc<sh_type, dynamic, size, big_endian>(sort_relocs),
+      target_(target)
+  { }
+
+ protected:
+  // Write out the data.
+  void
+  do_write(Output_file*);
+
+  // Add a relocation entry.
+  void
+  add(Output_data* od, const Output_reloc_type& reloc)
+  {
+    this->mips_relocs_.push_back(reloc);
+    this->set_current_data_size(this->mips_relocs_.size() * reloc_size);
+    if (dynamic)
+      od->add_dynamic_reloc();
+    if (reloc.is_relative())
+      this->bump_relative_reloc_count();
+    Sized_relobj<size, big_endian>* relobj = reloc.get_relobj();
+    if (relobj != NULL)
+      relobj->add_dyn_reloc(this->mips_relocs_.size() - 1);
+  }
+
+ private:
+  typedef std::vector<Output_reloc_type> Relocs;
+
+  // The class used to sort the relocations.
+  struct Sort_relocs_comparison
+  {
+    bool
+    operator()(const Output_reloc_type& r1, const Output_reloc_type& r2) const
+    { return r1.sort_before(r2); }
+  };
+
+  // The relocations in this section.
+  Relocs mips_relocs_;
+
+  // Swap out a MIPS 64-bit Rel reloc.
+  void
+  mips_elf64_swap_reloc_out(
+    // Address of relocation.
+    typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+    unsigned int r_sym,  // Symbol index.
+    unsigned char r_ssym,  // Special symbol.
+    unsigned char r_type3,  // Third relocation.
+    unsigned char r_type2,  // Second relocation.
+    unsigned char r_type,  // First relocation.
+    unsigned char* dst)
+  {
+    elfcpp::Swap<64, big_endian>::writeval(dst, r_offset);
+    elfcpp::Swap<32, big_endian>::writeval(dst + 8, r_sym);
+    elfcpp::Swap<8, big_endian>::writeval(dst + 12, r_ssym);
+    elfcpp::Swap<8, big_endian>::writeval(dst + 13, r_type3);
+    elfcpp::Swap<8, big_endian>::writeval(dst + 14, r_type2);
+    elfcpp::Swap<8, big_endian>::writeval(dst + 15, r_type);
+  }
+
+  // The target.
+  Target_mips<size, big_endian>* target_;
+};
+
+// Write out relocation data.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+void
+Mips_output_data_reloc<sh_type, dynamic, size, big_endian>::do_write(
+    Output_file* of)
+{
+  typedef typename Mips_output_data_reloc<sh_type, dynamic, size, big_endian>
+    ::Relocs Relocs;
+  typedef typename Mips_output_data_reloc<sh_type, dynamic, size, big_endian>
+    ::Sort_relocs_comparison Sort_relocs_comparison;
+
+  const off_t off = this->offset();
+  const off_t oview_size = this->data_size();
+  unsigned char* const oview = of->get_output_view(off, oview_size);
+
+  if (this->sort_relocs())
+    {
+      gold_assert(dynamic);
+      std::sort(this->mips_relocs_.begin(), this->mips_relocs_.end(),
+		Sort_relocs_comparison());
+    }
+
+  int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+  unsigned char* pov = oview;
+  for (typename Relocs::const_iterator p = this->mips_relocs_.begin();
+       p != this->mips_relocs_.end();
+       ++p)
+    {
+      if (!this->target_->is_output_n64())
+        p->write(pov);
+      else
+        {
+          if (p->type() != elfcpp::R_MIPS_REL32)
+            mips_elf64_swap_reloc_out(p->get_address(), p->get_symbol_index(),
+                                      0, 0, 0, p->type(), pov);
+          else
+            mips_elf64_swap_reloc_out(p->get_address(), p->get_symbol_index(),
+                                      0, elfcpp::R_MIPS_NONE, elfcpp::R_MIPS_64,
+                                      p->type(), pov);
+        }
+      pov += reloc_size;
+    }
+
+  gold_assert(pov - oview == oview_size);
+
+  of->write_output_view(off, oview_size, oview);
+
+  // We no longer need the relocation entries.
+  this->mips_relocs_.clear();
+}
+
 // 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,
@@ -2272,7 +2463,7 @@ class Mips_output_data_plt : public Output_section_data
       plt_mips_offset_(0), plt_comp_offset_(0), plt_header_size_(0),
       target_(target)
   {
-    this->rel_ = new Reloc_section(false);
+    this->rel_ = new Reloc_section(false, this->target_);
     layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
                                     elfcpp::SHF_ALLOC, this->rel_,
                                     ORDER_DYNAMIC_PLT_RELOCS, false);
@@ -2864,21 +3055,21 @@ 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 elfcpp::Swap<64, big_endian>::Valtype Valtype64;
 
  public:
   Target_mips(const Target::Target_info* info = &mips_info)
     : Sized_target<size, big_endian>(info), got_(NULL), gp_(NULL), plt_(NULL),
       got_plt_(NULL), rel_dyn_(NULL), copy_relocs_(),
       dyn_relocs_(), la25_stub_(NULL), mips_mach_extensions_(),
-      mips_stubs_(NULL), ei_class_(0), mach_(0), layout_(NULL),
+      mips_stubs_(NULL), mach_(0), layout_(NULL),
       got16_addends_(), entry_symbol_is_compressed_(false), insn32_(false)
   {
+    ei_class_ = size == 64 ? elfcpp::ELFCLASS64 : elfcpp::ELFCLASS32;
     this->add_machine_extensions();
   }
 
@@ -2889,6 +3080,10 @@ class Target_mips : public Sized_target<size, big_endian>
   // offsets from $gp.
   static const unsigned int MIPS_GOT_MAX_SIZE = MIPS_GP_OFFSET + 0x7fff;
 
+  bool
+  is_mips64el() const
+  { return size == 64 && !big_endian; }
+
   // Make a new symbol table entry for the Mips target.
   Sized_symbol<size>*
   make_symbol() const
@@ -3382,12 +3577,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.
@@ -3600,13 +3795,14 @@ class Target_mips : public Sized_target<size, big_endian>
   copy_reloc(Symbol_table* symtab, Layout* layout,
              Sized_relobj_file<size, big_endian>* object,
              unsigned int shndx, Output_section* output_section,
-             Symbol* sym, const elfcpp::Rel<size, big_endian>& reloc)
+             Symbol* sym, Mips_address r_offset,
+             typename elfcpp::Elf_types<size>::Elf_WXword r_info)
   {
-    unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
+    unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
     this->copy_relocs_.copy_reloc(symtab, layout,
                                   symtab->get_sized_symbol<size>(sym),
                                   object, shndx, output_section,
-				  r_type, reloc.get_r_offset(), 0,
+                                  r_type, r_offset, 0,
                                   this->rel_dyn_section(layout));
   }
 
@@ -3785,8 +3981,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
@@ -3963,18 +4161,24 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   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, unsigned int r_type, bool calculate_only,
+        Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<16, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<16>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -3985,15 +4189,21 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   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, unsigned int r_type, bool calculate_only,
+        Valtype64 &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);
+                        : addend_a);
+    Valtype x = psymval->value(object, addend);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4003,11 +4213,12 @@ 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, Valtype64 &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.
@@ -4027,7 +4238,11 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
           }
       }
 
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
+    if (calculate_only)
+      calculated_value = val;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4036,15 +4251,21 @@ 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, unsigned int r_type,
+          bool calculate_only, Valtype64 &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);
+                        : addend_a);
+    Valtype x = psymval->value(object, addend) - address;
+
+    if (calculate_only)
+       calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4055,13 +4276,13 @@ 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, Valtype64 &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)
@@ -4074,7 +4295,7 @@ 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"));
@@ -4086,7 +4307,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
@@ -4098,7 +4319,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)))
           {
@@ -4136,7 +4357,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."));
@@ -4165,7 +4386,11 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
           }
       }
 
-    elfcpp::Swap<32, big_endian>::writeval(wv, val);
+    if (calculate_only)
+      calculated_value = val;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, !parameters->options().relocatable());
     return This::STATUS_OKAY;
   }
@@ -4174,18 +4399,25 @@ 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, unsigned int r_type,
+          bool calculate_only, Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x >> 2;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<18>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -4198,18 +4430,24 @@ 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)
+                      unsigned int r_type, bool calculate_only,
+                      Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x >> 1;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<8>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -4222,18 +4460,25 @@ 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)
+                       unsigned int r_type, bool calculate_only,
+                       Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x >> 1;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<11>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -4246,18 +4491,25 @@ 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)
+                       unsigned int r_type, bool calculate_only,
+                       Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x >> 1;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<17>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -4284,13 +4536,14 @@ 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,
+             Valtype64 &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;
@@ -4321,9 +4574,14 @@ 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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      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
@@ -4349,13 +4607,14 @@ 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_hi,
                     unsigned int r_type, bool extract_addend,
-                    Valtype32 addend_lo, Target_mips<size, big_endian>* target)
+                    Valtype32 addend_lo, Target_mips<size, big_endian>* target,
+                    bool calculate_only, Valtype64 &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.
@@ -4366,9 +4625,14 @@ 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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<16>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -4381,57 +4645,63 @@ 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, Valtype64 &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)
+    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))
+        // 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))
+              {
+                if (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) == 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))
+              {
+                if (do_relgot16_local(got16.view, got16.object, got16.psymval,
+                                    got16.addend, got16.r_type,
+                                    got16.extract_addend, addend,
+                                    target, calculate_only,
+                                    calculated_value) == 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
@@ -4464,7 +4734,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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4476,40 +4751,72 @@ 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, unsigned int r_type,
+         bool calculate_only, Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      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);
   }
 
+  // R_MIPS_EH
+  static inline typename This::Status
+  releh(unsigned char* view, int gp_offset, unsigned int r_type,
+         bool calculate_only, Valtype64 &calculated_value)
+  {
+    mips_reloc_unshuffle(view, r_type, false);
+    Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+    Valtype x = gp_offset;
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
+    mips_reloc_shuffle(view, r_type, false);
+    return (Bits<32>::has_overflow32(x)
+            ? This::STATUS_OVERFLOW
+            : This::STATUS_OKAY);
+  }
+
   // R_MIPS_GOT_PAGE, R_MICROMIPS_GOT_PAGE
   static inline typename This::Status
   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, unsigned int r_type, bool calculate_only,
+             Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<16>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -4521,18 +4828,19 @@ 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, unsigned int r_type,
+             bool calculate_only, Valtype64 &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.
@@ -4545,7 +4853,12 @@ 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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return (Bits<16>::has_overflow32(x)
             ? This::STATUS_OVERFLOW
@@ -4555,15 +4868,21 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   // 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, unsigned int r_type,
+              bool calculate_only, Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4571,14 +4890,20 @@ class Mips_relocate_functions : public Relocate_functions<size, big_endian>
   // 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, unsigned int r_type,
+              bool calculate_only, Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4589,13 +4914,14 @@ 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,
+           Valtype64 &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)
@@ -4610,7 +4936,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
@@ -4624,9 +4950,14 @@ 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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
-    if (Bits<16>::has_overflow32(x))
+    if (!calculate_only && Bits<16>::has_overflow32(x))
       {
         gold_error(_("small-data section exceeds 64KB; lower small-data size "
                      "limit (see option -G)"));
@@ -4639,16 +4970,22 @@ 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, unsigned int r_type,
+             bool calculate_only, Valtype64 &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);
+    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);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
  }
@@ -4659,17 +4996,23 @@ 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, unsigned int r_type,
+             bool calculate_only, Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4680,17 +5023,23 @@ 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, unsigned int r_type,
+             bool calculate_only, Valtype64 &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);
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4700,16 +5049,22 @@ 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, unsigned int r_type,
+           bool calculate_only, Valtype64 &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);
+    Valtype x = psymval->value(object, addend) - tp_offset;
+
+    if (calculate_only)
+      calculated_value = x;
+    else
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+
     mips_reloc_shuffle(view, r_type, false);
     return This::STATUS_OKAY;
   }
@@ -4718,18 +5073,52 @@ 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, unsigned int r_type, bool calculate_only,
+         Valtype64 &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, unsigned int r_type, bool calculate_only,
+        Valtype64 &calculated_value, bool apply_addend_only)
+  {
+    mips_reloc_unshuffle(view, r_type, false);
+    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);
+      }
+
+    mips_reloc_shuffle(view, r_type, false);
+    return This::STATUS_OKAY;
+  }
+
 };
 
 template<int size, bool big_endian>
@@ -4749,12 +5138,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);
 }
 
@@ -4934,13 +5324,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);
+          }
         }
     }
 
@@ -5138,9 +5535,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());
             }
@@ -5150,7 +5548,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());
@@ -5163,12 +5562,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());
             }
@@ -5910,6 +6312,89 @@ Mips_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
           this->cprmask4_ = elfcpp::Swap<size, big_endian>::readval(view + 16);
         }
 
+      // 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 (shdr.get_sh_type() == elfcpp::SHT_MIPS_OPTIONS)
+        {
+          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] =
@@ -6242,7 +6727,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)
 };
@@ -7248,7 +7733,8 @@ Target_mips<size, big_endian>::rel_dyn_section(Layout* layout)
   if (this->rel_dyn_ == NULL)
     {
       gold_assert(layout != NULL);
-      this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
+      this->rel_dyn_ = new Reloc_section(parameters->options().combreloc(),
+                                         this);
       layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
                                       elfcpp::SHF_ALLOC, this->rel_dyn_,
                                       ORDER_DYNAMIC_RELOCS, false);
@@ -7528,7 +8014,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,
@@ -7539,19 +8025,34 @@ Target_mips<size, big_endian>::gc_process_relocs(
   typedef Target_mips<size, big_endian> Mips;
   typedef typename Target_mips<size, big_endian>::Scan Scan;
 
-  gold::gc_process_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan,
-                          typename Target_mips::Relocatable_size_for_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)
+    gold::gc_process_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan,
+                            typename Target_mips::Relocatable_size_for_reloc>(
+      symtab,
+      layout,
+      this,
+      object,
+      data_shndx,
+      prelocs,
+      reloc_count,
+      output_section,
+      needs_special_offset_handling,
+      local_symbol_count,
+      plocal_symbols);
+  else if (sh_type == elfcpp::SHT_RELA)
+    gold::gc_process_relocs<size, big_endian, Mips, elfcpp::SHT_RELA, Scan,
+                            typename Target_mips::Relocatable_size_for_reloc>(
+      symtab,
+      layout,
+      this,
+      object,
+      data_shndx,
+      prelocs,
+      reloc_count,
+      output_section,
+      needs_special_offset_handling,
+      local_symbol_count,
+      plocal_symbols);
 }
 
 // Scan relocations for a section.
@@ -8011,9 +8512,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);
         }
     }
 
@@ -8306,6 +8818,7 @@ Target_mips<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
     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:
@@ -8371,25 +8884,40 @@ Target_mips<size, big_endian>::scan_relocatable_relocs(
                         const unsigned char* plocal_symbols,
                         Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_REL);
-
   typedef Mips_scan_relocatable_relocs<big_endian, elfcpp::SHT_REL,
     Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  typedef Mips_scan_relocatable_relocs<big_endian, elfcpp::SHT_RELA,
+    Relocatable_size_for_reloc> Scan_relocatable_relocs_rela;
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_REL,
-    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)
+    gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_REL,
+      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)
+    gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+      Scan_relocatable_relocs_rela>(
+      symtab,
+      layout,
+      object,
+      data_shndx,
+      prelocs,
+      reloc_count,
+      output_section,
+      needs_special_offset_handling,
+      local_symbol_count,
+      plocal_symbols,
+      rr);
+}
 
 // Emit relocations for a section.
 
@@ -8410,20 +8938,32 @@ Target_mips<size, big_endian>::relocate_relocs(
                         unsigned char* reloc_view,
                         section_size_type reloc_view_size)
 {
-  gold_assert(sh_type == elfcpp::SHT_REL);
-
-  gold::relocate_relocs<size, big_endian, elfcpp::SHT_REL>(
-    relinfo,
-    prelocs,
-    reloc_count,
-    output_section,
-    offset_in_output_section,
-    rr,
-    view,
-    view_address,
-    view_size,
-    reloc_view,
-    reloc_view_size);
+  if (sh_type == elfcpp::SHT_REL)
+    gold::relocate_relocs<size, big_endian, elfcpp::SHT_REL>(
+      relinfo,
+      prelocs,
+      reloc_count,
+      output_section,
+      offset_in_output_section,
+      rr,
+      view,
+      view_address,
+      view_size,
+      reloc_view,
+      reloc_view_size);
+  else if (sh_type == elfcpp::SHT_RELA)
+    gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+      relinfo,
+      prelocs,
+      reloc_count,
+      output_section,
+      offset_in_output_section,
+      rr,
+      view,
+      view_address,
+      view_size,
+      reloc_view,
+      reloc_view_size);
 }
 
 // Perform target-specific processing in a relocatable link.  This is
@@ -8521,7 +9061,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.
-
+  Valtype64 calculated_value = 0;
   const Symbol_value<size>* psymval = object->local_symbol(r_sym);
 
   unsigned char* paddend = view + offset;
@@ -8531,7 +9071,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:
@@ -8663,6 +9204,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;
@@ -8673,7 +9215,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
@@ -8685,7 +9228,9 @@ Target_mips<size, big_endian>::Scan::local(
       Mips_output_data_got<size, big_endian>* got =
         target->got_section(symtab, layout);
       unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
-      got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U);
+      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)
@@ -8818,6 +9363,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(mips_obj, data_shndx))
+              break;
             Reloc_section* rel_dyn = target->rel_dyn_section(layout);
             unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
             rel_dyn->add_symbolless_local_addend(object, r_sym,
@@ -8864,7 +9411,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
               {
@@ -8881,7 +9428,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
               {
@@ -8899,7 +9446,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
               {
@@ -9008,7 +9555,7 @@ Target_mips<size, big_endian>::Scan::local(
     &reloc,
     (const elfcpp::Rel<size, big_endian>*) NULL,
     elfcpp::SHT_RELA,
-    r_type,
+    r_type & 0xff,
     lsym, is_discarded);
 }
 
@@ -9119,6 +9666,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;
@@ -9145,14 +9693,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(mips_obj, data_shndx)
+          || mips_obj->is_pic())))
+          && (mips_obj->section_flags(data_shndx) & 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;
         }
@@ -9249,8 +9797,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_offset, r_info);
             }
           else if (can_make_dynamic)
             {
@@ -9287,6 +9835,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 =
@@ -9374,7 +9923,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
               {
@@ -9477,7 +10026,7 @@ Target_mips<size, big_endian>::Scan::global(
     &reloc,
     (const elfcpp::Rel<size, big_endian>*) NULL,
     elfcpp::SHT_RELA,
-    r_type,
+    r_type & 0xff,
     gsym);
 }
 
@@ -9508,11 +10057,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,
@@ -9569,7 +10121,7 @@ Target_mips<size, big_endian>::Relocate::relocate(
                         const elfcpp::Rela<size, big_endian>* rela,
                         const elfcpp::Rel<size, big_endian>* rel,
                         unsigned int rel_type,
-                        unsigned int r_type,
+                        unsigned int rel_kind,
                         const Sized_symbol<size>* gsym,
                         const Symbol_value<size>* psymval,
                         unsigned char* view,
@@ -9599,6 +10151,14 @@ Target_mips<size, big_endian>::Relocate::relocate(
   Mips_relobj<size, big_endian>* object =
     Mips_relobj<size, big_endian>::as_mips_relobj(relinfo->object);
 
+  unsigned char r_ssym = 0;
+  unsigned int r_type = rel_kind;
+  if (object->is_n64())
+    {
+      r_ssym = get_r_ssym(r_type);
+      r_type &= 0xff;
+    }
+
   unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
   bool target_is_16_bit_code = false;
   bool target_is_micromips_code = false;
@@ -9854,318 +10414,465 @@ 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;
+  Valtype64 calculated_value = 0;
   bool extract_addend = rel_type == elfcpp::SHT_REL;
-  switch (r_type)
+  // Value of the symbol for r_type2 and r_type3.
+  Symbol_value<size> symval2;
+
+  // 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.
+  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;
+      r_type = get_r_type(rel_kind, i);
+      if (r_type == 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)
+      calculate_only = get_r_type(rel_kind, i+1) != elfcpp::R_MIPS_NONE;
+
+      bool update_got_entry = false;
+      switch (r_type)
         {
-          // If mips_sym->has_mips16_fn_stub() is false, symbol value is
-          // already updated by adding +1.
-          if (mips_sym->has_mips16_fn_stub())
+        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,
+                                            calculate_only, calculated_value);
+          break;
+
+        case elfcpp::R_MIPS_32:
+          if (should_apply_static_reloc(mips_sym, r_type, output_section,
+                                        target))
+            reloc_status = Reloc_funcs::rel32(view, object, psymval, r_addend,
+                                              extract_addend, r_type,
+                                              calculate_only, calculated_value);
+          if (mips_sym != NULL
+              && (mips_sym->is_mips16() || mips_sym->is_micromips())
+              && mips_sym->global_got_area() == GGA_RELOC_ONLY)
             {
-              gold_assert(mips_sym->need_fn_stub());
-              Mips16_stub_section<size, big_endian>* fn_stub =
-                mips_sym->template get_mips16_fn_stub<big_endian>();
+              // 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>();
 
-              symval.set_output_value(fn_stub->output_address());
-              psymval = &symval;
+                  symval.set_output_value(fn_stub->output_address());
+                  psymval = &symval;
+                }
+              got_offset = mips_sym->global_gotoffset();
+              update_got_entry = true;
             }
-          got_offset = mips_sym->global_gotoffset();
-          update_got_entry = true;
-        }
-      break;
-
-    case elfcpp::R_MIPS_REL32:
-      gold_unreachable();
+          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_64:
+          if (should_apply_static_reloc(mips_sym, r_type, output_section,
+                                        target))
+            reloc_status = Reloc_funcs::rel64(view, object, psymval, r_addend,
+                                              extract_addend, r_type,
+                                              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, r_type,
+                                              calculate_only, calculated_value,
+                                              true);
+          break;
+        case elfcpp::R_MIPS_REL32:
+          gold_unreachable();
 
-    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;
+        case elfcpp::R_MIPS_PC32:
+          reloc_status = Reloc_funcs::relpc32(view, object, psymval, address,
+                                              r_addend, extract_addend, r_type,
+                                              calculate_only, calculated_value);
+          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_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(), calculate_only, calculated_value);
+          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_type, r_sym);
-      break;
+        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_type,
+                                                   extract_addend, 0,
+                                                   target, calculate_only,
+                                                   calculated_value);
+          else
+            reloc_status = Reloc_funcs::relhi16(view, object, psymval, r_addend,
+                                                address, gp_disp, r_type, r_sym,
+                                                extract_addend);
+          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_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, rel_type,
+                                              calculate_only, calculated_value);
+          break;
 
-      // Fall through.
+        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_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;
+          // Fall through.
 
-    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,
+        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, 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_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;
+                                             r_addend, extract_addend,
+                                             gsym == NULL, r_type,
+                                             calculate_only, calculated_value);
+          break;
 
-    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_PC16:
+          reloc_status = Reloc_funcs::relpc16(view, object, psymval, address,
+                                              r_addend, extract_addend, r_type,
+                                              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, r_type,
+                                                        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,
+                                                       r_type, 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,
+                                                       r_type, 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, r_type,
+                                              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, r_type,
+                                                  calculate_only,
+                                                  calculated_value);
+          update_got_entry = changed_symbol_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_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, r_type,
+                                                  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_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_type))
+            reloc_status = Reloc_funcs::releh(view, gp_offset, r_type,
+                                              calculate_only,
+                                              calculated_value);
+          else
+            reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type,
+                                               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, r_type,
+                                             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, r_type,
+                                                 calculate_only,
+                                                 calculated_value);
+            }
+          else
+            {
+              if (rel_type == elfcpp::SHT_RELA)
+                reloc_status = Reloc_funcs::do_relgot16_local(view, object,
+                                                         psymval, r_addend,
+                                                         r_type, extract_addend,
+                                                         0, target,
+                                                         calculate_only,
+                                                         calculated_value);
+              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;
 
-    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, r_type,
+                                             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, r_type,
+                                             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, r_type,
+                                             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,
+                                                 r_type, 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, r_type, 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_type,
+                                                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, r_type,
+                                                 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, r_type,
+                                                 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, r_type,
+                                               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, r_type,
+                                                 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, r_type,
+                                                 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, r_type,
+                                               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, r_type,
+                                             calculate_only, calculated_value);
+          break;
+        default:
+          gold_error_at_location(relinfo, relnum, r_offset,
+                                 _("unsupported reloc %u"), r_type);
+          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));
+        }
+
+      if (object->is_n64())
+        {
+          if (i == 0)
+            {
+              psymval = &symval2;
+              // Handle special symbol for r_type2 relocation type.
+              switch (r_ssym)
+                {
+                case RSS_UNDEF:
+                  symval2.set_output_value(0);
+                  break;
+                case RSS_GP:
+                  symval2.set_output_value(target->gp_value());
+                  break;
+                case RSS_GP0:
+                  symval2.set_output_value(object->gp_value());
+                  break;
+                case RSS_LOC:
+                  symval2.set_output_value(address);
+                  break;
+                default:
+                  gold_unreachable();
+                }
+            }
+          else if (i == 1)
+            // For r_type3 symbol value is 0.
+            symval2.set_output_value(0);
+
+          r_addend = calculated_value;
+        }
     }
 
   // Report any errors.
@@ -10309,6 +11016,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;
 
@@ -10480,7 +11188,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)
@@ -10549,8 +11257,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()
diff --git a/gold/output.h b/gold/output.h
index c7ad54e..b2ae154 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -1150,11 +1150,6 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 	      r2) const
   { return this->compare(r2) < 0; }
 
- private:
-  // Record that we need a dynamic symbol index.
-  void
-  set_needs_dynsym_index();
-
   // Return the symbol index.
   unsigned int
   get_symbol_index() const;
@@ -1163,6 +1158,11 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   Address
   get_address() const;
 
+ private:
+  // Record that we need a dynamic symbol index.
+  void
+  set_needs_dynsym_index();
+
   // Codes for local_sym_index_.
   enum
   {
@@ -1502,7 +1502,7 @@ class Output_data_reloc_base : public Output_data_reloc_generic
   }
 
   // Add a relocation entry.
-  void
+  virtual void
   add(Output_data* od, const Output_reloc_type& reloc)
   {
     this->relocs_.push_back(reloc);

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