MIPS/BFD: Factor out relocated field storing
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index f5296a49159c9ecc5db2e704fa528cf83a847b4f..0573e93394ff49706f9b3ae0b922057bd30795c6 100644 (file)
@@ -1,7 +1,5 @@
 /* MIPS-specific support for ELF
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
-   Free Software Foundation, Inc.
+   Copyright (C) 1993-2018 Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
@@ -38,6 +36,7 @@
 #include "elfxx-mips.h"
 #include "elf/mips.h"
 #include "elf-vxworks.h"
+#include "dwarf2.h"
 
 /* Get the ECOFF swapping routines.  */
 #include "coff/sym.h"
@@ -170,8 +169,10 @@ struct mips_got_info
   unsigned int page_gotno;
   /* The number of relocations needed for the GOT entries.  */
   unsigned int relocs;
-  /* The number of local .got entries we have used.  */
-  unsigned int assigned_gotno;
+  /* The first unused local .got entry.  */
+  unsigned int assigned_low_gotno;
+  /* The last unused local .got entry.  */
+  unsigned int assigned_high_gotno;
   /* A hash table holding members of the got.  */
   struct htab *got_entries;
   /* A hash table holding mips_got_page_ref structures.  */
@@ -309,14 +310,43 @@ struct mips_elf_hash_sort_data
   struct elf_link_hash_entry *low;
   /* The least dynamic symbol table index corresponding to a non-TLS
      symbol with a GOT entry.  */
-  long min_got_dynindx;
+  bfd_size_type min_got_dynindx;
   /* The greatest dynamic symbol table index corresponding to a symbol
      with a GOT entry that is not referenced (e.g., a dynamic symbol
      with dynamic relocations pointing to it from non-primary GOTs).  */
-  long max_unref_got_dynindx;
-  /* The greatest dynamic symbol table index not corresponding to a
+  bfd_size_type max_unref_got_dynindx;
+  /* The greatest dynamic symbol table index corresponding to a local
+     symbol.  */
+  bfd_size_type max_local_dynindx;
+  /* The greatest dynamic symbol table index corresponding to an external
      symbol without a GOT entry.  */
-  long max_non_got_dynindx;
+  bfd_size_type max_non_got_dynindx;
+};
+
+/* We make up to two PLT entries if needed, one for standard MIPS code
+   and one for compressed code, either a MIPS16 or microMIPS one.  We
+   keep a separate record of traditional lazy-binding stubs, for easier
+   processing.  */
+
+struct plt_entry
+{
+  /* Traditional SVR4 stub offset, or -1 if none.  */
+  bfd_vma stub_offset;
+
+  /* Standard PLT entry offset, or -1 if none.  */
+  bfd_vma mips_offset;
+
+  /* Compressed PLT entry offset, or -1 if none.  */
+  bfd_vma comp_offset;
+
+  /* The corresponding .got.plt index, or -1 if none.  */
+  bfd_vma gotplt_index;
+
+  /* Whether we need a standard PLT entry.  */
+  unsigned int need_mips : 1;
+
+  /* Whether we need a compressed PLT entry.  */
+  unsigned int need_comp : 1;
 };
 
 /* The MIPS ELF linker needs additional information for each symbol in
@@ -383,6 +413,9 @@ struct mips_elf_link_hash_entry
   /* Does this symbol need a traditional MIPS lazy-binding stub
      (as opposed to a PLT entry)?  */
   unsigned int needs_lazy_stub : 1;
+
+  /* Does this symbol resolve to a PLT entry?  */
+  unsigned int use_plt_entry : 1;
 };
 
 /* MIPS ELF linker hash table.  */
@@ -410,6 +443,12 @@ struct mips_elf_link_hash_table
   /* True if we can generate copy relocs and PLTs.  */
   bfd_boolean use_plts_and_copy_relocs;
 
+  /* True if we can only use 32-bit microMIPS instructions.  */
+  bfd_boolean insn32;
+
+  /* True if we suppress checks for invalid branches between ISA modes.  */
+  bfd_boolean ignore_branch_isa;
+
   /* True if we're generating code for VxWorks.  */
   bfd_boolean is_vxworks;
 
@@ -418,14 +457,8 @@ struct mips_elf_link_hash_table
 
   /* Shortcuts to some dynamic sections, or NULL if they are not
      being used.  */
-  asection *srelbss;
-  asection *sdynbss;
-  asection *srelplt;
   asection *srelplt2;
-  asection *sgotplt;
-  asection *splt;
   asection *sstubs;
-  asection *sgot;
 
   /* The master GOT information.  */
   struct mips_got_info *got_info;
@@ -437,8 +470,20 @@ struct mips_elf_link_hash_table
   /* The size of the PLT header in bytes.  */
   bfd_vma plt_header_size;
 
-  /* The size of a PLT entry in bytes.  */
-  bfd_vma plt_entry_size;
+  /* The size of a standard PLT entry in bytes.  */
+  bfd_vma plt_mips_entry_size;
+
+  /* The size of a compressed PLT entry in bytes.  */
+  bfd_vma plt_comp_entry_size;
+
+  /* The offset of the next standard PLT entry to create.  */
+  bfd_vma plt_mips_offset;
+
+  /* The offset of the next compressed PLT entry to create.  */
+  bfd_vma plt_comp_offset;
+
+  /* The index of the next .got.plt entry to create.  */
+  bfd_vma plt_got_index;
 
   /* The number of functions that need a lazy-binding stub.  */
   bfd_vma lazy_stub_count;
@@ -468,6 +513,9 @@ struct mips_elf_link_hash_table
 
   /* Small local sym cache.  */
   struct sym_cache sym_cache;
+
+  /* Is the PLT header compressed?  */
+  unsigned int plt_header_is_comp : 1;
 };
 
 /* Get the MIPS ELF linker hash table from a link_info structure.  */
@@ -497,6 +545,13 @@ struct mips_elf_obj_tdata
   /* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output.  */
   bfd *abi_fp_bfd;
 
+  /* Input BFD providing Tag_GNU_MIPS_ABI_MSA attribute for output.  */
+  bfd *abi_msa_bfd;
+
+  /* The abiflags for this object.  */
+  Elf_Internal_ABIFlags_v0 abiflags;
+  bfd_boolean abiflags_valid;
+
   /* The GOT requirements of input bfds.  */
   struct mips_got_info *got;
 
@@ -726,6 +781,10 @@ static bfd *reldyn_sorting_bfd;
 #define PIC_OBJECT_P(abfd) \
   ((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0)
 
+/* Nonzero if ABFD is using the O32 ABI.  */
+#define ABI_O32_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_O32)
+
 /* Nonzero if ABFD is using the N32 ABI.  */
 #define ABI_N32_P(abfd) \
   ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
@@ -741,6 +800,11 @@ static bfd *reldyn_sorting_bfd;
 #define MICROMIPS_P(abfd) \
   ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0)
 
+/* Nonzero if ABFD is MIPS R6.  */
+#define MIPSR6_P(abfd) \
+  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6 \
+    || (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6)
+
 /* The IRIX compatibility level we are striving for.  */
 #define IRIX_COMPAT(abfd) \
   (get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd))
@@ -758,6 +822,10 @@ static bfd *reldyn_sorting_bfd;
 #define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \
   (strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0)
 
+/* True if NAME is the recognized name of any SHT_MIPS_ABIFLAGS section.  */
+#define MIPS_ELF_ABIFLAGS_SECTION_NAME_P(NAME) \
+  (strcmp (NAME, ".MIPS.abiflags") == 0)
+
 /* Whether the section is readonly.  */
 #define MIPS_ELF_READONLY_SECTION(sec) \
   ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))                \
@@ -800,8 +868,8 @@ static bfd *reldyn_sorting_bfd;
 
 /* Put out word-sized data.  */
 #define MIPS_ELF_PUT_WORD(abfd, val, ptr)      \
-  (ABI_64_P (abfd)                             \
-   ? bfd_put_64 (abfd, val, ptr)               \
+  (ABI_64_P (abfd)                             \
+   ? bfd_put_64 (abfd, val, ptr)               \
    : bfd_put_32 (abfd, val, ptr))
 
 /* The opcode for word-sized loads (LW or LD).  */
@@ -813,7 +881,7 @@ static bfd *reldyn_sorting_bfd;
   _bfd_elf_add_dynamic_entry (info, tag, val)
 
 #define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela)                     \
-  (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela))
+  (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (abfd, rtype, rela))
 
 /* The name of the dynamic relocation section.  */
 #define MIPS_ELF_REL_DYN_NAME(INFO) \
@@ -842,13 +910,10 @@ static bfd *reldyn_sorting_bfd;
 #define STUB_LW(abfd)                                                  \
   ((ABI_64_P (abfd)                                                    \
     ? 0xdf998010                               /* ld t9,0x8010(gp) */  \
-    : 0x8f998010))                             /* lw t9,0x8010(gp) */
-#define STUB_MOVE(abfd)                                                        \
-   ((ABI_64_P (abfd)                                                   \
-     ? 0x03e0782d                              /* daddu t7,ra */       \
-     : 0x03e07821))                            /* addu t7,ra */
+    : 0x8f998010))                             /* lw t9,0x8010(gp) */
+#define STUB_MOVE 0x03e07825                   /* or t7,ra,zero */
 #define STUB_LUI(VAL) (0x3c180000 + (VAL))     /* lui t8,VAL */
-#define STUB_JALR 0x0320f809                   /* jalr t9,ra */
+#define STUB_JALR 0x0320f809                   /* jalr ra,t9 */
 #define STUB_ORI(VAL) (0x37180000 + (VAL))     /* ori t8,t8,VAL */
 #define STUB_LI16U(VAL) (0x34180000 + (VAL))   /* ori t8,zero,VAL unsigned */
 #define STUB_LI16S(abfd, VAL)                                          \
@@ -856,15 +921,39 @@ static bfd *reldyn_sorting_bfd;
     ? (0x64180000 + (VAL))     /* daddiu t8,zero,VAL sign extended */  \
     : (0x24180000 + (VAL))))   /* addiu t8,zero,VAL sign extended */
 
+/* Likewise for the microMIPS ASE.  */
+#define STUB_LW_MICROMIPS(abfd)                                                \
+  (ABI_64_P (abfd)                                                     \
+   ? 0xdf3c8010                                        /* ld t9,0x8010(gp) */  \
+   : 0xff3c8010)                               /* lw t9,0x8010(gp) */
+#define STUB_MOVE_MICROMIPS 0x0dff             /* move t7,ra */
+#define STUB_MOVE32_MICROMIPS 0x001f7a90       /* or t7,ra,zero */
+#define STUB_LUI_MICROMIPS(VAL)                                                \
+   (0x41b80000 + (VAL))                                /* lui t8,VAL */
+#define STUB_JALR_MICROMIPS 0x45d9             /* jalr t9 */
+#define STUB_JALR32_MICROMIPS 0x03f90f3c       /* jalr ra,t9 */
+#define STUB_ORI_MICROMIPS(VAL)                                                \
+  (0x53180000 + (VAL))                         /* ori t8,t8,VAL */
+#define STUB_LI16U_MICROMIPS(VAL)                                      \
+  (0x53000000 + (VAL))                         /* ori t8,zero,VAL unsigned */
+#define STUB_LI16S_MICROMIPS(abfd, VAL)                                        \
+   (ABI_64_P (abfd)                                                    \
+    ? 0x5f000000 + (VAL)       /* daddiu t8,zero,VAL sign extended */  \
+    : 0x33000000 + (VAL))      /* addiu t8,zero,VAL sign extended */
+
 #define MIPS_FUNCTION_STUB_NORMAL_SIZE 16
 #define MIPS_FUNCTION_STUB_BIG_SIZE 20
+#define MICROMIPS_FUNCTION_STUB_NORMAL_SIZE 12
+#define MICROMIPS_FUNCTION_STUB_BIG_SIZE 16
+#define MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE 16
+#define MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE 20
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 
-#define ELF_DYNAMIC_INTERPRETER(abfd)          \
-   (ABI_N32_P (abfd) ? "/usr/lib32/libc.so.1"  \
-    : ABI_64_P (abfd) ? "/usr/lib64/libc.so.1"         \
+#define ELF_DYNAMIC_INTERPRETER(abfd)          \
+   (ABI_N32_P (abfd) ? "/usr/lib32/libc.so.1"  \
+    : ABI_64_P (abfd) ? "/usr/lib64/libc.so.1" \
     : "/usr/lib/libc.so.1")
 
 #ifdef BFD64
@@ -935,7 +1024,7 @@ static const bfd_vma mips_o32_exec_plt0_entry[] =
   0x8f990000,  /* lw $25, %lo(&GOTPLT[0])($28)                         */
   0x279c0000,  /* addiu $28, $28, %lo(&GOTPLT[0])                      */
   0x031cc023,  /* subu $24, $24, $28                                   */
-  0x03e07821,  /* move $15, $31        # 32-bit move (addu)            */
+  0x03e07825,  /* or t7, ra, zero                                      */
   0x0018c082,  /* srl $24, $24, 2                                      */
   0x0320f809,  /* jalr $25                                             */
   0x2718fffe   /* subu $24, $24, 2                                     */
@@ -949,7 +1038,7 @@ static const bfd_vma mips_n32_exec_plt0_entry[] =
   0x8dd90000,  /* lw $25, %lo(&GOTPLT[0])($14)                         */
   0x25ce0000,  /* addiu $14, $14, %lo(&GOTPLT[0])                      */
   0x030ec023,  /* subu $24, $24, $14                                   */
-  0x03e07821,  /* move $15, $31        # 32-bit move (addu)            */
+  0x03e07825,  /* or t7, ra, zero                                      */
   0x0018c082,  /* srl $24, $24, 2                                      */
   0x0320f809,  /* jalr $25                                             */
   0x2718fffe   /* subu $24, $24, 2                                     */
@@ -963,13 +1052,46 @@ static const bfd_vma mips_n64_exec_plt0_entry[] =
   0xddd90000,  /* ld $25, %lo(&GOTPLT[0])($14)                         */
   0x25ce0000,  /* addiu $14, $14, %lo(&GOTPLT[0])                      */
   0x030ec023,  /* subu $24, $24, $14                                   */
-  0x03e0782d,  /* move $15, $31        # 64-bit move (daddu)           */
+  0x03e07825,  /* or t7, ra, zero                                      */
   0x0018c0c2,  /* srl $24, $24, 3                                      */
   0x0320f809,  /* jalr $25                                             */
   0x2718fffe   /* subu $24, $24, 2                                     */
 };
 
-/* The format of subsequent PLT entries.  */
+/* The format of the microMIPS first PLT entry in an O32 executable.
+   We rely on v0 ($2) rather than t8 ($24) to contain the address
+   of the GOTPLT entry handled, so this stub may only be used when
+   all the subsequent PLT entries are microMIPS code too.
+
+   The trailing NOP is for alignment and correct disassembly only.  */
+static const bfd_vma micromips_o32_exec_plt0_entry[] =
+{
+  0x7980, 0x0000,      /* addiupc $3, (&GOTPLT[0]) - .                 */
+  0xff23, 0x0000,      /* lw $25, 0($3)                                */
+  0x0535,              /* subu $2, $2, $3                              */
+  0x2525,              /* srl $2, $2, 2                                */
+  0x3302, 0xfffe,      /* subu $24, $2, 2                              */
+  0x0dff,              /* move $15, $31                                */
+  0x45f9,              /* jalrs $25                                    */
+  0x0f83,              /* move $28, $3                                 */
+  0x0c00               /* nop                                          */
+};
+
+/* The format of the microMIPS first PLT entry in an O32 executable
+   in the insn32 mode.  */
+static const bfd_vma micromips_insn32_o32_exec_plt0_entry[] =
+{
+  0x41bc, 0x0000,      /* lui $28, %hi(&GOTPLT[0])                     */
+  0xff3c, 0x0000,      /* lw $25, %lo(&GOTPLT[0])($28)                 */
+  0x339c, 0x0000,      /* addiu $28, $28, %lo(&GOTPLT[0])              */
+  0x0398, 0xc1d0,      /* subu $24, $24, $28                           */
+  0x001f, 0x7a90,      /* or $15, $31, zero                            */
+  0x0318, 0x1040,      /* srl $24, $24, 2                              */
+  0x03f9, 0x0f3c,      /* jalr $25                                     */
+  0x3318, 0xfffe       /* subu $24, $24, 2                             */
+};
+
+/* The format of subsequent standard PLT entries.  */
 static const bfd_vma mips_exec_plt_entry[] =
 {
   0x3c0f0000,  /* lui $15, %hi(.got.plt entry)                 */
@@ -978,6 +1100,50 @@ static const bfd_vma mips_exec_plt_entry[] =
   0x03200008   /* jr $25                                       */
 };
 
+/* In the following PLT entry the JR and ADDIU instructions will
+   be swapped in _bfd_mips_elf_finish_dynamic_symbol because
+   LOAD_INTERLOCKS_P will be true for MIPS R6.  */
+static const bfd_vma mipsr6_exec_plt_entry[] =
+{
+  0x3c0f0000,  /* lui $15, %hi(.got.plt entry)                 */
+  0x01f90000,  /* l[wd] $25, %lo(.got.plt entry)($15)          */
+  0x25f80000,  /* addiu $24, $15, %lo(.got.plt entry)          */
+  0x03200009   /* jr $25                                       */
+};
+
+/* The format of subsequent MIPS16 o32 PLT entries.  We use v0 ($2)
+   and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not
+   directly addressable.  */
+static const bfd_vma mips16_o32_exec_plt_entry[] =
+{
+  0xb203,              /* lw $2, 12($pc)                       */
+  0x9a60,              /* lw $3, 0($2)                         */
+  0x651a,              /* move $24, $2                         */
+  0xeb00,              /* jr $3                                */
+  0x653b,              /* move $25, $3                         */
+  0x6500,              /* nop                                  */
+  0x0000, 0x0000       /* .word (.got.plt entry)               */
+};
+
+/* The format of subsequent microMIPS o32 PLT entries.  We use v0 ($2)
+   as a temporary because t8 ($24) is not addressable with ADDIUPC.  */
+static const bfd_vma micromips_o32_exec_plt_entry[] =
+{
+  0x7900, 0x0000,      /* addiupc $2, (.got.plt entry) - .     */
+  0xff22, 0x0000,      /* lw $25, 0($2)                        */
+  0x4599,              /* jr $25                               */
+  0x0f02               /* move $24, $2                         */
+};
+
+/* The format of subsequent microMIPS o32 PLT entries in the insn32 mode.  */
+static const bfd_vma micromips_insn32_o32_exec_plt_entry[] =
+{
+  0x41af, 0x0000,      /* lui $15, %hi(.got.plt entry)         */
+  0xff2f, 0x0000,      /* lw $25, %lo(.got.plt entry)($15)     */
+  0x0019, 0x0f3c,      /* jr $25                               */
+  0x330f, 0x0000       /* addiu $24, $15, %lo(.got.plt entry)  */
+};
+
 /* The format of the first PLT entry in a VxWorks executable.  */
 static const bfd_vma mips_vxworks_exec_plt0_entry[] =
 {
@@ -1026,7 +1192,7 @@ static void
 bfd_put_micromips_32 (const bfd *abfd, bfd_vma opcode, bfd_byte *ptr)
 {
   bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
-  bfd_put_16 (abfd,  opcode        & 0xffff, ptr + 2);
+  bfd_put_16 (abfd,  opcode       & 0xffff, ptr + 2);
 }
 
 /* microMIPS 32-bit opcode helper retriever.  */
@@ -1116,6 +1282,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       ret->need_fn_stub = FALSE;
       ret->has_nonpic_branches = FALSE;
       ret->needs_lazy_stub = FALSE;
+      ret->use_plt_entry = FALSE;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -1411,19 +1578,23 @@ mips_elf_create_stub_symbol (struct bfd_link_info *info,
                             const char *prefix, asection *s, bfd_vma value,
                             bfd_vma size)
 {
+  bfd_boolean micromips_p = ELF_ST_IS_MICROMIPS (h->root.other);
   struct bfd_link_hash_entry *bh;
   struct elf_link_hash_entry *elfh;
-  const char *name;
+  char *name;
+  bfd_boolean res;
 
-  if (ELF_ST_IS_MICROMIPS (h->root.other))
+  if (micromips_p)
     value |= 1;
 
   /* Create a new symbol.  */
-  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
+  name = concat (prefix, h->root.root.root.string, NULL);
   bh = NULL;
-  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
-                                        BSF_LOCAL, s, value, NULL,
-                                        TRUE, FALSE, &bh))
+  res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
+                                         BSF_LOCAL, s, value, NULL,
+                                         TRUE, FALSE, &bh);
+  free (name);
+  if (! res)
     return FALSE;
 
   /* Make it a local function.  */
@@ -1431,6 +1602,8 @@ mips_elf_create_stub_symbol (struct bfd_link_info *info,
   elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
   elfh->size = size;
   elfh->forced_local = 1;
+  if (micromips_p)
+    elfh->other = ELF_ST_SET_MICROMIPS (elfh->other);
   return TRUE;
 }
 
@@ -1445,9 +1618,10 @@ mips_elf_create_shadow_symbol (struct bfd_link_info *info,
 {
   struct bfd_link_hash_entry *bh;
   struct elf_link_hash_entry *elfh;
-  const char *name;
+  char *name;
   asection *s;
   bfd_vma value;
+  bfd_boolean res;
 
   /* Read the symbol's value.  */
   BFD_ASSERT (h->root.root.type == bfd_link_hash_defined
@@ -1456,11 +1630,13 @@ mips_elf_create_shadow_symbol (struct bfd_link_info *info,
   value = h->root.root.u.def.value;
 
   /* Create a new symbol.  */
-  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
+  name = concat (prefix, h->root.root.root.string, NULL);
   bh = NULL;
-  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
-                                        BSF_LOCAL, s, value, NULL,
-                                        TRUE, FALSE, &bh))
+  res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
+                                         BSF_LOCAL, s, value, NULL,
+                                         TRUE, FALSE, &bh);
+  free (name);
+  if (! res)
     return FALSE;
 
   /* Make it local and copy the other attributes from H.  */
@@ -1534,36 +1710,39 @@ mips_elf_check_mips16_stubs (struct bfd_link_info *info,
       && ! h->need_fn_stub)
     {
       /* We don't need the fn_stub; the only references to this symbol
-         are 16 bit calls.  Clobber the size to 0 to prevent it from
-         being included in the link.  */
+        are 16 bit calls.  Clobber the size to 0 to prevent it from
+        being included in the link.  */
       h->fn_stub->size = 0;
       h->fn_stub->flags &= ~SEC_RELOC;
       h->fn_stub->reloc_count = 0;
       h->fn_stub->flags |= SEC_EXCLUDE;
+      h->fn_stub->output_section = bfd_abs_section_ptr;
     }
 
   if (h->call_stub != NULL
       && ELF_ST_IS_MIPS16 (h->root.other))
     {
       /* We don't need the call_stub; this is a 16 bit function, so
-         calls from other 16 bit functions are OK.  Clobber the size
-         to 0 to prevent it from being included in the link.  */
+        calls from other 16 bit functions are OK.  Clobber the size
+        to 0 to prevent it from being included in the link.  */
       h->call_stub->size = 0;
       h->call_stub->flags &= ~SEC_RELOC;
       h->call_stub->reloc_count = 0;
       h->call_stub->flags |= SEC_EXCLUDE;
+      h->call_stub->output_section = bfd_abs_section_ptr;
     }
 
   if (h->call_fp_stub != NULL
       && ELF_ST_IS_MIPS16 (h->root.other))
     {
       /* We don't need the call_stub; this is a 16 bit function, so
-         calls from other 16 bit functions are OK.  Clobber the size
-         to 0 to prevent it from being included in the link.  */
+        calls from other 16 bit functions are OK.  Clobber the size
+        to 0 to prevent it from being included in the link.  */
       h->call_fp_stub->size = 0;
       h->call_fp_stub->flags &= ~SEC_RELOC;
       h->call_fp_stub->reloc_count = 0;
       h->call_fp_stub->flags |= SEC_EXCLUDE;
+      h->call_fp_stub->output_section = bfd_abs_section_ptr;
     }
 }
 
@@ -1629,6 +1808,7 @@ mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
           || h->root.root.type == bfd_link_hash_defweak)
          && h->root.def_regular
          && !bfd_is_abs_section (h->root.root.u.def.section)
+         && !bfd_is_und_section (h->root.root.u.def.section)
          && (!ELF_ST_IS_MIPS16 (h->root.other)
              || (h->fn_stub && h->need_fn_stub))
          && (PIC_OBJECT_P (h->root.root.u.def.section->owner)
@@ -1785,6 +1965,8 @@ mips_elf_add_la25_stub (struct bfd_link_info *info,
   /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
      of the section and if we would need no more than 2 nops.  */
   value = mips_elf_get_la25_target (stub, &s);
+  if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+    value &= ~1;
   use_trampoline_p = (value != 0 || s->alignment_power > 4);
 
   h->la25_stub = stub;
@@ -1802,7 +1984,7 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
   struct mips_htab_traverse_info *hti;
 
   hti = (struct mips_htab_traverse_info *) data;
-  if (!hti->info->relocatable)
+  if (!bfd_link_relocatable (hti->info))
     mips_elf_check_mips16_stubs (hti->info, h);
 
   if (mips_elf_local_pic_function_p (h))
@@ -1817,7 +1999,7 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
         being PIC.  If we're creating a non-relocatable object with
         non-PIC branches and jumps to H, make sure that H has an la25
         stub.  */
-      if (hti->info->relocatable)
+      if (bfd_link_relocatable (hti->info))
        {
          if (!PIC_OBJECT_P (hti->output_bfd))
            h->root.other = ELF_ST_SET_MIPS_PIC (h->root.other);
@@ -1840,7 +2022,7 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
    +--------------+--------------------------------+
    |     JALX     | X|   Imm 20:16  |   Imm 25:21  |
    +--------------+--------------------------------+
-   |                Immediate  15:0                |
+   |               Immediate  15:0                |
    +-----------------------------------------------+
 
    JALX is the 5-bit value 00011.  X is 0 for jal, 1 for jalx.
@@ -1870,16 +2052,16 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
 
    big-endian:
    +--------+----------------------+
-   |        |                      |
-   |        |    targ26-16         |
-   |31    26|25                   0|
+   |       |                      |
+   |       |    targ26-16         |
+   |31   26|25                   0|
    +--------+----------------------+
 
    little-endian:
    +----------+------+-------------+
-   |          |      |             |
-   |  sub1    |      |     sub2    |
-   |0        9|10  15|16         31|
+   |         |      |             |
+   |  sub1    |             |     sub2    |
+   |0       9|10  15|16         31|
    +----------+--------------------+
    where targ26-16 is sub1 followed by sub2 (i.e., the addend field A is
    ((sub1 << 16) | sub2)).
@@ -1914,7 +2096,11 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
 
    All we need to do here is shuffle the bits appropriately.
    As above, the two 16-bit halves must be swapped on a
-   little-endian system.  */
+   little-endian system.
+
+   Finally R_MIPS16_PC16_S1 corresponds to R_MIPS_PC16, however the
+   relocatable field is shifted by 1 rather than 2 and the same bit
+   shuffling is done as with the relocations above.  */
 
 static inline bfd_boolean
 mips16_reloc_p (int r_type)
@@ -1934,6 +2120,7 @@ mips16_reloc_p (int r_type)
     case R_MIPS16_TLS_GOTTPREL:
     case R_MIPS16_TLS_TPREL_HI16:
     case R_MIPS16_TLS_TPREL_LO16:
+    case R_MIPS16_PC16_S1:
       return TRUE;
 
     default:
@@ -1989,18 +2176,6 @@ got_page_reloc_p (unsigned int r_type)
   return r_type == R_MIPS_GOT_PAGE || r_type == R_MICROMIPS_GOT_PAGE;
 }
 
-static inline bfd_boolean
-got_ofst_reloc_p (unsigned int r_type)
-{
-  return r_type == R_MIPS_GOT_OFST || r_type == R_MICROMIPS_GOT_OFST;
-}
-
-static inline bfd_boolean
-got_hi16_reloc_p (unsigned int r_type)
-{
-  return r_type == R_MIPS_GOT_HI16 || r_type == R_MICROMIPS_GOT_HI16;
-}
-
 static inline bfd_boolean
 got_lo16_reloc_p (unsigned int r_type)
 {
@@ -2024,7 +2199,8 @@ hi16_reloc_p (int r_type)
 {
   return (r_type == R_MIPS_HI16
          || r_type == R_MIPS16_HI16
-         || r_type == R_MICROMIPS_HI16);
+         || r_type == R_MICROMIPS_HI16
+         || r_type == R_MIPS_PCHI16);
 }
 
 static inline bfd_boolean
@@ -2032,7 +2208,8 @@ lo16_reloc_p (int r_type)
 {
   return (r_type == R_MIPS_LO16
          || r_type == R_MIPS16_LO16
-         || r_type == R_MICROMIPS_LO16);
+         || r_type == R_MICROMIPS_LO16
+         || r_type == R_MIPS_PCLO16);
 }
 
 static inline bfd_boolean
@@ -2049,6 +2226,43 @@ jal_reloc_p (int r_type)
          || r_type == R_MICROMIPS_26_S1);
 }
 
+static inline bfd_boolean
+b_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_PC26_S2
+         || r_type == R_MIPS_PC21_S2
+         || r_type == R_MIPS_PC16
+         || r_type == R_MIPS_GNU_REL16_S2
+         || r_type == R_MIPS16_PC16_S1
+         || r_type == R_MICROMIPS_PC16_S1
+         || r_type == R_MICROMIPS_PC10_S1
+         || r_type == R_MICROMIPS_PC7_S1);
+}
+
+static inline bfd_boolean
+aligned_pcrel_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_PC18_S3
+         || r_type == R_MIPS_PC19_S2);
+}
+
+static inline bfd_boolean
+branch_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_26
+         || r_type == R_MIPS_PC26_S2
+         || r_type == R_MIPS_PC21_S2
+         || r_type == R_MIPS_PC16
+         || r_type == R_MIPS_GNU_REL16_S2);
+}
+
+static inline bfd_boolean
+mips16_branch_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS16_26
+         || r_type == R_MIPS16_PC16_S1);
+}
+
 static inline bfd_boolean
 micromips_branch_reloc_p (int r_type)
 {
@@ -2520,6 +2734,46 @@ bfd_mips_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in,
   H_PUT_16 (abfd, in->section, ex->section);
   H_PUT_32 (abfd, in->info, ex->info);
 }
+
+/* Swap in an abiflags structure.  */
+
+void
+bfd_mips_elf_swap_abiflags_v0_in (bfd *abfd,
+                                 const Elf_External_ABIFlags_v0 *ex,
+                                 Elf_Internal_ABIFlags_v0 *in)
+{
+  in->version = H_GET_16 (abfd, ex->version);
+  in->isa_level = H_GET_8 (abfd, ex->isa_level);
+  in->isa_rev = H_GET_8 (abfd, ex->isa_rev);
+  in->gpr_size = H_GET_8 (abfd, ex->gpr_size);
+  in->cpr1_size = H_GET_8 (abfd, ex->cpr1_size);
+  in->cpr2_size = H_GET_8 (abfd, ex->cpr2_size);
+  in->fp_abi = H_GET_8 (abfd, ex->fp_abi);
+  in->isa_ext = H_GET_32 (abfd, ex->isa_ext);
+  in->ases = H_GET_32 (abfd, ex->ases);
+  in->flags1 = H_GET_32 (abfd, ex->flags1);
+  in->flags2 = H_GET_32 (abfd, ex->flags2);
+}
+
+/* Swap out an abiflags structure.  */
+
+void
+bfd_mips_elf_swap_abiflags_v0_out (bfd *abfd,
+                                  const Elf_Internal_ABIFlags_v0 *in,
+                                  Elf_External_ABIFlags_v0 *ex)
+{
+  H_PUT_16 (abfd, in->version, ex->version);
+  H_PUT_8 (abfd, in->isa_level, ex->isa_level);
+  H_PUT_8 (abfd, in->isa_rev, ex->isa_rev);
+  H_PUT_8 (abfd, in->gpr_size, ex->gpr_size);
+  H_PUT_8 (abfd, in->cpr1_size, ex->cpr1_size);
+  H_PUT_8 (abfd, in->cpr2_size, ex->cpr2_size);
+  H_PUT_8 (abfd, in->fp_abi, ex->fp_abi);
+  H_PUT_32 (abfd, in->isa_ext, ex->isa_ext);
+  H_PUT_32 (abfd, in->ases, ex->ases);
+  H_PUT_32 (abfd, in->flags1, ex->flags1);
+  H_PUT_32 (abfd, in->flags2, ex->flags2);
+}
 \f
 /* This function is called via qsort() to sort the dynamic relocation
    entries by increasing r_symndx value.  */
@@ -2633,7 +2887,7 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
          const char *name;
 
          /* Use undefined class.  Also, set class and type for some
-             special symbols.  */
+            special symbols.  */
          name = h->root.root.root.string;
          if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
              || strcmp (name, mips_elf_dynsym_rtproc_names[1]) == 0)
@@ -2649,12 +2903,6 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
              h->esym.asym.value =
                mips_elf_hash_table (einfo->info)->procedure_count;
            }
-         else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (einfo->abfd))
-           {
-             h->esym.asym.sc = scAbs;
-             h->esym.asym.st = stLabel;
-             h->esym.asym.value = elf_gp (einfo->abfd);
-           }
          else
            h->esym.asym.sc = scUndefined;
        }
@@ -2730,6 +2978,8 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
 
       if (hd->needs_lazy_stub)
        {
+         BFD_ASSERT (hd->root.plt.plist != NULL);
+         BFD_ASSERT (hd->root.plt.plist->stub_offset != MINUS_ONE);
          /* Set type and value for a symbol with a function stub.  */
          h->esym.asym.st = stProc;
          sec = hd->root.root.u.def.section;
@@ -2739,7 +2989,7 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
            {
              output_section = sec->output_section;
              if (output_section != NULL)
-               h->esym.asym.value = (hd->root.plt.offset
+               h->esym.asym.value = (hd->root.plt.plist->stub_offset
                                      + sec->output_offset
                                      + output_section->vma);
              else
@@ -3001,11 +3251,13 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
   bfd_boolean need_relocs = FALSE;
   bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
 
-  if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
-      && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, h)))
+  if (h != NULL
+      && h->dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+      && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
     indx = h->dynindx;
 
-  if ((info->shared || indx != 0)
+  if ((bfd_link_dll (info) || indx != 0)
       && (h == NULL
          || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
          || h->root.type != bfd_link_hash_undefweak))
@@ -3023,7 +3275,7 @@ mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
       return 1;
 
     case GOT_TLS_LDM:
-      return info->shared ? 1 : 0;
+      return bfd_link_dll (info) ? 1 : 0;
 
     default:
       return 0;
@@ -3090,6 +3342,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
                               struct mips_elf_link_hash_entry *h,
                               bfd_vma value)
 {
+  bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
   struct mips_elf_link_hash_table *htab;
   int indx;
   asection *sreloc, *sgot;
@@ -3100,22 +3353,19 @@ mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
   if (htab == NULL)
     return;
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
 
   indx = 0;
-  if (h != NULL)
-    {
-      bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
-
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->root)
-         && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
-       indx = h->root.dynindx;
-    }
+  if (h != NULL
+      && h->root.dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), &h->root)
+      && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+    indx = h->root.dynindx;
 
   if (entry->tls_initialized)
     return;
 
-  if ((info->shared || indx != 0)
+  if ((bfd_link_dll (info) || indx != 0)
       && (h == NULL
          || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
          || h->root.type != bfd_link_hash_undefweak))
@@ -3190,7 +3440,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
                         sgot->contents + got_offset
                         + MIPS_ELF_GOT_SIZE (abfd));
 
-      if (!info->shared)
+      if (!bfd_link_dll (info))
        MIPS_ELF_PUT_WORD (abfd, 1,
                           sgot->contents + got_offset);
       else
@@ -3215,25 +3465,20 @@ static bfd_vma
 mips_elf_gotplt_index (struct bfd_link_info *info,
                       struct elf_link_hash_entry *h)
 {
-  bfd_vma plt_index, got_address, got_value;
+  bfd_vma got_address, got_value;
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
-
-  /* This function only works for VxWorks, because a non-VxWorks .got.plt
-     section starts with reserved entries.  */
-  BFD_ASSERT (htab->is_vxworks);
-
-  /* Calculate the index of the symbol's PLT entry.  */
-  plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
+  BFD_ASSERT (h->plt.plist != NULL);
+  BFD_ASSERT (h->plt.plist->gotplt_index != MINUS_ONE);
 
   /* Calculate the address of the associated .got.plt entry.  */
-  got_address = (htab->sgotplt->output_section->vma
-                + htab->sgotplt->output_offset
-                + plt_index * 4);
+  got_address = (htab->root.sgotplt->output_section->vma
+                + htab->root.sgotplt->output_offset
+                + (h->plt.plist->gotplt_index
+                   * MIPS_ELF_GOT_SIZE (info->output_bfd)));
 
   /* Calculate the value of _GLOBAL_OFFSET_TABLE_.  */
   got_value = (htab->root.hgot->root.u.def.section->output_section->vma
@@ -3295,7 +3540,7 @@ mips_elf_primary_global_got_index (bfd *obfd, struct bfd_link_info *info,
   g = mips_elf_bfd_got (obfd, FALSE);
   got_index = ((h->dynindx - global_got_dynindx + g->local_gotno)
               * MIPS_ELF_GOT_SIZE (obfd));
-  BFD_ASSERT (got_index < htab->sgot->size);
+  BFD_ASSERT (got_index < htab->root.sgot->size);
 
   return got_index;
 }
@@ -3329,7 +3574,7 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
   BFD_ASSERT (entry);
 
   gotidx = entry->gotidx;
-  BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
+  BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
 
   if (lookup.tls_type)
     {
@@ -3417,7 +3662,7 @@ mips_elf_got_offset_from_index (struct bfd_link_info *info, bfd *output_bfd,
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   gp = _bfd_get_gp_value (output_bfd)
     + mips_elf_adjust_gp (output_bfd, htab->got_info, input_bfd);
 
@@ -3480,7 +3725,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       BFD_ASSERT (entry);
 
       gotidx = entry->gotidx;
-      BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
+      BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
 
       return entry;
     }
@@ -3496,10 +3741,10 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
   if (entry)
     return entry;
 
-  if (g->assigned_gotno >= g->local_gotno)
+  if (g->assigned_low_gotno > g->assigned_high_gotno)
     {
       /* We didn't allocate enough space in the GOT.  */
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("not enough GOT space for local GOT entries"));
       bfd_set_error (bfd_error_bad_value);
       return NULL;
@@ -3509,11 +3754,18 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
   if (!entry)
     return NULL;
 
-  lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
+  if (got16_reloc_p (r_type)
+      || call16_reloc_p (r_type)
+      || got_page_reloc_p (r_type)
+      || got_disp_reloc_p (r_type))
+    lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_low_gotno++;
+  else
+    lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_high_gotno--;
+
   *entry = lookup;
   *loc = entry;
 
-  MIPS_ELF_PUT_WORD (abfd, value, htab->sgot->contents + entry->gotidx);
+  MIPS_ELF_PUT_WORD (abfd, value, htab->root.sgot->contents + entry->gotidx);
 
   /* These GOT entries need a dynamic relocation on VxWorks.  */
   if (htab->is_vxworks)
@@ -3524,8 +3776,8 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       bfd_vma got_address;
 
       s = mips_elf_rel_dyn_section (info, FALSE);
-      got_address = (htab->sgot->output_section->vma
-                    + htab->sgot->output_offset
+      got_address = (htab->root.sgot->output_section->vma
+                    + htab->root.sgot->output_offset
                     + entry->gotidx);
 
       rloc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
@@ -3549,7 +3801,8 @@ count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
   bfd_size_type count;
 
   count = 0;
-  if (info->shared || elf_hash_table (info)->is_relocatable_executable)
+  if (bfd_link_pic (info)
+      || elf_hash_table (info)->is_relocatable_executable)
     {
       asection *p;
       const struct elf_backend_data *bed;
@@ -3558,6 +3811,7 @@ count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
       for (p = output_bfd->sections; p ; p = p->next)
        if ((p->flags & SEC_EXCLUDE) == 0
            && (p->flags & SEC_ALLOC) != 0
+           && elf_hash_table (info)->dynamic_relocs
            && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
          ++count;
     }
@@ -3574,12 +3828,12 @@ mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
   struct mips_elf_hash_sort_data hsd;
   struct mips_got_info *g;
 
-  if (elf_hash_table (info)->dynsymcount == 0)
-    return TRUE;
-
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
+  if (htab->root.dynsymcount == 0)
+    return TRUE;
+
   g = htab->got_info;
   if (g == NULL)
     return TRUE;
@@ -3587,20 +3841,19 @@ mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
   hsd.low = NULL;
   hsd.max_unref_got_dynindx
     = hsd.min_got_dynindx
-    = (elf_hash_table (info)->dynsymcount - g->reloc_only_gotno);
-  hsd.max_non_got_dynindx = count_section_dynsyms (abfd, info) + 1;
-  mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
-                               elf_hash_table (info)),
-                              mips_elf_sort_hash_table_f,
-                              &hsd);
+    = (htab->root.dynsymcount - g->reloc_only_gotno);
+  /* Add 1 to local symbol indices to account for the mandatory NULL entry
+     at the head of the table; see `_bfd_elf_link_renumber_dynsyms'.  */
+  hsd.max_local_dynindx = count_section_dynsyms (abfd, info) + 1;
+  hsd.max_non_got_dynindx = htab->root.local_dynsymcount + 1;
+  mips_elf_link_hash_traverse (htab, mips_elf_sort_hash_table_f, &hsd);
 
   /* There should have been enough room in the symbol table to
      accommodate both the GOT and non-GOT symbols.  */
+  BFD_ASSERT (hsd.max_local_dynindx <= htab->root.local_dynsymcount + 1);
   BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
-  BFD_ASSERT ((unsigned long) hsd.max_unref_got_dynindx
-             == elf_hash_table (info)->dynsymcount);
-  BFD_ASSERT (elf_hash_table (info)->dynsymcount - hsd.min_got_dynindx
-             == g->global_gotno);
+  BFD_ASSERT (hsd.max_unref_got_dynindx == htab->root.dynsymcount);
+  BFD_ASSERT (htab->root.dynsymcount - hsd.min_got_dynindx == g->global_gotno);
 
   /* Now we know which dynamic symbol has the lowest dynamic symbol
      table index in the GOT.  */
@@ -3626,7 +3879,10 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
   switch (h->global_got_area)
     {
     case GGA_NONE:
-      h->root.dynindx = hsd->max_non_got_dynindx++;
+      if (h->root.forced_local)
+       h->root.dynindx = hsd->max_local_dynindx++;
+      else
+       h->root.dynindx = hsd->max_non_got_dynindx++;
       break;
 
     case GGA_NORMAL:
@@ -3950,9 +4206,10 @@ mips_elf_pages_for_range (const struct mips_got_page_range *range)
 /* Record that G requires a page entry that can reach SEC + ADDEND.  */
 
 static bfd_boolean
-mips_elf_record_got_page_entry (struct mips_got_info *g,
+mips_elf_record_got_page_entry (struct mips_elf_traverse_got_arg *arg,
                                asection *sec, bfd_signed_vma addend)
 {
+  struct mips_got_info *g = arg->g;
   struct mips_got_page_entry lookup, *entry;
   struct mips_got_page_range **range_ptr, *range;
   bfd_vma old_pages, new_pages;
@@ -3969,7 +4226,7 @@ mips_elf_record_got_page_entry (struct mips_got_info *g,
   entry = (struct mips_got_page_entry *) *loc;
   if (!entry)
     {
-      entry = bfd_zalloc (sec->owner, sizeof (*entry));
+      entry = bfd_zalloc (arg->info->output_bfd, sizeof (*entry));
       if (!entry)
        return FALSE;
 
@@ -3989,7 +4246,7 @@ mips_elf_record_got_page_entry (struct mips_got_info *g,
   range = *range_ptr;
   if (!range || addend < range->min_addend - 0xffff)
     {
-      range = bfd_zalloc (sec->owner, sizeof (*range));
+      range = bfd_zalloc (arg->info->output_bfd, sizeof (*range));
       if (!range)
        return FALSE;
 
@@ -4109,7 +4366,7 @@ mips_elf_resolve_got_page_ref (void **refp, void *data)
       else
        addend = isym->st_value + ref->addend;
     }
-  if (!mips_elf_record_got_page_entry (arg->g, sec, addend))
+  if (!mips_elf_record_got_page_entry (arg, sec, addend))
     {
       arg->g = NULL;
       return 0;
@@ -4163,6 +4420,36 @@ mips_elf_resolve_final_got_entries (struct bfd_link_info *info,
   return TRUE;
 }
 
+/* Return true if a GOT entry for H should live in the local rather than
+   global GOT area.  */
+
+static bfd_boolean
+mips_use_local_got_p (struct bfd_link_info *info,
+                     struct mips_elf_link_hash_entry *h)
+{
+  /* Symbols that aren't in the dynamic symbol table must live in the
+     local GOT.  This includes symbols that are completely undefined
+     and which therefore don't bind locally.  We'll report undefined
+     symbols later if appropriate.  */
+  if (h->root.dynindx == -1)
+    return TRUE;
+
+  /* Symbols that bind locally can (and in the case of forced-local
+     symbols, must) live in the local GOT.  */
+  if (h->got_only_for_calls
+      ? SYMBOL_CALLS_LOCAL (info, &h->root)
+      : SYMBOL_REFERENCES_LOCAL (info, &h->root))
+    return TRUE;
+
+  /* If this is an executable that must provide a definition of the symbol,
+     either though PLTs or copy relocations, then that address should go in
+     the local rather than global GOT.  */
+  if (bfd_link_executable (info) && h->has_static_relocs)
+    return TRUE;
+
+  return FALSE;
+}
+
 /* A mips_elf_link_hash_traverse callback for which DATA points to the
    link_info structure.  Decide whether the hash entry needs an entry in
    the global part of the primary GOT, setting global_got_area accordingly.
@@ -4182,25 +4469,15 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
   if (h->global_got_area != GGA_NONE)
     {
       /* Make a final decision about whether the symbol belongs in the
-        local or global GOT.  Symbols that bind locally can (and in the
-        case of forced-local symbols, must) live in the local GOT.
-        Those that are aren't in the dynamic symbol table must also
-        live in the local GOT.
-
-        Note that the former condition does not always imply the
-        latter: symbols do not bind locally if they are completely
-        undefined.  We'll report undefined symbols later if appropriate.  */
-      if (h->root.dynindx == -1
-         || (h->got_only_for_calls
-             ? SYMBOL_CALLS_LOCAL (info, &h->root)
-             : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+        local or global GOT.  */
+      if (mips_use_local_got_p (info, h))
        /* The symbol belongs in the local GOT.  We no longer need this
           entry if it was only used for relocations; those relocations
           will be against the null or section symbol instead of H.  */
        h->global_got_area = GGA_NONE;
       else if (htab->is_vxworks
               && h->got_only_for_calls
-              && h->root.plt.offset != MINUS_ONE)
+              && h->root.plt.plist->mips_offset != MINUS_ONE)
        /* On VxWorks, calls can refer directly to the .got.plt entry;
           they don't need entries in the regular GOT.  .got.plt entries
           will be allocated by _bfd_mips_elf_adjust_dynamic_symbol.  */
@@ -4468,14 +4745,14 @@ mips_elf_set_global_gotidx (void **entryp, void *data)
       && entry->symndx == -1
       && entry->d.h->global_got_area != GGA_NONE)
     {
-      if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->assigned_gotno))
+      if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->assigned_low_gotno))
        {
          arg->g = NULL;
          return 0;
        }
-      arg->g->assigned_gotno += 1;
+      arg->g->assigned_low_gotno += 1;
 
-      if (arg->info->shared
+      if (bfd_link_pic (arg->info)
          || (elf_hash_table (arg->info)->dynamic_sections_created
              && entry->d.h->root.def_dynamic
              && !entry->d.h->root.def_regular))
@@ -4568,7 +4845,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
   /* Try to merge the GOTs of input bfds together, as long as they
      don't seem to exceed the maximum GOT size, choosing one of them
      to be the primary GOT.  */
-  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
     {
       gg = mips_elf_bfd_got (ibfd, FALSE);
       if (gg && !mips_elf_merge_got (ibfd, gg, &got_per_bfd_arg))
@@ -4606,7 +4883,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
   htab_traverse (g->got_entries, mips_elf_set_global_got_area, &tga);
 
   /* Now go through the GOTs assigning them offset ranges.
-     [assigned_gotno, local_gotno[ will be set to the range of local
+     [assigned_low_gotno, local_gotno[ will be set to the range of local
      entries in each GOT.  We can then compute the end of a GOT by
      adding local_gotno to global_gotno.  We reverse the list and make
      it circular since then we'll be able to quickly compute the
@@ -4629,9 +4906,10 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
       struct mips_got_info *gn;
 
       assign += htab->reserved_gotno;
-      g->assigned_gotno = assign;
+      g->assigned_low_gotno = assign;
       g->local_gotno += assign;
       g->local_gotno += (pages < g->page_gotno ? pages : g->page_gotno);
+      g->assigned_high_gotno = g->local_gotno - 1;
       assign = g->local_gotno + g->global_gotno + g->tls_gotno;
 
       /* Take g out of the direct list, and push it onto the reversed
@@ -4670,21 +4948,21 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
 
       /* Assign offsets to global GOT entries and count how many
         relocations they need.  */
-      save_assign = g->assigned_gotno;
-      g->assigned_gotno = g->local_gotno;
+      save_assign = g->assigned_low_gotno;
+      g->assigned_low_gotno = g->local_gotno;
       tga.info = info;
       tga.value = MIPS_ELF_GOT_SIZE (abfd);
       tga.g = g;
       htab_traverse (g->got_entries, mips_elf_set_global_gotidx, &tga);
       if (!tga.g)
        return FALSE;
-      BFD_ASSERT (g->assigned_gotno == g->local_gotno + g->global_gotno);
-      g->assigned_gotno = save_assign;
+      BFD_ASSERT (g->assigned_low_gotno == g->local_gotno + g->global_gotno);
+      g->assigned_low_gotno = save_assign;
 
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
-         g->relocs += g->local_gotno - g->assigned_gotno;
-         BFD_ASSERT (g->assigned_gotno == g->next->local_gotno
+         g->relocs += g->local_gotno - g->assigned_low_gotno;
+         BFD_ASSERT (g->assigned_low_gotno == g->next->local_gotno
                      + g->next->global_gotno
                      + g->next->tls_gotno
                      + htab->reserved_gotno);
@@ -4854,7 +5132,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   BFD_ASSERT (htab != NULL);
 
   /* This function may be called more than once.  */
-  if (htab->sgot)
+  if (htab->root.sgot)
     return TRUE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
@@ -4866,7 +5144,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 4))
     return FALSE;
-  htab->sgot = s;
+  htab->root.sgot = s;
 
   /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the
      linker script because we don't want to define the symbol if we
@@ -4881,9 +5159,10 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   h->non_elf = 0;
   h->def_regular = 1;
   h->type = STT_OBJECT;
+  h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
   elf_hash_table (info)->hgot = h;
 
-  if (info->shared
+  if (bfd_link_pic (info)
       && ! bfd_elf_link_record_dynamic_symbol (info, h))
     return FALSE;
 
@@ -4899,7 +5178,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
                                          | SEC_LINKER_CREATED);
   if (s == NULL)
     return FALSE;
-  htab->sgotplt = s;
+  htab->root.sgotplt = s;
 
   return TRUE;
 }
@@ -4912,7 +5191,7 @@ static bfd_boolean
 is_gott_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h)
 {
   return (mips_elf_hash_table (info)->is_vxworks
-         && info->shared
+         && bfd_link_pic (info)
          && (strcmp (h->root.root.string, "__GOTT_BASE__") == 0
              || strcmp (h->root.root.string, "__GOTT_INDEX__") == 0));
 }
@@ -4938,6 +5217,8 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
     {
     case R_MIPS_26:
     case R_MIPS_PC16:
+    case R_MIPS_PC21_S2:
+    case R_MIPS_PC26_S2:
     case R_MICROMIPS_26_S1:
     case R_MICROMIPS_PC7_S1:
     case R_MICROMIPS_PC10_S1:
@@ -4953,6 +5234,21 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
     }
 }
 \f
+/* Store the field relocated by RELOCATION.  */
+
+static void
+mips_elf_store_contents (reloc_howto_type *howto,
+                        const Elf_Internal_Rela *relocation,
+                        bfd *input_bfd, bfd_byte *contents, bfd_vma x)
+{
+  bfd_byte *location = contents + relocation->r_offset;
+  unsigned int size = bfd_get_reloc_size (howto);
+
+  /* Put the value into the output.  */
+  if (size != 0)
+    bfd_put (8 * size, input_bfd, x, location);
+}
+
 /* Calculate the value produced by the RELOCATION (which comes from
    the INPUT_BFD).  The ADDEND is the addend to use for this
    RELOCATION; RELOCATION->R_ADDEND is ignored.
@@ -5002,6 +5298,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   /* TRUE if the symbol referred to by this relocation is a local
      symbol.  */
   bfd_boolean local_p, was_local_p;
+  /* TRUE if the symbol referred to by this relocation is a section
+     symbol.  */
+  bfd_boolean section_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is "_gp_disp".  */
   bfd_boolean gp_disp_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is
@@ -5019,6 +5318,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   bfd_boolean target_is_micromips_code_p = FALSE;
   struct mips_elf_link_hash_table *htab;
   bfd *dynobj;
+  bfd_boolean resolved_to_zero;
 
   dynobj = elf_hash_table (info)->dynobj;
   htab = mips_elf_hash_table (info);
@@ -5052,17 +5352,18 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   /* Figure out the value of the symbol.  */
   if (local_p)
     {
+      bfd_boolean micromips_p = MICROMIPS_P (abfd);
       Elf_Internal_Sym *sym;
 
       sym = local_syms + r_symndx;
       sec = local_sections[r_symndx];
 
+      section_p = ELF_ST_TYPE (sym->st_info) == STT_SECTION;
+
       symbol = sec->output_section->vma + sec->output_offset;
-      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION
-         || (sec->flags & SEC_MERGE))
+      if (!section_p || (sec->flags & SEC_MERGE))
        symbol += sym->st_value;
-      if ((sec->flags & SEC_MERGE)
-         && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+      if ((sec->flags & SEC_MERGE) && section_p)
        {
          addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
          addend -= symbol;
@@ -5077,11 +5378,29 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       *namep = bfd_elf_string_from_elf_section (input_bfd,
                                                symtab_hdr->sh_link,
                                                sym->st_name);
-      if (*namep == '\0')
+      if (*namep == NULL || **namep == '\0')
        *namep = bfd_section_name (input_bfd, sec);
 
-      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
-      target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other);
+      /* For relocations against a section symbol and ones against no
+        symbol (absolute relocations) infer the ISA mode from the addend.  */
+      if (section_p || r_symndx == STN_UNDEF)
+       {
+         target_is_16_bit_code_p = (addend & 1) && !micromips_p;
+         target_is_micromips_code_p = (addend & 1) && micromips_p;
+       }
+      /* For relocations against an absolute symbol infer the ISA mode
+        from the value of the symbol plus addend.  */
+      else if (bfd_is_abs_section (sec))
+       {
+         target_is_16_bit_code_p = ((symbol + addend) & 1) && !micromips_p;
+         target_is_micromips_code_p = ((symbol + addend) & 1) && micromips_p;
+       }
+      /* Otherwise just use the regular symbol annotation available.  */
+      else
+       {
+         target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
+         target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other);
+       }
     }
   else
     {
@@ -5146,11 +5465,11 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        {
          /* If this is a dynamic link, we should have created a
             _DYNAMIC_LINK symbol or _DYNAMIC_LINKING(for normal mips) symbol
-            in in _bfd_mips_elf_create_dynamic_sections.
+            in _bfd_mips_elf_create_dynamic_sections.
             Otherwise, we should define the symbol with a value of 0.
             FIXME: It should probably get into the symbol table
             somehow as well.  */
-         BFD_ASSERT (! info->shared);
+         BFD_ASSERT (! bfd_link_pic (info));
          BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL);
          symbol = 0;
        }
@@ -5165,24 +5484,24 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
             http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf  */
          symbol = 0;
        }
-      else if ((*info->callbacks->undefined_symbol)
-              (info, h->root.root.root.string, input_bfd,
-               input_section, relocation->r_offset,
-               (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
-                || ELF_ST_VISIBILITY (h->root.other)))
-       {
-         return bfd_reloc_undefined;
-       }
       else
        {
-         return bfd_reloc_notsupported;
+         bfd_boolean reject_undefined
+           = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
+              || ELF_ST_VISIBILITY (h->root.other) != STV_DEFAULT);
+
+         (*info->callbacks->undefined_symbol)
+           (info, h->root.root.root.string, input_bfd,
+            input_section, relocation->r_offset, reject_undefined);
+
+         if (reject_undefined)
+           return bfd_reloc_undefined;
+
+         symbol = 0;
        }
 
       target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
-      /* If the output section is the PLT section,
-         then the target is not microMIPS.  */
-      target_is_micromips_code_p = (htab->splt != sec
-                                   && ELF_ST_IS_MICROMIPS (h->root.other));
+      target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (h->root.other);
     }
 
   /* If this is a reference to a 16-bit function with a stub, we need
@@ -5195,7 +5514,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 
      (c) the section allows direct references to MIPS16 functions.  */
   if (r_type != R_MIPS16_26
-      && !info->relocatable
+      && !bfd_link_relocatable (info)
       && ((h != NULL
           && h->fn_stub != NULL
           && (r_type != R_MIPS16_CALL16 || h->need_fn_stub))
@@ -5233,16 +5552,16 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       /* The target is 16-bit, but the stub isn't.  */
       target_is_16_bit_code_p = FALSE;
     }
-  /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
-     need to redirect the call to the stub.  Note that we specifically
-     exclude R_MIPS16_CALL16 from this behavior; indirect calls should
-     use an indirect stub instead.  */
-  else if (r_type == R_MIPS16_26 && !info->relocatable
+  /* If this is a MIPS16 call with a stub, that is made through the PLT or
+     to a standard MIPS function, we need to redirect the call to the stub.
+     Note that we specifically exclude R_MIPS16_CALL16 from this behavior;
+     indirect calls should use an indirect stub instead.  */
+  else if (r_type == R_MIPS16_26 && !bfd_link_relocatable (info)
           && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL))
               || (local_p
                   && mips_elf_tdata (input_bfd)->local_call_stubs != NULL
                   && mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
-          && !target_is_16_bit_code_p)
+          && ((h != NULL && h->use_plt_entry) || !target_is_16_bit_code_p))
     {
       if (local_p)
        sec = mips_elf_tdata (input_bfd)->local_call_stubs[r_symndx];
@@ -5271,7 +5590,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
            sec = h->call_stub;
          else
            sec = h->call_fp_stub;
-       }
+       }
 
       BFD_ASSERT (sec->size > 0);
       symbol = sec->output_section->vma + sec->output_offset;
@@ -5281,15 +5600,45 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   else if (h != NULL && h->la25_stub
           && mips_elf_relocation_needs_la25_stub (input_bfd, r_type,
                                                   target_is_16_bit_code_p))
-    symbol = (h->la25_stub->stub_section->output_section->vma
-             + h->la25_stub->stub_section->output_offset
-             + h->la25_stub->offset);
+    {
+       symbol = (h->la25_stub->stub_section->output_section->vma
+                 + h->la25_stub->stub_section->output_offset
+                 + h->la25_stub->offset);
+       if (ELF_ST_IS_MICROMIPS (h->root.other))
+         symbol |= 1;
+    }
+  /* For direct MIPS16 and microMIPS calls make sure the compressed PLT
+     entry is used if a standard PLT entry has also been made.  In this
+     case the symbol will have been set by mips_elf_set_plt_sym_value
+     to point to the standard PLT entry, so redirect to the compressed
+     one.  */
+  else if ((mips16_branch_reloc_p (r_type)
+           || micromips_branch_reloc_p (r_type))
+          && !bfd_link_relocatable (info)
+          && h != NULL
+          && h->use_plt_entry
+          && h->root.plt.plist->comp_offset != MINUS_ONE
+          && h->root.plt.plist->mips_offset != MINUS_ONE)
+    {
+      bfd_boolean micromips_p = MICROMIPS_P (abfd);
+
+      sec = htab->root.splt;
+      symbol = (sec->output_section->vma
+               + sec->output_offset
+               + htab->plt_header_size
+               + htab->plt_mips_offset
+               + h->root.plt.plist->comp_offset
+               + 1);
+
+      target_is_16_bit_code_p = !micromips_p;
+      target_is_micromips_code_p = micromips_p;
+    }
 
   /* Make sure MIPS16 and microMIPS are not used together.  */
-  if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
+  if ((mips16_branch_reloc_p (r_type) && target_is_micromips_code_p)
       || (micromips_branch_reloc_p (r_type) && target_is_16_bit_code_p))
    {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("MIPS16 and microMIPS functions cannot call each other"));
       return bfd_reloc_notsupported;
    }
@@ -5300,19 +5649,18 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
      because the assembly writer may have "known" that any definition of the
      symbol would be 16-bit code, and that direct jumps were therefore
      acceptable.  */
-  *cross_mode_jump_p = (!info->relocatable
+  *cross_mode_jump_p = (!bfd_link_relocatable (info)
                        && !(h && h->root.root.type == bfd_link_hash_undefweak)
-                       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
-                           || (r_type == R_MICROMIPS_26_S1
+                       && ((mips16_branch_reloc_p (r_type)
+                            && !target_is_16_bit_code_p)
+                           || (micromips_branch_reloc_p (r_type)
                                && !target_is_micromips_code_p)
-                           || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
+                           || ((branch_reloc_p (r_type)
+                                || r_type == R_MIPS_JALR)
                                && (target_is_16_bit_code_p
                                    || target_is_micromips_code_p))));
 
-  local_p = (h == NULL
-            || (h->got_only_for_calls
-                ? SYMBOL_CALLS_LOCAL (info, &h->root)
-                : SYMBOL_REFERENCES_LOCAL (info, &h->root)));
+  local_p = (h == NULL || mips_use_local_got_p (info, h));
 
   gp0 = _bfd_get_gp_value (input_bfd);
   gp = _bfd_get_gp_value (abfd);
@@ -5332,6 +5680,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       addend = 0;
     }
 
+  resolved_to_zero = (h != NULL
+                     && UNDEFWEAK_NO_DYNAMIC_RELOC (info,
+                                                         &h->root));
+
   /* If we haven't already determined the GOT offset, and we're going
      to need it, get it now.  */
   switch (r_type)
@@ -5390,7 +5742,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
              if (!TLS_RELOC_P (r_type)
                  && !elf_hash_table (info)->dynamic_sections_created)
                /* This is a static link.  We must initialize the GOT entry.  */
-               MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g);
+               MIPS_ELF_PUT_WORD (dynobj, symbol, htab->root.sgot->contents + g);
            }
        }
       else if (!htab->is_vxworks
@@ -5445,14 +5797,16 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       return bfd_reloc_continue;
 
     case R_MIPS_16:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 16);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 16);
+      value = symbol + addend;
       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
     case R_MIPS_32:
     case R_MIPS_REL32:
     case R_MIPS_64:
-      if ((info->shared
+      if ((bfd_link_pic (info)
           || (htab->root.dynamic_sections_created
               && h != NULL
               && h->root.def_dynamic
@@ -5461,7 +5815,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
          && r_symndx != STN_UNDEF
          && (h == NULL
              || h->root.root.type != bfd_link_hash_undefweak
-             || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
+             || (ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
+                 && !resolved_to_zero))
          && (input_section->flags & SEC_ALLOC) != 0)
        {
          /* If we're creating a shared library, then we can't know
@@ -5507,20 +5862,26 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       {
        unsigned int shift;
 
-       /* 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_p && (symbol & 3) != (r_type == R_MIPS_26))
-         return bfd_reloc_outofrange;
-
        /* Shift is 2, unusually, for microMIPS JALX.  */
        shift = (!*cross_mode_jump_p && r_type == R_MICROMIPS_26_S1) ? 1 : 2;
 
-       if (was_local_p)
-         value = addend | ((p + 4) & (0xfc000000 << shift));
-       else
+       if (howto->partial_inplace && !section_p)
          value = _bfd_mips_elf_sign_extend (addend, 26 + shift);
-       value = (value + symbol) >> shift;
-       if (!was_local_p && h->root.root.type != bfd_link_hash_undefweak)
+       else
+         value = addend;
+       value += symbol;
+
+       /* Make sure the target of a jump is suitably aligned.  Bit 0 must
+          be the correct ISA mode selector except for weak undefined
+          symbols.  */
+       if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+           && (*cross_mode_jump_p
+               ? (value & 3) != (r_type == R_MIPS_26)
+               : (value & ((1 << shift) - 1)) != (r_type != R_MIPS_26)))
+         return bfd_reloc_outofrange;
+
+       value >>= shift;
+       if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
          overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift));
        value &= howto->dst_mask;
       }
@@ -5567,9 +5928,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       else
        {
          /* For MIPS16 ABI code we generate this sequence
-               0: li      $v0,%hi(_gp_disp)
-               4: addiupc $v1,%lo(_gp_disp)
-               8: sll     $v0,16
+               0: li      $v0,%hi(_gp_disp)
+               4: addiupc $v1,%lo(_gp_disp)
+               8: sll     $v0,16
               12: addu    $v0,$v1
               14: move    $gp,$v0
             So the offsets of hi and lo relocs are the same, but the
@@ -5585,7 +5946,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
            value = mips_elf_high (addend + gp - p - 1);
          else
            value = mips_elf_high (addend + gp - p);
-         overflowed_p = mips_elf_overflow_p (value, 16);
        }
       break;
 
@@ -5655,7 +6015,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
         to them before.  */
       if (was_local_p)
        value += gp0;
-      overflowed_p = mips_elf_overflow_p (value, 16);
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 16);
       break;
 
     case R_MIPS16_GOT16:
@@ -5703,36 +6064,168 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 
     case R_MIPS_PC16:
     case R_MIPS_GNU_REL16_S2:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 18) - p;
-      overflowed_p = mips_elf_overflow_p (value, 18);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 18);
+
+      /* No need to exclude weak undefined symbols here as they resolve
+        to 0 and never set `*cross_mode_jump_p', so this alignment check
+        will never trigger for them.  */
+      if (*cross_mode_jump_p
+         ? ((symbol + addend) & 3) != 1
+         : ((symbol + addend) & 3) != 0)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 18);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS16_PC16_S1:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend) & 3) != 0
+             : ((symbol + addend) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 17);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC21_S2:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 23);
+
+      if ((symbol + addend) & 3)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 23);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC26_S2:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 28);
+
+      if ((symbol + addend) & 3)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 28);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC18_S3:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 21);
+
+      if ((symbol + addend) & 7)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - ((p | 7) ^ 7);
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 21);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PC19_S2:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 21);
+
+      if ((symbol + addend) & 3)
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 21);
       value >>= howto->rightshift;
       value &= howto->dst_mask;
       break;
 
+    case R_MIPS_PCHI16:
+      value = mips_elf_high (symbol + addend - p);
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 16);
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_PCLO16:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 16);
+      value = symbol + addend - p;
+      value &= howto->dst_mask;
+      break;
+
     case R_MICROMIPS_PC7_S1:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p;
-      overflowed_p = mips_elf_overflow_p (value, 8);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 8);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend + 2) & 3) != 0
+             : ((symbol + addend + 2) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 8);
       value >>= howto->rightshift;
       value &= howto->dst_mask;
       break;
 
     case R_MICROMIPS_PC10_S1:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p;
-      overflowed_p = mips_elf_overflow_p (value, 11);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 11);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend + 2) & 3) != 0
+             : ((symbol + addend + 2) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 11);
       value >>= howto->rightshift;
       value &= howto->dst_mask;
       break;
 
     case R_MICROMIPS_PC16_S1:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p;
-      overflowed_p = mips_elf_overflow_p (value, 17);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend) & 3) != 0
+             : ((symbol + addend) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 17);
       value >>= howto->rightshift;
       value &= howto->dst_mask;
       break;
 
     case R_MICROMIPS_PC23_S2:
-      value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - ((p | 3) ^ 3);
-      overflowed_p = mips_elf_overflow_p (value, 25);
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 25);
+      value = symbol + addend - ((p | 3) ^ 3);
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 25);
       value >>= howto->rightshift;
       value &= howto->dst_mask;
       break;
@@ -5805,7 +6298,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
         when the symbol does not resolve locally.  */
       if (h != NULL && !SYMBOL_CALLS_LOCAL (info, &h->root))
        return bfd_reloc_continue;
+      /* We can't optimize cross-mode jumps either.  */
+      if (*cross_mode_jump_p)
+       return bfd_reloc_continue;
       value = symbol + addend;
+      /* Neither we can non-instruction-aligned targets.  */
+      if (r_type == R_MIPS_JALR ? (value & 3) != 0 : (value & 1) == 0)
+       return bfd_reloc_continue;
       break;
 
     case R_MIPS_PJUMP:
@@ -5831,11 +6330,13 @@ mips_elf_obtain_contents (reloc_howto_type *howto,
                          const Elf_Internal_Rela *relocation,
                          bfd *input_bfd, bfd_byte *contents)
 {
-  bfd_vma x;
+  bfd_vma x = 0;
   bfd_byte *location = contents + relocation->r_offset;
+  unsigned int size = bfd_get_reloc_size (howto);
 
   /* Obtain the bytes.  */
-  x = bfd_get ((8 * bfd_get_reloc_size (howto)), input_bfd, location);
+  if (size != 0)
+    x = bfd_get (8 * size, input_bfd, location);
 
   return x;
 }
@@ -5875,7 +6376,21 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
   /* Set the field.  */
   x |= (value & howto->dst_mask);
 
-  /* If required, turn JAL into JALX.  */
+  /* Detect incorrect JALX usage.  If required, turn JAL or BAL into JALX.  */
+  if (!cross_mode_jump_p && jal_reloc_p (r_type))
+    {
+      bfd_vma opcode = x >> 26;
+
+      if (r_type == R_MIPS16_26 ? opcode == 0x7
+         : r_type == R_MICROMIPS_26_S1 ? opcode == 0x3c
+         : opcode == 0x1d)
+       {
+         info->callbacks->einfo
+           (_("%X%H: unsupported JALX to the same ISA mode\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
+       }
+    }
   if (cross_mode_jump_p && jal_reloc_p (r_type))
     {
       bfd_boolean ok;
@@ -5900,41 +6415,92 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
        }
 
       /* If the opcode is not JAL or JALX, there's a problem.  We cannot
-         convert J or JALS to JALX.  */
+        convert J or JALS to JALX.  */
       if (!ok)
        {
-         (*_bfd_error_handler)
-           (_("%B: %A+0x%lx: Unsupported jump between ISA modes; consider recompiling with interlinking enabled."),
-            input_bfd,
-            input_section,
-            (unsigned long) relocation->r_offset);
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         info->callbacks->einfo
+           (_("%X%H: unsupported jump between ISA modes; "
+              "consider recompiling with interlinking enabled\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
        }
 
       /* Make this the JALX opcode.  */
       x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
     }
-
-  /* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in
-     range.  */
-  if (!info->relocatable
-      && !cross_mode_jump_p
-      && ((JAL_TO_BAL_P (input_bfd)
-          && r_type == R_MIPS_26
-          && (x >> 26) == 0x3)         /* jal addr */
-         || (JALR_TO_BAL_P (input_bfd)
-             && r_type == R_MIPS_JALR
-             && x == 0x0320f809)       /* jalr t9 */
-         || (JR_TO_B_P (input_bfd)
-             && r_type == R_MIPS_JALR
-             && x == 0x03200008)))     /* jr t9 */
+  else if (cross_mode_jump_p && b_reloc_p (r_type))
     {
+      bfd_boolean ok = FALSE;
+      bfd_vma opcode = x >> 16;
+      bfd_vma jalx_opcode = 0;
+      bfd_vma sign_bit = 0;
       bfd_vma addr;
       bfd_vma dest;
-      bfd_signed_vma off;
 
-      addr = (input_section->output_section->vma
+      if (r_type == R_MICROMIPS_PC16_S1)
+       {
+         ok = opcode == 0x4060;
+         jalx_opcode = 0x3c;
+         sign_bit = 0x10000;
+         value <<= 1;
+       }
+      else if (r_type == R_MIPS_PC16 || r_type == R_MIPS_GNU_REL16_S2)
+       {
+         ok = opcode == 0x411;
+         jalx_opcode = 0x1d;
+         sign_bit = 0x20000;
+         value <<= 2;
+       }
+
+      if (ok && !bfd_link_pic (info))
+       {
+         addr = (input_section->output_section->vma
+                 + input_section->output_offset
+                 + relocation->r_offset
+                 + 4);
+         dest = (addr
+                 + (((value & ((sign_bit << 1) - 1)) ^ sign_bit) - sign_bit));
+
+         if ((addr >> 28) << 28 != (dest >> 28) << 28)
+           {
+             info->callbacks->einfo
+               (_("%X%H: cannot convert branch between ISA modes "
+                  "to JALX: relocation out of range\n"),
+                input_bfd, input_section, relocation->r_offset);
+             return TRUE;
+           }
+
+         /* Make this the JALX opcode.  */
+         x = ((dest >> 2) & 0x3ffffff) | jalx_opcode << 26;
+       }
+      else if (!mips_elf_hash_table (info)->ignore_branch_isa)
+       {
+         info->callbacks->einfo
+           (_("%X%H: unsupported branch between ISA modes\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
+       }
+    }
+
+  /* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in
+     range.  */
+  if (!bfd_link_relocatable (info)
+      && !cross_mode_jump_p
+      && ((JAL_TO_BAL_P (input_bfd)
+          && r_type == R_MIPS_26
+          && (x >> 26) == 0x3)                 /* jal addr */
+         || (JALR_TO_BAL_P (input_bfd)
+             && r_type == R_MIPS_JALR
+             && x == 0x0320f809)               /* jalr t9 */
+         || (JR_TO_B_P (input_bfd)
+             && r_type == R_MIPS_JALR
+             && (x & ~1) == 0x03200008)))      /* jr t9 / jalr zero, t9 */
+    {
+      bfd_vma addr;
+      bfd_vma dest;
+      bfd_signed_vma off;
+
+      addr = (input_section->output_section->vma
              + input_section->output_offset
              + relocation->r_offset
              + 4);
@@ -5945,7 +6511,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
       off = dest - addr;
       if (off <= 0x1ffff && off >= -0x20000)
        {
-         if (x == 0x03200008)  /* jr t9 */
+         if ((x & ~1) == 0x03200008)           /* jr t9 / jalr zero, t9 */
            x = 0x10000000 | (((bfd_vma) off >> 2) & 0xffff);   /* b addr */
          else
            x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff);   /* bal addr */
@@ -5953,9 +6519,9 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
     }
 
   /* Put the value into the output.  */
-  bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
+  mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
 
-  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !info->relocatable,
+  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info),
                               location);
 
   return TRUE;
@@ -6233,8 +6799,17 @@ _bfd_elf_mips_mach (flagword flags)
     case E_MIPS_MACH_LS2F:
       return bfd_mach_mips_loongson_2f;
 
-    case E_MIPS_MACH_LS3A:
-      return bfd_mach_mips_loongson_3a;
+    case E_MIPS_MACH_GS464:
+      return bfd_mach_mips_gs464;
+
+    case E_MIPS_MACH_GS464E:
+      return bfd_mach_mips_gs464e;
+
+    case E_MIPS_MACH_GS264E:
+      return bfd_mach_mips_gs264e;
+
+    case E_MIPS_MACH_OCTEON3:
+      return bfd_mach_mips_octeon3;
 
     case E_MIPS_MACH_OCTEON2:
       return bfd_mach_mips_octeon2;
@@ -6245,6 +6820,9 @@ _bfd_elf_mips_mach (flagword flags)
     case E_MIPS_MACH_XLR:
       return bfd_mach_mips_xlr;
 
+    case E_MIPS_MACH_IAMR2:
+      return bfd_mach_mips_interaptiv_mr2;
+
     default:
       switch (flags & EF_MIPS_ARCH)
        {
@@ -6275,6 +6853,12 @@ _bfd_elf_mips_mach (flagword flags)
 
        case E_MIPS_ARCH_64R2:
          return bfd_mach_mipsisa64r2;
+
+       case E_MIPS_ARCH_32R6:
+         return bfd_mach_mipsisa32r6;
+
+       case E_MIPS_ARCH_64R6:
+         return bfd_mach_mipsisa64r6;
        }
     }
 
@@ -6398,7 +6982,7 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
          {
            asym->section = section;
            /* MIPS_TEXT is a bit special, the address is not an offset
-              to the base of the .text section.  So substract the section
+              to the base of the .text section.  So subtract the section
               base address to make it an offset.  */
            asym->value -= section->vma;
          }
@@ -6413,7 +6997,7 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
          {
            asym->section = section;
            /* MIPS_DATA is a bit special, the address is not an offset
-              to the base of the .data section.  So substract the section
+              to the base of the .data section.  So subtract the section
               base address to make it an offset.  */
            asym->value -= section->vma;
          }
@@ -6456,10 +7040,10 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
    We therefore take the following approach:
 
       - If ABFD contains a .gcc_compiled_longXX section, use it to
-        determine the pointer size.
+       determine the pointer size.
 
       - Otherwise check the type of the first relocation.  Assume that
-        the LP64 ABI is being used if the relocation is of type R_MIPS_64.
+       the LP64 ABI is being used if the relocation is of type R_MIPS_64.
 
       - Otherwise punt.
 
@@ -6474,7 +7058,7 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
    did so.  */
 
 unsigned int
-_bfd_mips_elf_eh_frame_address_size (bfd *abfd, asection *sec)
+_bfd_mips_elf_eh_frame_address_size (bfd *abfd, const asection *sec)
 {
   if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
     return 8;
@@ -6535,9 +7119,19 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
     {
       bfd_byte buf[4];
 
-      BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo));
       BFD_ASSERT (hdr->contents == NULL);
 
+      if (hdr->sh_size != sizeof (Elf32_External_RegInfo))
+       {
+         _bfd_error_handler
+           (_("%pB: incorrect `.reginfo' section size; "
+              "expected %" PRIu64 ", got %" PRIu64),
+            abfd, (uint64_t) sizeof (Elf32_External_RegInfo),
+            (uint64_t) hdr->sh_size);
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+
       if (bfd_seek (abfd,
                    hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4,
                    SEEK_SET) != 0)
@@ -6572,8 +7166,10 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
                                        &intopt);
          if (intopt.size < sizeof (Elf_External_Options))
            {
-             (*_bfd_error_handler)
-               (_("%B: Warning: bad `%s' option size %u smaller than its header"),
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: warning: bad `%s' option size %u smaller than"
+                  " its header"),
                abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
              break;
            }
@@ -6625,20 +7221,11 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
       if (strcmp (name, ".sdata") == 0
          || strcmp (name, ".lit8") == 0
          || strcmp (name, ".lit4") == 0)
-       {
-         hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
-         hdr->sh_type = SHT_PROGBITS;
-       }
+       hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
       else if (strcmp (name, ".srdata") == 0)
-       {
-         hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
-         hdr->sh_type = SHT_PROGBITS;
-       }
+       hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
       else if (strcmp (name, ".compact_rel") == 0)
-       {
-         hdr->sh_flags = 0;
-         hdr->sh_type = SHT_PROGBITS;
-       }
+       hdr->sh_flags = 0;
       else if (strcmp (name, ".rtproc") == 0)
        {
          if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0)
@@ -6720,9 +7307,14 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
       if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name))
        return FALSE;
       break;
+    case SHT_MIPS_ABIFLAGS:
+      if (!MIPS_ELF_ABIFLAGS_SECTION_NAME_P (name))
+       return FALSE;
+      flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE);
+      break;
     case SHT_MIPS_DWARF:
       if (! CONST_STRNEQ (name, ".debug_")
-          && ! CONST_STRNEQ (name, ".zdebug_"))
+         && ! CONST_STRNEQ (name, ".zdebug_"))
        return FALSE;
       break;
     case SHT_MIPS_SYMBOL_LIB:
@@ -6750,6 +7342,20 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
        return FALSE;
     }
 
+  if (hdr->sh_type == SHT_MIPS_ABIFLAGS)
+    {
+      Elf_External_ABIFlags_v0 ext;
+
+      if (! bfd_get_section_contents (abfd, hdr->bfd_section,
+                                     &ext, 0, sizeof ext))
+       return FALSE;
+      bfd_mips_elf_swap_abiflags_v0_in (abfd, &ext,
+                                       &mips_elf_tdata (abfd)->abiflags);
+      if (mips_elf_tdata (abfd)->abiflags.version != 0)
+       return FALSE;
+      mips_elf_tdata (abfd)->abiflags_valid = TRUE;
+    }
+
   /* FIXME: We should record sh_info for a .gptab section.  */
 
   /* For a .reginfo section, set the gp value in the tdata information
@@ -6795,8 +7401,10 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
                                        &intopt);
          if (intopt.size < sizeof (Elf_External_Options))
            {
-             (*_bfd_error_handler)
-               (_("%B: Warning: bad `%s' option size %u smaller than its header"),
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: warning: bad `%s' option size %u smaller than"
+                  " its header"),
                abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
              break;
            }
@@ -6859,7 +7467,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
     {
       hdr->sh_type = SHT_MIPS_DEBUG;
       /* In a shared object on IRIX 5.3, the .mdebug section has an
-         entsize of 0.  FIXME: Does this matter?  */
+        entsize of 0.  FIXME: Does this matter?  */
       if (SGI_COMPAT (abfd) && (abfd->flags & DYNAMIC) != 0)
        hdr->sh_entsize = 0;
       else
@@ -6869,7 +7477,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
     {
       hdr->sh_type = SHT_MIPS_REGINFO;
       /* In a shared object on IRIX 5.3, the .reginfo section has an
-         entsize of 0x18.  FIXME: Does this matter?  */
+        entsize of 0x18.  FIXME: Does this matter?  */
       if (SGI_COMPAT (abfd))
        {
          if ((abfd->flags & DYNAMIC) != 0)
@@ -6916,8 +7524,13 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
       hdr->sh_entsize = 1;
       hdr->sh_flags |= SHF_MIPS_NOSTRIP;
     }
+  else if (CONST_STRNEQ (name, ".MIPS.abiflags"))
+    {
+      hdr->sh_type = SHT_MIPS_ABIFLAGS;
+      hdr->sh_entsize = sizeof (Elf_External_ABIFlags_v0);
+    }
   else if (CONST_STRNEQ (name, ".debug_")
-           || CONST_STRNEQ (name, ".zdebug_"))
+          || CONST_STRNEQ (name, ".zdebug_"))
     {
       hdr->sh_type = SHT_MIPS_DWARF;
 
@@ -6931,7 +7544,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
     {
       hdr->sh_type = SHT_MIPS_SYMBOL_LIB;
       /* The sh_link and sh_info fields are set in
-         final_write_processing.  */
+        final_write_processing.  */
     }
   else if (CONST_STRNEQ (name, ".MIPS.events")
           || CONST_STRNEQ (name, ".MIPS.post_rel"))
@@ -7061,8 +7674,8 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
          elf_text_symbol->section = elf_text_section;
        }
       /* This code used to do *secp = bfd_und_section_ptr if
-         info->shared.  I don't know why, and that doesn't make sense,
-         so I took it out.  */
+        bfd_link_pic (info).  I don't know why, and that doesn't make sense,
+        so I took it out.  */
       *secp = mips_elf_tdata (abfd)->elf_text_section;
       break;
 
@@ -7102,8 +7715,8 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
          elf_data_symbol->section = elf_data_section;
        }
       /* This code used to do *secp = bfd_und_section_ptr if
-         info->shared.  I don't know why, and that doesn't make sense,
-         so I took it out.  */
+        bfd_link_pic (info).  I don't know why, and that doesn't make sense,
+        so I took it out.  */
       *secp = mips_elf_tdata (abfd)->elf_data_section;
       break;
 
@@ -7113,7 +7726,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
     }
 
   if (SGI_COMPAT (abfd)
-      && ! info->shared
+      && ! bfd_link_pic (info)
       && info->output_bfd->xvec == abfd->xvec
       && strcmp (*namep, "__rld_obj_head") == 0)
     {
@@ -7221,7 +7834,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   htab->sstubs = s;
 
   if (!mips_elf_hash_table (info)->use_rld_obj_head
-      && !info->shared
+      && bfd_link_executable (info)
       && bfd_get_linker_section (abfd, ".rld_map") == NULL)
     {
       s = bfd_make_section_anyway_with_flags (abfd, ".rld_map",
@@ -7247,6 +7860,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
            return FALSE;
 
          h = (struct elf_link_hash_entry *) bh;
+         h->mark = 1;
          h->non_elf = 0;
          h->def_regular = 1;
          h->type = STT_SECTION;
@@ -7265,23 +7879,27 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       /* Change alignments of some sections.  */
       s = bfd_get_linker_section (abfd, ".hash");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
       s = bfd_get_linker_section (abfd, ".dynsym");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
       s = bfd_get_linker_section (abfd, ".dynstr");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
       /* ??? */
       s = bfd_get_section_by_name (abfd, ".reginfo");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+
       s = bfd_get_linker_section (abfd, ".dynamic");
       if (s != NULL)
-       bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
     }
 
-  if (!info->shared)
+  if (bfd_link_executable (info))
     {
       const char *name;
 
@@ -7332,50 +7950,10 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (!_bfd_elf_create_dynamic_sections (abfd, info))
     return FALSE;
 
-  /* Cache the sections created above.  */
-  htab->splt = bfd_get_linker_section (abfd, ".plt");
-  htab->sdynbss = bfd_get_linker_section (abfd, ".dynbss");
-  if (htab->is_vxworks)
-    {
-      htab->srelbss = bfd_get_linker_section (abfd, ".rela.bss");
-      htab->srelplt = bfd_get_linker_section (abfd, ".rela.plt");
-    }
-  else
-    htab->srelplt = bfd_get_linker_section (abfd, ".rel.plt");
-  if (!htab->sdynbss
-      || (htab->is_vxworks && !htab->srelbss && !info->shared)
-      || !htab->srelplt
-      || !htab->splt)
-    abort ();
-
-  if (htab->is_vxworks)
-    {
-      /* Do the usual VxWorks handling.  */
-      if (!elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
-       return FALSE;
-
-      /* Work out the PLT sizes.  */
-      if (info->shared)
-       {
-         htab->plt_header_size
-           = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
-         htab->plt_entry_size
-           = 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry);
-       }
-      else
-       {
-         htab->plt_header_size
-           = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
-         htab->plt_entry_size
-           = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
-       }
-    }
-  else if (!info->shared)
-    {
-      /* All variants of the plt0 entry are the same size.  */
-      htab->plt_header_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry);
-      htab->plt_entry_size = 4 * ARRAY_SIZE (mips_exec_plt_entry);
-    }
+  /* Do the usual VxWorks handling.  */
+  if (htab->is_vxworks
+      && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
+    return FALSE;
 
   return TRUE;
 }
@@ -7413,16 +7991,24 @@ mips_elf_read_rel_addend (bfd *abfd, const Elf_Internal_Rela *rel,
   bfd_byte *location;
   unsigned int r_type;
   bfd_vma addend;
+  bfd_vma bytes;
 
   r_type = ELF_R_TYPE (abfd, rel->r_info);
   location = contents + rel->r_offset;
 
   /* Get the addend, which is stored in the input file.  */
   _bfd_mips_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
-  addend = mips_elf_obtain_contents (howto, rel, abfd, contents);
+  bytes = mips_elf_obtain_contents (howto, rel, abfd, contents);
   _bfd_mips_elf_reloc_shuffle (abfd, r_type, FALSE, location);
 
-  return addend & howto->src_mask;
+  addend = bytes & howto->src_mask;
+
+  /* Shift is 2, unusually, for microMIPS JALX.  Adjust the addend
+     accordingly.  */
+  if (r_type == R_MICROMIPS_26_S1 && (bytes >> 26) == 0x3c)
+    addend <<= 1;
+
+  return addend;
 }
 
 /* REL is a relocation in ABFD that needs a partnering LO16 relocation
@@ -7447,6 +8033,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
     lo16_type = R_MIPS16_LO16;
   else if (micromips_reloc_p (r_type))
     lo16_type = R_MICROMIPS_LO16;
+  else if (r_type == R_MIPS_PCHI16)
+    lo16_type = R_MIPS_PCLO16;
   else
     lo16_type = R_MIPS_LO16;
 
@@ -7503,8 +8091,27 @@ mips_elf_get_section_contents (bfd *abfd, asection *sec, bfd_byte **contents)
   return bfd_malloc_and_get_section (abfd, sec, contents);
 }
 
+/* Make a new PLT record to keep internal data.  */
+
+static struct plt_entry *
+mips_elf_make_plt_record (bfd *abfd)
+{
+  struct plt_entry *entry;
+
+  entry = bfd_zalloc (abfd, sizeof (*entry));
+  if (entry == NULL)
+    return NULL;
+
+  entry->stub_offset = MINUS_ONE;
+  entry->mips_offset = MINUS_ONE;
+  entry->comp_offset = MINUS_ONE;
+  entry->gotplt_index = MINUS_ONE;
+  return entry;
+}
+
 /* Look through the relocs for a section during the first phase, and
-   allocate space in the global offset table.  */
+   allocate space in the global offset table and record the need for
+   standard MIPS and compressed procedure linkage table entries.  */
 
 bfd_boolean
 _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
@@ -7524,7 +8131,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   bfd_vma addend;
   reloc_howto_type *howto;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   htab = mips_elf_hash_table (info);
@@ -7536,7 +8143,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
 
   bed = get_elf_backend_data (abfd);
-  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+  rel_end = relocs + sec->reloc_count;
 
   /* Check for the mips16 stub sections.  */
 
@@ -7546,13 +8153,14 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
 
       /* Look at the relocation information to figure out which symbol
-         this is for.  */
+        this is for.  */
 
       r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
       if (r_symndx == 0)
        {
-         (*_bfd_error_handler)
-           (_("%B: Warning: cannot determine the target function for"
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: warning: cannot determine the target function for"
               " stub section `%s'"),
             abfd, name);
          bfd_set_error (bfd_error_bad_value);
@@ -7565,8 +8173,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          asection *o;
 
          /* This stub is for a local symbol.  This stub will only be
-             needed if there is some relocation in this BFD, other
-             than a 16 bit function call, which refers to this symbol.  */
+            needed if there is some relocation in this BFD, other
+            than a 16 bit function call, which refers to this symbol.  */
          for (o = abfd->sections; o != NULL; o = o->next)
            {
              Elf_Internal_Rela *sec_relocs;
@@ -7600,16 +8208,16 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (o == NULL)
            {
              /* There is no non-call reloc for this stub, so we do
-                 not need it.  Since this function is called before
-                 the linker maps input sections to output sections, we
-                 can easily discard it by setting the SEC_EXCLUDE
-                 flag.  */
+                not need it.  Since this function is called before
+                the linker maps input sections to output sections, we
+                can easily discard it by setting the SEC_EXCLUDE
+                flag.  */
              sec->flags |= SEC_EXCLUDE;
              return TRUE;
            }
 
          /* Record this stub in an array of local symbol stubs for
-             this BFD.  */
+            this BFD.  */
          if (mips_elf_tdata (abfd)->local_stubs == NULL)
            {
              unsigned long symcount;
@@ -7631,9 +8239,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          mips_elf_tdata (abfd)->local_stubs[r_symndx] = sec;
 
          /* We don't need to set mips16_stubs_seen in this case.
-             That flag is used to see whether we need to look through
-             the global symbol table for stubs.  We don't need to set
-             it here, because we just have a local stub.  */
+            That flag is used to see whether we need to look through
+            the global symbol table for stubs.  We don't need to set
+            it here, because we just have a local stub.  */
        }
       else
        {
@@ -7671,13 +8279,14 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       asection **loc;
 
       /* Look at the relocation information to figure out which symbol
-         this is for.  */
+        this is for.  */
 
       r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
       if (r_symndx == 0)
        {
-         (*_bfd_error_handler)
-           (_("%B: Warning: cannot determine the target function for"
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: warning: cannot determine the target function for"
               " stub section `%s'"),
             abfd, name);
          bfd_set_error (bfd_error_bad_value);
@@ -7690,8 +8299,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          asection *o;
 
          /* This stub is for a local symbol.  This stub will only be
-             needed if there is some relocation (R_MIPS16_26) in this BFD
-             that refers to this symbol.  */
+            needed if there is some relocation (R_MIPS16_26) in this BFD
+            that refers to this symbol.  */
          for (o = abfd->sections; o != NULL; o = o->next)
            {
              Elf_Internal_Rela *sec_relocs;
@@ -7725,16 +8334,16 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (o == NULL)
            {
              /* There is no non-call reloc for this stub, so we do
-                 not need it.  Since this function is called before
-                 the linker maps input sections to output sections, we
-                 can easily discard it by setting the SEC_EXCLUDE
-                 flag.  */
+                not need it.  Since this function is called before
+                the linker maps input sections to output sections, we
+                can easily discard it by setting the SEC_EXCLUDE
+                flag.  */
              sec->flags |= SEC_EXCLUDE;
              return TRUE;
            }
 
          /* Record this stub in an array of local symbol call_stubs for
-             this BFD.  */
+            this BFD.  */
          if (mips_elf_tdata (abfd)->local_call_stubs == NULL)
            {
              unsigned long symcount;
@@ -7756,9 +8365,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          mips_elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
 
          /* We don't need to set mips16_stubs_seen in this case.
-             That flag is used to see whether we need to look through
-             the global symbol table for stubs.  We don't need to set
-             it here, because we just have a local stub.  */
+            That flag is used to see whether we need to look through
+            the global symbol table for stubs.  We don't need to set
+            it here, because we just have a local stub.  */
        }
       else
        {
@@ -7797,6 +8406,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned int r_type;
       struct elf_link_hash_entry *h;
       bfd_boolean can_make_dynamic_p;
+      bfd_boolean call_reloc_p;
+      bfd_boolean constrain_symbol_p;
 
       r_symndx = ELF_R_SYM (abfd, rel->r_info);
       r_type = ELF_R_TYPE (abfd, rel->r_info);
@@ -7805,8 +8416,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        h = NULL;
       else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
        {
-         (*_bfd_error_handler)
-           (_("%B: Malformed reloc detected for section %s"),
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: malformed reloc detected for section %s"),
             abfd, name);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
@@ -7814,21 +8426,41 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       else
        {
          h = sym_hashes[r_symndx - extsymoff];
-         while (h != NULL
-                && (h->root.type == bfd_link_hash_indirect
-                    || h->root.type == bfd_link_hash_warning))
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+         if (h != NULL)
+           {
+             while (h->root.type == bfd_link_hash_indirect
+                    || h->root.type == bfd_link_hash_warning)
+               h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           }
        }
 
       /* Set CAN_MAKE_DYNAMIC_P to true if we can convert this
         relocation into a dynamic one.  */
       can_make_dynamic_p = FALSE;
+
+      /* Set CALL_RELOC_P to true if the relocation is for a call,
+        and if pointer equality therefore doesn't matter.  */
+      call_reloc_p = FALSE;
+
+      /* Set CONSTRAIN_SYMBOL_P if we need to take the relocation
+        into account when deciding how to define the symbol.
+        Relocations in nonallocatable sections such as .pdr and
+        .debug* should have no effect.  */
+      constrain_symbol_p = ((sec->flags & SEC_ALLOC) != 0);
+
       switch (r_type)
        {
-       case R_MIPS_GOT16:
        case R_MIPS_CALL16:
        case R_MIPS_CALL_HI16:
        case R_MIPS_CALL_LO16:
+       case R_MIPS16_CALL16:
+       case R_MICROMIPS_CALL16:
+       case R_MICROMIPS_CALL_HI16:
+       case R_MICROMIPS_CALL_LO16:
+         call_reloc_p = TRUE;
+         /* Fall through.  */
+
+       case R_MIPS_GOT16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16:
        case R_MIPS_GOT_PAGE:
@@ -7838,14 +8470,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MIPS_TLS_GD:
        case R_MIPS_TLS_LDM:
        case R_MIPS16_GOT16:
-       case R_MIPS16_CALL16:
        case R_MIPS16_TLS_GOTTPREL:
        case R_MIPS16_TLS_GD:
        case R_MIPS16_TLS_LDM:
        case R_MICROMIPS_GOT16:
-       case R_MICROMIPS_CALL16:
-       case R_MICROMIPS_CALL_HI16:
-       case R_MICROMIPS_CALL_LO16:
        case R_MICROMIPS_GOT_HI16:
        case R_MICROMIPS_GOT_LO16:
        case R_MICROMIPS_GOT_PAGE:
@@ -7858,20 +8486,36 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            elf_hash_table (info)->dynobj = dynobj = abfd;
          if (!mips_elf_create_got_section (dynobj, info))
            return FALSE;
-         if (htab->is_vxworks && !info->shared)
+         if (htab->is_vxworks && !bfd_link_pic (info))
            {
-             (*_bfd_error_handler)
-               (_("%B: GOT reloc at 0x%lx not expected in executables"),
-                abfd, (unsigned long) rel->r_offset);
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: GOT reloc at %#" PRIx64 " not expected in executables"),
+                abfd, (uint64_t) rel->r_offset);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
            }
+         can_make_dynamic_p = TRUE;
          break;
 
-         /* This is just a hint; it can safely be ignored.  Don't set
-            has_static_relocs for the corresponding symbol.  */
+       case R_MIPS_NONE:
        case R_MIPS_JALR:
        case R_MICROMIPS_JALR:
+         /* These relocations have empty fields and are purely there to
+            provide link information.  The symbol value doesn't matter.  */
+         constrain_symbol_p = FALSE;
+         break;
+
+       case R_MIPS_GPREL16:
+       case R_MIPS_GPREL32:
+       case R_MIPS16_GPREL:
+       case R_MICROMIPS_GPREL16:
+         /* GP-relative relocations always resolve to a definition in a
+            regular input file, ignoring the one-definition rule.  This is
+            important for the GP setup sequence in NewABI code, which
+            always resolves to a local function even if other relocations
+            against the symbol wouldn't.  */
+         constrain_symbol_p = FALSE;
          break;
 
        case R_MIPS_32:
@@ -7886,7 +8530,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             one or using copy relocations or PLT entries.  It is
             usually better to do the former, unless the relocation is
             against a read-only section.  */
-         if ((info->shared
+         if ((bfd_link_pic (info)
               || (h != NULL
                   && !htab->is_vxworks
                   && strcmp (h->root.root.string, "__gnu_local_gp") != 0
@@ -7898,51 +8542,42 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              can_make_dynamic_p = TRUE;
              if (dynobj == NULL)
                elf_hash_table (info)->dynobj = dynobj = abfd;
-             break;
            }
-         /* For sections that are not SEC_ALLOC a copy reloc would be
-            output if possible (implying questionable semantics for
-            read-only data objects) or otherwise the final link would
-            fail as ld.so will not process them and could not therefore
-            handle any outstanding dynamic relocations.
-
-            For such sections that are also SEC_DEBUGGING, we can avoid
-            these problems by simply ignoring any relocs as these
-            sections have a predefined use and we know it is safe to do
-            so.
-
-            This is needed in cases such as a global symbol definition
-            in a shared library causing a common symbol from an object
-            file to be converted to an undefined reference.  If that
-            happens, then all the relocations against this symbol from
-            SEC_DEBUGGING sections in the object file will resolve to
-            nil.  */
-         if ((sec->flags & SEC_DEBUGGING) != 0)
-           break;
-         /* Fall through.  */
-
-       default:
-         /* Most static relocations require pointer equality, except
-            for branches.  */
-         if (h)
-           h->pointer_equality_needed = TRUE;
-         /* Fall through.  */
+         break;
 
        case R_MIPS_26:
        case R_MIPS_PC16:
+       case R_MIPS_PC21_S2:
+       case R_MIPS_PC26_S2:
        case R_MIPS16_26:
+       case R_MIPS16_PC16_S1:
        case R_MICROMIPS_26_S1:
        case R_MICROMIPS_PC7_S1:
        case R_MICROMIPS_PC10_S1:
        case R_MICROMIPS_PC16_S1:
        case R_MICROMIPS_PC23_S2:
-         if (h)
-           ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE;
+         call_reloc_p = TRUE;
          break;
        }
 
       if (h)
        {
+         if (constrain_symbol_p)
+           {
+             if (!can_make_dynamic_p)
+               ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = 1;
+
+             if (!call_reloc_p)
+               h->pointer_equality_needed = 1;
+
+             /* We must not create a stub for a symbol that has
+                relocations related to taking the function's address.
+                This doesn't apply to VxWorks, where CALL relocs refer
+                to a .got.plt entry instead of a normal .got entry.  */
+             if (!htab->is_vxworks && (!can_make_dynamic_p || !call_reloc_p))
+               ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
+           }
+
          /* Relocations against the special VxWorks __GOTT_BASE__ and
             __GOTT_INDEX__ symbols must be left to the loader.  Allocate
             room for them in .rela.dyn.  */
@@ -7991,9 +8626,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MICROMIPS_CALL16:
          if (h == NULL)
            {
-             (*_bfd_error_handler)
-               (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
-                abfd, (unsigned long) rel->r_offset);
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: CALL16 reloc at %#" PRIx64 " not against global symbol"),
+                abfd, (uint64_t) rel->r_offset);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
            }
@@ -8061,7 +8697,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
                  /* This symbol is definitely not overridable.  */
                  if (hmips->root.def_regular
-                     && ! (info->shared && ! info->symbolic
+                     && ! (bfd_link_pic (info) && ! info->symbolic
                            && ! hmips->root.forced_local))
                    h = NULL;
                }
@@ -8080,7 +8716,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MIPS_TLS_GOTTPREL:
        case R_MIPS16_TLS_GOTTPREL:
        case R_MICROMIPS_TLS_GOTTPREL:
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          /* Fall through */
 
@@ -8128,7 +8764,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  if (sreloc == NULL)
                    return FALSE;
                }
-             if (info->shared && h == NULL)
+             if (bfd_link_pic (info) && h == NULL)
                {
                  /* When creating a shared object, we must copy these
                     reloc types into the output file as R_MIPS_REL32
@@ -8201,27 +8837,29 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
        }
 
-      /* We must not create a stub for a symbol that has relocations
-        related to taking the function's address.  This doesn't apply to
-        VxWorks, where CALL relocs refer to a .got.plt entry instead of
-        a normal .got entry.  */
-      if (!htab->is_vxworks && h != NULL)
-       switch (r_type)
-         {
-         default:
-           ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
-           break;
-         case R_MIPS16_CALL16:
-         case R_MIPS_CALL16:
-         case R_MIPS_CALL_HI16:
-         case R_MIPS_CALL_LO16:
-         case R_MIPS_JALR:
-         case R_MICROMIPS_CALL16:
-         case R_MICROMIPS_CALL_HI16:
-         case R_MICROMIPS_CALL_LO16:
-         case R_MICROMIPS_JALR:
-           break;
-         }
+      /* Record the need for a PLT entry.  At this point we don't know
+        yet if we are going to create a PLT in the first place, but
+        we only record whether the relocation requires a standard MIPS
+        or a compressed code entry anyway.  If we don't make a PLT after
+        all, then we'll just ignore these arrangements.  Likewise if
+        a PLT entry is not created because the symbol is satisfied
+        locally.  */
+      if (h != NULL
+         && (branch_reloc_p (r_type)
+             || mips16_branch_reloc_p (r_type)
+             || micromips_branch_reloc_p (r_type))
+         && !SYMBOL_CALLS_LOCAL (info, h))
+       {
+         if (h->plt.plist == NULL)
+           h->plt.plist = mips_elf_make_plt_record (abfd);
+         if (h->plt.plist == NULL)
+           return FALSE;
+
+         if (branch_reloc_p (r_type))
+           h->plt.plist->need_mips = TRUE;
+         else
+           h->plt.plist->need_comp = TRUE;
+       }
 
       /* See if this reloc would need to refer to a MIPS16 hard-float stub,
         if there is one.  We only need to handle global symbols here;
@@ -8242,7 +8880,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
         not PIC, but we can create dynamic relocations and the result
         will be fine.  Also do not refuse R_MIPS_LO16, which can be
         combined with R_MIPS_GOT16.  */
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          switch (r_type)
            {
@@ -8274,8 +8912,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_MIPS_26:
            case R_MICROMIPS_26_S1:
              howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
-             (*_bfd_error_handler)
-               (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: relocation %s against `%s' can not be used"
+                  " when making a shared object; recompile with -fPIC"),
                 abfd, howto->name,
                 (h) ? h->root.root.string : "a local symbol");
              bfd_set_error (bfd_error_bad_value);
@@ -8289,167 +8929,6 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 \f
-bfd_boolean
-_bfd_mips_relax_section (bfd *abfd, asection *sec,
-                        struct bfd_link_info *link_info,
-                        bfd_boolean *again)
-{
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irel, *irelend;
-  Elf_Internal_Shdr *symtab_hdr;
-  bfd_byte *contents = NULL;
-  size_t extsymoff;
-  bfd_boolean changed_contents = FALSE;
-  bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
-  Elf_Internal_Sym *isymbuf = NULL;
-
-  /* We are not currently changing any sizes, so only one pass.  */
-  *again = FALSE;
-
-  if (link_info->relocatable)
-    return TRUE;
-
-  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
-                                              link_info->keep_memory);
-  if (internal_relocs == NULL)
-    return TRUE;
-
-  irelend = internal_relocs + sec->reloc_count
-    * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel;
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
-
-  for (irel = internal_relocs; irel < irelend; irel++)
-    {
-      bfd_vma symval;
-      bfd_signed_vma sym_offset;
-      unsigned int r_type;
-      unsigned long r_symndx;
-      asection *sym_sec;
-      unsigned long instruction;
-
-      /* Turn jalr into bgezal, and jr into beq, if they're marked
-        with a JALR relocation, that indicate where they jump to.
-        This saves some pipeline bubbles.  */
-      r_type = ELF_R_TYPE (abfd, irel->r_info);
-      if (r_type != R_MIPS_JALR)
-       continue;
-
-      r_symndx = ELF_R_SYM (abfd, irel->r_info);
-      /* Compute the address of the jump target.  */
-      if (r_symndx >= extsymoff)
-       {
-         struct mips_elf_link_hash_entry *h
-           = ((struct mips_elf_link_hash_entry *)
-              elf_sym_hashes (abfd) [r_symndx - extsymoff]);
-
-         while (h->root.root.type == bfd_link_hash_indirect
-                || h->root.root.type == bfd_link_hash_warning)
-           h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
-         /* If a symbol is undefined, or if it may be overridden,
-            skip it.  */
-         if (! ((h->root.root.type == bfd_link_hash_defined
-                 || h->root.root.type == bfd_link_hash_defweak)
-                && h->root.root.u.def.section)
-             || (link_info->shared && ! link_info->symbolic
-                 && !h->root.forced_local))
-           continue;
-
-         sym_sec = h->root.root.u.def.section;
-         if (sym_sec->output_section)
-           symval = (h->root.root.u.def.value
-                     + sym_sec->output_section->vma
-                     + sym_sec->output_offset);
-         else
-           symval = h->root.root.u.def.value;
-       }
-      else
-       {
-         Elf_Internal_Sym *isym;
-
-         /* Read this BFD's symbols if we haven't done so already.  */
-         if (isymbuf == NULL && symtab_hdr->sh_info != 0)
-           {
-             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
-             if (isymbuf == NULL)
-               isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
-                                               symtab_hdr->sh_info, 0,
-                                               NULL, NULL, NULL);
-             if (isymbuf == NULL)
-               goto relax_return;
-           }
-
-         isym = isymbuf + r_symndx;
-         if (isym->st_shndx == SHN_UNDEF)
-           continue;
-         else if (isym->st_shndx == SHN_ABS)
-           sym_sec = bfd_abs_section_ptr;
-         else if (isym->st_shndx == SHN_COMMON)
-           sym_sec = bfd_com_section_ptr;
-         else
-           sym_sec
-             = bfd_section_from_elf_index (abfd, isym->st_shndx);
-         symval = isym->st_value
-           + sym_sec->output_section->vma
-           + sym_sec->output_offset;
-       }
-
-      /* Compute branch offset, from delay slot of the jump to the
-        branch target.  */
-      sym_offset = (symval + irel->r_addend)
-       - (sec_start + irel->r_offset + 4);
-
-      /* Branch offset must be properly aligned.  */
-      if ((sym_offset & 3) != 0)
-       continue;
-
-      sym_offset >>= 2;
-
-      /* Check that it's in range.  */
-      if (sym_offset < -0x8000 || sym_offset >= 0x8000)
-       continue;
-
-      /* Get the section contents if we haven't done so already.  */
-      if (!mips_elf_get_section_contents (abfd, sec, &contents))
-       goto relax_return;
-
-      instruction = bfd_get_32 (abfd, contents + irel->r_offset);
-
-      /* If it was jalr <reg>, turn it into bgezal $zero, <target>.  */
-      if ((instruction & 0xfc1fffff) == 0x0000f809)
-       instruction = 0x04110000;
-      /* If it was jr <reg>, turn it into b <target>.  */
-      else if ((instruction & 0xfc1fffff) == 0x00000008)
-       instruction = 0x10000000;
-      else
-       continue;
-
-      instruction |= (sym_offset & 0xffff);
-      bfd_put_32 (abfd, instruction, contents + irel->r_offset);
-      changed_contents = TRUE;
-    }
-
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    {
-      if (!changed_contents && !link_info->keep_memory)
-        free (contents);
-      else
-        {
-          /* Cache the section contents for elf_link_input_bfd.  */
-          elf_section_data (sec)->this_hdr.contents = contents;
-        }
-    }
-  return TRUE;
-
- relax_return:
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    free (contents);
-  return FALSE;
-}
-\f
 /* Allocate space for global sym dynamic relocs.  */
 
 static bfd_boolean
@@ -8468,7 +8947,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
   /* VxWorks executables are handled elsewhere; we only need to
      allocate relocations in shared objects.  */
-  if (htab->is_vxworks && !info->shared)
+  if (htab->is_vxworks && !bfd_link_pic (info))
     return TRUE;
 
   /* Ignore indirect symbols.  All relocations against such symbols
@@ -8479,19 +8958,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   /* If this symbol is defined in a dynamic object, or we are creating
      a shared library, we will need to copy any R_MIPS_32 or
      R_MIPS_REL32 relocs against it into the output file.  */
-  if (! info->relocatable
+  if (! bfd_link_relocatable (info)
       && hmips->possibly_dynamic_relocs != 0
       && (h->root.type == bfd_link_hash_defweak
          || (!h->def_regular && !ELF_COMMON_DEF_P (h))
-         || info->shared))
+         || bfd_link_pic (info)))
     {
       bfd_boolean do_copy = TRUE;
 
       if (h->root.type == bfd_link_hash_undefweak)
        {
-         /* Do not copy relocations for undefined weak symbols with
-            non-default visibility.  */
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+         /* Do not copy relocations for undefined weak symbols that
+            we are not going to export.  */
+         if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
            do_copy = FALSE;
 
          /* Make sure undefined weak symbols are output as a dynamic
@@ -8545,6 +9024,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   bfd *dynobj;
   struct mips_elf_link_hash_entry *hmips;
   struct mips_elf_link_hash_table *htab;
+  asection *s, *srel;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
@@ -8555,7 +9035,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* Make sure we know what is going on here.  */
   BFD_ASSERT (dynobj != NULL
              && (h->needs_plt
-                 || h->u.weakdef != NULL
+                 || h->is_weakalias
                  || (h->def_dynamic
                      && h->ref_regular
                      && !h->def_regular)));
@@ -8579,7 +9059,8 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         the symbol to the stub location.  This is required to make
         function pointers compare as equal between the normal
         executable and the shared library.  */
-      if (!h->def_regular)
+      if (!h->def_regular
+         && !bfd_is_abs_section (htab->sstubs->output_section))
        {
          hmips->needs_lazy_stub = TRUE;
          htab->lazy_stub_count++;
@@ -8603,66 +9084,138 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
           && !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
                && h->root.type == bfd_link_hash_undefweak))
     {
-      /* If this is the first symbol to need a PLT entry, allocate room
-        for the header.  */
-      if (htab->splt->size == 0)
+      bfd_boolean micromips_p = MICROMIPS_P (info->output_bfd);
+      bfd_boolean newabi_p = NEWABI_P (info->output_bfd);
+
+      /* If this is the first symbol to need a PLT entry, then make some
+        basic setup.  Also work out PLT entry sizes.  We'll need them
+        for PLT offset calculations.  */
+      if (htab->plt_mips_offset + htab->plt_comp_offset == 0)
        {
-         BFD_ASSERT (htab->sgotplt->size == 0);
+         BFD_ASSERT (htab->root.sgotplt->size == 0);
+         BFD_ASSERT (htab->plt_got_index == 0);
 
          /* If we're using the PLT additions to the psABI, each PLT
             entry is 16 bytes and the PLT0 entry is 32 bytes.
             Encourage better cache usage by aligning.  We do this
             lazily to avoid pessimizing traditional objects.  */
          if (!htab->is_vxworks
-             && !bfd_set_section_alignment (dynobj, htab->splt, 5))
+             && !bfd_set_section_alignment (dynobj, htab->root.splt, 5))
            return FALSE;
 
          /* Make sure that .got.plt is word-aligned.  We do this lazily
             for the same reason as above.  */
-         if (!bfd_set_section_alignment (dynobj, htab->sgotplt,
+         if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt,
                                          MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
            return FALSE;
 
-         htab->splt->size += htab->plt_header_size;
-
          /* On non-VxWorks targets, the first two entries in .got.plt
             are reserved.  */
          if (!htab->is_vxworks)
-           htab->sgotplt->size
-             += get_elf_backend_data (dynobj)->got_header_size;
+           htab->plt_got_index
+             += (get_elf_backend_data (dynobj)->got_header_size
+                 / MIPS_ELF_GOT_SIZE (dynobj));
 
          /* On VxWorks, also allocate room for the header's
             .rela.plt.unloaded entries.  */
-         if (htab->is_vxworks && !info->shared)
+         if (htab->is_vxworks && !bfd_link_pic (info))
            htab->srelplt2->size += 2 * sizeof (Elf32_External_Rela);
+
+         /* Now work out the sizes of individual PLT entries.  */
+         if (htab->is_vxworks && bfd_link_pic (info))
+           htab->plt_mips_entry_size
+             = 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry);
+         else if (htab->is_vxworks)
+           htab->plt_mips_entry_size
+             = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
+         else if (newabi_p)
+           htab->plt_mips_entry_size
+             = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+         else if (!micromips_p)
+           {
+             htab->plt_mips_entry_size
+               = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+             htab->plt_comp_entry_size
+               = 2 * ARRAY_SIZE (mips16_o32_exec_plt_entry);
+           }
+         else if (htab->insn32)
+           {
+             htab->plt_mips_entry_size
+               = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+             htab->plt_comp_entry_size
+               = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt_entry);
+           }
+         else
+           {
+             htab->plt_mips_entry_size
+               = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+             htab->plt_comp_entry_size
+               = 2 * ARRAY_SIZE (micromips_o32_exec_plt_entry);
+           }
        }
 
-      /* Assign the next .plt entry to this symbol.  */
-      h->plt.offset = htab->splt->size;
-      htab->splt->size += htab->plt_entry_size;
+      if (h->plt.plist == NULL)
+       h->plt.plist = mips_elf_make_plt_record (dynobj);
+      if (h->plt.plist == NULL)
+       return FALSE;
+
+      /* There are no defined MIPS16 or microMIPS PLT entries for VxWorks,
+        n32 or n64, so always use a standard entry there.
+
+        If the symbol has a MIPS16 call stub and gets a PLT entry, then
+        all MIPS16 calls will go via that stub, and there is no benefit
+        to having a MIPS16 entry.  And in the case of call_stub a
+        standard entry actually has to be used as the stub ends with a J
+        instruction.  */
+      if (newabi_p
+         || htab->is_vxworks
+         || hmips->call_stub
+         || hmips->call_fp_stub)
+       {
+         h->plt.plist->need_mips = TRUE;
+         h->plt.plist->need_comp = FALSE;
+       }
+
+      /* Otherwise, if there are no direct calls to the function, we
+        have a free choice of whether to use standard or compressed
+        entries.  Prefer microMIPS entries if the object is known to
+        contain microMIPS code, so that it becomes possible to create
+        pure microMIPS binaries.  Prefer standard entries otherwise,
+        because MIPS16 ones are no smaller and are usually slower.  */
+      if (!h->plt.plist->need_mips && !h->plt.plist->need_comp)
+       {
+         if (micromips_p)
+           h->plt.plist->need_comp = TRUE;
+         else
+           h->plt.plist->need_mips = TRUE;
+       }
 
-      /* If the output file has no definition of the symbol, set the
-        symbol's value to the address of the stub.  */
-      if (!info->shared && !h->def_regular)
+      if (h->plt.plist->need_mips)
+       {
+         h->plt.plist->mips_offset = htab->plt_mips_offset;
+         htab->plt_mips_offset += htab->plt_mips_entry_size;
+       }
+      if (h->plt.plist->need_comp)
        {
-         h->root.u.def.section = htab->splt;
-         h->root.u.def.value = h->plt.offset;
-         /* For VxWorks, point at the PLT load stub rather than the
-            lazy resolution stub; this stub will become the canonical
-            function address.  */
-         if (htab->is_vxworks)
-           h->root.u.def.value += 8;
+         h->plt.plist->comp_offset = htab->plt_comp_offset;
+         htab->plt_comp_offset += htab->plt_comp_entry_size;
        }
 
-      /* Make room for the .got.plt entry and the R_MIPS_JUMP_SLOT
-        relocation.  */
-      htab->sgotplt->size += MIPS_ELF_GOT_SIZE (dynobj);
-      htab->srelplt->size += (htab->is_vxworks
-                             ? MIPS_ELF_RELA_SIZE (dynobj)
-                             : MIPS_ELF_REL_SIZE (dynobj));
+      /* Reserve the corresponding .got.plt entry now too.  */
+      h->plt.plist->gotplt_index = htab->plt_got_index++;
+
+      /* If the output file has no definition of the symbol, set the
+        symbol's value to the address of the stub.  */
+      if (!bfd_link_pic (info) && !h->def_regular)
+       hmips->use_plt_entry = TRUE;
+
+      /* Make room for the R_MIPS_JUMP_SLOT relocation.  */
+      htab->root.srelplt->size += (htab->is_vxworks
+                                  ? MIPS_ELF_RELA_SIZE (dynobj)
+                                  : MIPS_ELF_REL_SIZE (dynobj));
 
       /* Make room for the .rela.plt.unloaded relocations.  */
-      if (htab->is_vxworks && !info->shared)
+      if (htab->is_vxworks && !bfd_link_pic (info))
        htab->srelplt2->size += 3 * sizeof (Elf32_External_Rela);
 
       /* All relocations against this symbol that could have been made
@@ -8675,12 +9228,12 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.  */
-  if (h->u.weakdef != NULL)
+  if (h->is_weakalias)
     {
-      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
-                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->u.weakdef->root.u.def.section;
-      h->root.u.def.value = h->u.weakdef->root.u.def.value;
+      struct elf_link_hash_entry *def = weakdef (h);
+      BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+      h->root.u.def.section = def->root.u.def.section;
+      h->root.u.def.value = def->root.u.def.value;
       return TRUE;
     }
 
@@ -8696,11 +9249,11 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   /* We're now relying on copy relocations.  Complain if we have
      some that we can't convert.  */
-  if (!htab->use_plts_and_copy_relocs || info->shared)
+  if (!htab->use_plts_and_copy_relocs || bfd_link_pic (info))
     {
-      (*_bfd_error_handler) (_("non-dynamic relocations refer to "
-                              "dynamic symbol %s"),
-                            h->root.root.string);
+      _bfd_error_handler (_("non-dynamic relocations refer to "
+                           "dynamic symbol %s"),
+                         h->root.root.string);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
@@ -8715,10 +9268,20 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      both the dynamic object and the regular object will refer to the
      same memory location for the variable.  */
 
+  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+    {
+      s = htab->root.sdynrelro;
+      srel = htab->root.sreldynrelro;
+    }
+  else
+    {
+      s = htab->root.sdynbss;
+      srel = htab->root.srelbss;
+    }
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
     {
       if (htab->is_vxworks)
-       htab->srelbss->size += sizeof (Elf32_External_Rela);
+       srel->size += sizeof (Elf32_External_Rela);
       else
        mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
       h->needs_copy = 1;
@@ -8728,7 +9291,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      dynamic will now refer to the local copy instead.  */
   hmips->possibly_dynamic_relocs = 0;
 
-  return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 \f
 /* This function is called after all the input files have been read,
@@ -8739,7 +9302,7 @@ bfd_boolean
 _bfd_mips_elf_always_size_sections (bfd *output_bfd,
                                    struct bfd_link_info *info)
 {
-  asection *ri;
+  asection *sect;
   struct mips_elf_link_hash_table *htab;
   struct mips_htab_traverse_info hti;
 
@@ -8747,9 +9310,21 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
   BFD_ASSERT (htab != NULL);
 
   /* The .reginfo section has a fixed size.  */
-  ri = bfd_get_section_by_name (output_bfd, ".reginfo");
-  if (ri != NULL)
-    bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo));
+  sect = bfd_get_section_by_name (output_bfd, ".reginfo");
+  if (sect != NULL)
+    {
+      bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo));
+      sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
+    }
+
+  /* The .MIPS.abiflags section has a fixed size.  */
+  sect = bfd_get_section_by_name (output_bfd, ".MIPS.abiflags");
+  if (sect != NULL)
+    {
+      bfd_set_section_size (output_bfd, sect,
+                           sizeof (Elf_External_ABIFlags_v0));
+      sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
+    }
 
   hti.info = info;
   hti.output_bfd = output_bfd;
@@ -8779,7 +9354,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  s = htab->sgot;
+  s = htab->root.sgot;
   if (s == NULL)
     return TRUE;
 
@@ -8788,13 +9363,13 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
 
   /* Allocate room for the reserved entries.  VxWorks always reserves
      3 entries; other objects only reserve 2 entries.  */
-  BFD_ASSERT (g->assigned_gotno == 0);
+  BFD_ASSERT (g->assigned_low_gotno == 0);
   if (htab->is_vxworks)
     htab->reserved_gotno = 3;
   else
     htab->reserved_gotno = 2;
   g->local_gotno += htab->reserved_gotno;
-  g->assigned_gotno = htab->reserved_gotno;
+  g->assigned_low_gotno = htab->reserved_gotno;
 
   /* Decide which symbols need to go in the global part of the GOT and
      count the number of reloc-only GOT symbols.  */
@@ -8806,7 +9381,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
   /* Calculate the total loadable size of the output.  That
      will give us the maximum number of GOT_PAGE entries
      required.  */
-  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
     {
       asection *subsection;
 
@@ -8837,6 +9412,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
     page_gotno = g->page_gotno;
 
   g->local_gotno += page_gotno;
+  g->assigned_high_gotno = g->local_gotno - 1;
 
   s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
   s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
@@ -8854,7 +9430,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
     {
       /* Record that all bfds use G.  This also has the effect of freeing
         the per-bfd GOTs, which we no longer need.  */
-      for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+      for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
        if (mips_elf_bfd_got (ibfd, FALSE))
          mips_elf_replace_bfd_got (ibfd, g);
       mips_elf_replace_bfd_got (output_bfd, g);
@@ -8871,7 +9447,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
                  == g->global_gotno + g->local_gotno + g->tls_gotno);
 
       /* Each VxWorks GOT entry needs an explicit relocation.  */
-      if (htab->is_vxworks && info->shared)
+      if (htab->is_vxworks && bfd_link_pic (info))
        g->relocs += g->global_gotno + g->local_gotno - htab->reserved_gotno;
 
       /* Allocate room for the TLS relocations.  */
@@ -8907,29 +9483,62 @@ mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info)
   dynsymcount = (elf_hash_table (info)->dynsymcount
                 + count_section_dynsyms (output_bfd, info));
 
-  /* Determine the size of one stub entry.  */
-  htab->function_stub_size = (dynsymcount > 0x10000
-                             ? MIPS_FUNCTION_STUB_BIG_SIZE
-                             : MIPS_FUNCTION_STUB_NORMAL_SIZE);
+  /* Determine the size of one stub entry.  There's no disadvantage
+     from using microMIPS code here, so for the sake of pure-microMIPS
+     binaries we prefer it whenever there's any microMIPS code in
+     output produced at all.  This has a benefit of stubs being
+     shorter by 4 bytes each too, unless in the insn32 mode.  */
+  if (!MICROMIPS_P (output_bfd))
+    htab->function_stub_size = (dynsymcount > 0x10000
+                               ? MIPS_FUNCTION_STUB_BIG_SIZE
+                               : MIPS_FUNCTION_STUB_NORMAL_SIZE);
+  else if (htab->insn32)
+    htab->function_stub_size = (dynsymcount > 0x10000
+                               ? MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE
+                               : MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE);
+  else
+    htab->function_stub_size = (dynsymcount > 0x10000
+                               ? MICROMIPS_FUNCTION_STUB_BIG_SIZE
+                               : MICROMIPS_FUNCTION_STUB_NORMAL_SIZE);
 
   htab->sstubs->size = htab->lazy_stub_count * htab->function_stub_size;
 }
 
-/* A mips_elf_link_hash_traverse callback for which DATA points to the
-   MIPS hash table.  If H needs a traditional MIPS lazy-binding stub,
-   allocate an entry in the stubs section.  */
+/* A mips_elf_link_hash_traverse callback for which DATA points to a
+   mips_htab_traverse_info.  If H needs a traditional MIPS lazy-binding
+   stub, allocate an entry in the stubs section.  */
 
 static bfd_boolean
-mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data)
+mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void *data)
 {
+  struct mips_htab_traverse_info *hti = data;
   struct mips_elf_link_hash_table *htab;
-
-  htab = (struct mips_elf_link_hash_table *) data;
+  struct bfd_link_info *info;
+  bfd *output_bfd;
+
+  info = hti->info;
+  output_bfd = hti->output_bfd;
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
   if (h->needs_lazy_stub)
     {
+      bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+      unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+      bfd_vma isa_bit = micromips_p;
+
+      BFD_ASSERT (htab->root.dynobj != NULL);
+      if (h->root.plt.plist == NULL)
+       h->root.plt.plist = mips_elf_make_plt_record (htab->sstubs->owner);
+      if (h->root.plt.plist == NULL)
+       {
+         hti->error = TRUE;
+         return FALSE;
+       }
       h->root.root.u.def.section = htab->sstubs;
-      h->root.root.u.def.value = htab->sstubs->size;
-      h->root.plt.offset = htab->sstubs->size;
+      h->root.root.u.def.value = htab->sstubs->size + isa_bit;
+      h->root.plt.plist->stub_offset = htab->sstubs->size;
+      h->root.other = other;
       htab->sstubs->size += htab->function_stub_size;
     }
   return TRUE;
@@ -8938,22 +9547,97 @@ mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data)
 /* Allocate offsets in the stubs section to each symbol that needs one.
    Set the final size of the .MIPS.stub section.  */
 
-static void
+static bfd_boolean
 mips_elf_lay_out_lazy_stubs (struct bfd_link_info *info)
 {
+  bfd *output_bfd = info->output_bfd;
+  bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+  unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+  bfd_vma isa_bit = micromips_p;
   struct mips_elf_link_hash_table *htab;
+  struct mips_htab_traverse_info hti;
+  struct elf_link_hash_entry *h;
+  bfd *dynobj;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
   if (htab->lazy_stub_count == 0)
-    return;
+    return TRUE;
 
   htab->sstubs->size = 0;
-  mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, htab);
+  hti.info = info;
+  hti.output_bfd = output_bfd;
+  hti.error = FALSE;
+  mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, &hti);
+  if (hti.error)
+    return FALSE;
   htab->sstubs->size += htab->function_stub_size;
   BFD_ASSERT (htab->sstubs->size
              == htab->lazy_stub_count * htab->function_stub_size);
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+  h = _bfd_elf_define_linkage_sym (dynobj, info, htab->sstubs, "_MIPS_STUBS_");
+  if (h == NULL)
+    return FALSE;
+  h->root.u.def.value = isa_bit;
+  h->other = other;
+  h->type = STT_FUNC;
+
+  return TRUE;
+}
+
+/* A mips_elf_link_hash_traverse callback for which DATA points to a
+   bfd_link_info.  If H uses the address of a PLT entry as the value
+   of the symbol, then set the entry in the symbol table now.  Prefer
+   a standard MIPS PLT entry.  */
+
+static bfd_boolean
+mips_elf_set_plt_sym_value (struct mips_elf_link_hash_entry *h, void *data)
+{
+  struct bfd_link_info *info = data;
+  bfd_boolean micromips_p = MICROMIPS_P (info->output_bfd);
+  struct mips_elf_link_hash_table *htab;
+  unsigned int other;
+  bfd_vma isa_bit;
+  bfd_vma val;
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (h->use_plt_entry)
+    {
+      BFD_ASSERT (h->root.plt.plist != NULL);
+      BFD_ASSERT (h->root.plt.plist->mips_offset != MINUS_ONE
+                 || h->root.plt.plist->comp_offset != MINUS_ONE);
+
+      val = htab->plt_header_size;
+      if (h->root.plt.plist->mips_offset != MINUS_ONE)
+       {
+         isa_bit = 0;
+         val += h->root.plt.plist->mips_offset;
+         other = 0;
+       }
+      else
+       {
+         isa_bit = 1;
+         val += htab->plt_mips_offset + h->root.plt.plist->comp_offset;
+         other = micromips_p ? STO_MICROMIPS : STO_MIPS16;
+       }
+      val += isa_bit;
+      /* For VxWorks, point at the PLT load stub rather than the lazy
+        resolution stub; this stub will become the canonical function
+        address.  */
+      if (htab->is_vxworks)
+       val += 8;
+
+      h->root.root.u.def.section = htab->root.splt;
+      h->root.root.u.def.value = val;
+      h->root.other = other;
+    }
+
+  return TRUE;
 }
 
 /* Set the sizes of the dynamic sections.  */
@@ -8975,7 +9659,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
+      if (bfd_link_executable (info) && !info->nointerp)
        {
          s = bfd_get_linker_section (dynobj, ".interp");
          BFD_ASSERT (s != NULL);
@@ -8985,18 +9669,68 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
            = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
        }
 
-      /* Create a symbol for the PLT, if we know that we are using it.  */
-      if (htab->splt && htab->splt->size > 0 && htab->root.hplt == NULL)
+      /* Figure out the size of the PLT header if we know that we
+        are using it.  For the sake of cache alignment always use
+        a standard header whenever any standard entries are present
+        even if microMIPS entries are present as well.  This also
+        lets the microMIPS header rely on the value of $v0 only set
+        by microMIPS entries, for a small size reduction.
+
+        Set symbol table entry values for symbols that use the
+        address of their PLT entry now that we can calculate it.
+
+        Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we
+        haven't already in _bfd_elf_create_dynamic_sections.  */
+      if (htab->root.splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
        {
+         bfd_boolean micromips_p = (MICROMIPS_P (output_bfd)
+                                    && !htab->plt_mips_offset);
+         unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+         bfd_vma isa_bit = micromips_p;
          struct elf_link_hash_entry *h;
+         bfd_vma size;
 
          BFD_ASSERT (htab->use_plts_and_copy_relocs);
+         BFD_ASSERT (htab->root.sgotplt->size == 0);
+         BFD_ASSERT (htab->root.splt->size == 0);
+
+         if (htab->is_vxworks && bfd_link_pic (info))
+           size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
+         else if (htab->is_vxworks)
+           size = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
+         else if (ABI_64_P (output_bfd))
+           size = 4 * ARRAY_SIZE (mips_n64_exec_plt0_entry);
+         else if (ABI_N32_P (output_bfd))
+           size = 4 * ARRAY_SIZE (mips_n32_exec_plt0_entry);
+         else if (!micromips_p)
+           size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry);
+         else if (htab->insn32)
+           size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry);
+         else
+           size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry);
 
-         h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt,
-                                          "_PROCEDURE_LINKAGE_TABLE_");
-         htab->root.hplt = h;
-         if (h == NULL)
-           return FALSE;
+         htab->plt_header_is_comp = micromips_p;
+         htab->plt_header_size = size;
+         htab->root.splt->size = (size
+                                  + htab->plt_mips_offset
+                                  + htab->plt_comp_offset);
+         htab->root.sgotplt->size = (htab->plt_got_index
+                                     * MIPS_ELF_GOT_SIZE (dynobj));
+
+         mips_elf_link_hash_traverse (htab, mips_elf_set_plt_sym_value, info);
+
+         if (htab->root.hplt == NULL)
+           {
+             h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.splt,
+                                              "_PROCEDURE_LINKAGE_TABLE_");
+             htab->root.hplt = h;
+             if (h == NULL)
+               return FALSE;
+           }
+
+         h = htab->root.hplt;
+         h->root.u.def.value = isa_bit;
+         h->other = other;
          h->type = STT_FUNC;
        }
     }
@@ -9034,11 +9768,11 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
              asection *target;
 
              /* If this relocation section applies to a read only
-                 section, then we probably need a DT_TEXTREL entry.
-                 If the relocation section is .rel(a).dyn, we always
-                 assert a DT_TEXTREL entry rather than testing whether
-                 there exists a relocation to a read only section or
-                 not.  */
+                section, then we probably need a DT_TEXTREL entry.
+                If the relocation section is .rel(a).dyn, we always
+                assert a DT_TEXTREL entry rather than testing whether
+                there exists a relocation to a read only section or
+                not.  */
              outname = bfd_get_section_name (output_bfd,
                                              s->output_section);
              target = bfd_get_section_by_name (output_bfd, outname + 4);
@@ -9062,7 +9796,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
              info->combreloc = 0;
            }
        }
-      else if (! info->shared
+      else if (bfd_link_executable (info)
               && ! mips_elf_hash_table (info)->use_rld_obj_head
               && CONST_STRNEQ (name, ".rld_map"))
        {
@@ -9073,7 +9807,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
       else if (SGI_COMPAT (output_bfd)
               && CONST_STRNEQ (name, ".compact_rel"))
        s->size += mips_elf_hash_table (info)->compact_rel_size;
-      else if (s == htab->splt)
+      else if (s == htab->root.splt)
        {
          /* If the last PLT entry has a branch delay slot, allocate
             room for an extra nop to fill the delay slot.  This is
@@ -9083,10 +9817,11 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
            s->size += 4;
        }
       else if (! CONST_STRNEQ (name, ".init")
-              && s != htab->sgot
-              && s != htab->sgotplt
+              && s != htab->root.sgot
+              && s != htab->root.sgotplt
               && s != htab->sstubs
-              && s != htab->sdynbss)
+              && s != htab->root.sdynbss
+              && s != htab->root.sdynrelro)
        {
          /* It's not one of our sections, so don't allocate space.  */
          continue;
@@ -9121,13 +9856,17 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
         DT_MIPS_RLD_MAP entry.  This must come first because glibc
         only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and some tools
         may only look at the first one they see.  */
-      if (!info->shared
+      if (!bfd_link_pic (info)
          && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0))
        return FALSE;
 
+      if (bfd_link_executable (info)
+         && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP_REL, 0))
+       return FALSE;
+
       /* The DT_DEBUG entry may be filled in by the dynamic linker and
         used by the debugger.  */
-      if (info->executable
+      if (bfd_link_executable (info)
          && !SGI_COMPAT (output_bfd)
          && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
        return FALSE;
@@ -9169,7 +9908,8 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
        }
       else
        {
-         if (sreldyn && sreldyn->size > 0)
+         if (sreldyn && sreldyn->size > 0
+             && !bfd_is_abs_section (sreldyn->output_section))
            {
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
                return FALSE;
@@ -9212,7 +9952,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
              && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
            return FALSE;
        }
-      if (htab->splt->size > 0)
+      if (htab->root.splt->size > 0)
        {
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
            return FALSE;
@@ -9263,7 +10003,7 @@ mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info,
       sym = local_syms + r_symndx;
 
       /* Adjust REL's addend to account for section merging.  */
-      if (!info->relocatable)
+      if (!bfd_link_relocatable (info))
        {
          sec = local_sections[r_symndx];
          _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
@@ -9337,18 +10077,16 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   const Elf_Internal_Rela *relend;
   bfd_vma addend = 0;
   bfd_boolean use_saved_addend_p = FALSE;
-  const struct elf_backend_data *bed;
 
-  bed = get_elf_backend_data (output_bfd);
-  relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
+  relend = relocs + input_section->reloc_count;
   for (rel = relocs; rel < relend; ++rel)
     {
       const char *name;
       bfd_vma value = 0;
       reloc_howto_type *howto;
-      bfd_boolean cross_mode_jump_p;
+      bfd_boolean cross_mode_jump_p = FALSE;
       /* TRUE if the relocation is a RELA relocation, rather than a
-         REL relocation.  */
+        REL relocation.  */
       bfd_boolean rela_relocation_p = TRUE;
       unsigned int r_type = ELF_R_TYPE (output_bfd, rel->r_info);
       const char *msg;
@@ -9439,10 +10177,12 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                        name = bfd_elf_sym_name (input_bfd, symtab_hdr,
                                                 local_syms + r_symndx,
                                                 sec);
-                     (*_bfd_error_handler)
-                       (_("%B: Can't find matching LO16 reloc against `%s' for %s at 0x%lx in section `%A'"),
-                        input_bfd, input_section, name, howto->name,
-                        rel->r_offset);
+                     _bfd_error_handler
+                       /* xgettext:c-format */
+                       (_("%pB: can't find matching LO16 reloc against `%s'"
+                          " for %s at %#" PRIx64 " in section `%pA'"),
+                        input_bfd, name,
+                        howto->name, (uint64_t) rel->r_offset, input_section);
                    }
                }
              else
@@ -9454,7 +10194,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                                  local_syms, local_sections, rel);
        }
 
-      if (info->relocatable)
+      if (bfd_link_relocatable (info))
        {
          if (r_type == R_MIPS_64 && ! NEWABI_P (output_bfd)
              && bfd_big_endian (input_bfd))
@@ -9585,10 +10325,9 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  htab->small_data_overflow_reported = TRUE;
                  (*info->callbacks->einfo) ("%P: %s\n", msg);
                }
-             if (! ((*info->callbacks->reloc_overflow)
-                    (info, NULL, name, howto->name, (bfd_vma) 0,
-                     input_bfd, input_section, rel->r_offset)))
-               return FALSE;
+             (*info->callbacks->reloc_overflow)
+               (info, NULL, name, howto->name, (bfd_vma) 0,
+                input_bfd, input_section, rel->r_offset);
            }
          break;
 
@@ -9596,12 +10335,26 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          break;
 
        case bfd_reloc_outofrange:
+         msg = NULL;
          if (jal_reloc_p (howto->type))
+           msg = (cross_mode_jump_p
+                  ? _("cannot convert a jump to JALX "
+                      "for a non-word-aligned address")
+                  : (howto->type == R_MIPS16_26
+                     ? _("jump to a non-word-aligned address")
+                     : _("jump to a non-instruction-aligned address")));
+         else if (b_reloc_p (howto->type))
+           msg = (cross_mode_jump_p
+                  ? _("cannot convert a branch to JALX "
+                      "for a non-word-aligned address")
+                  : _("branch to a non-instruction-aligned address"));
+         else if (aligned_pcrel_reloc_p (howto->type))
+           msg = _("PC-relative load from unaligned address");
+         if (msg)
            {
-             msg = _("JALX to a non-word-aligned address");
-             info->callbacks->warning
-               (info, msg, name, input_bfd, input_section, rel->r_offset);
-             return FALSE;
+             info->callbacks->einfo
+               ("%X%H: %s\n", input_bfd, input_section, rel->r_offset, msg);
+             break;
            }
          /* Fall through.  */
 
@@ -9835,68 +10588,180 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 
   BFD_ASSERT (!htab->is_vxworks);
 
-  if (h->plt.offset != MINUS_ONE && hmips->no_fn_stub)
+  if (h->plt.plist != NULL
+      && (h->plt.plist->mips_offset != MINUS_ONE
+         || h->plt.plist->comp_offset != MINUS_ONE))
     {
       /* We've decided to create a PLT entry for this symbol.  */
       bfd_byte *loc;
-      bfd_vma header_address, plt_index, got_address;
+      bfd_vma header_address, got_address;
       bfd_vma got_address_high, got_address_low, load;
-      const bfd_vma *plt_entry;
+      bfd_vma got_index;
+      bfd_vma isa_bit;
+
+      got_index = h->plt.plist->gotplt_index;
 
       BFD_ASSERT (htab->use_plts_and_copy_relocs);
       BFD_ASSERT (h->dynindx != -1);
-      BFD_ASSERT (htab->splt != NULL);
-      BFD_ASSERT (h->plt.offset <= htab->splt->size);
+      BFD_ASSERT (htab->root.splt != NULL);
+      BFD_ASSERT (got_index != MINUS_ONE);
       BFD_ASSERT (!h->def_regular);
 
       /* Calculate the address of the PLT header.  */
-      header_address = (htab->splt->output_section->vma
-                       + htab->splt->output_offset);
-
-      /* Calculate the index of the entry.  */
-      plt_index = ((h->plt.offset - htab->plt_header_size)
-                  / htab->plt_entry_size);
+      isa_bit = htab->plt_header_is_comp;
+      header_address = (htab->root.splt->output_section->vma
+                       + htab->root.splt->output_offset + isa_bit);
 
       /* Calculate the address of the .got.plt entry.  */
-      got_address = (htab->sgotplt->output_section->vma
-                    + htab->sgotplt->output_offset
-                    + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj));
+      got_address = (htab->root.sgotplt->output_section->vma
+                    + htab->root.sgotplt->output_offset
+                    + got_index * MIPS_ELF_GOT_SIZE (dynobj));
+
       got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
       got_address_low = got_address & 0xffff;
 
+      /* The PLT sequence is not safe for N64 if .got.plt entry's address
+        cannot be loaded in two instructions.  */
+      if (ABI_64_P (output_bfd)
+         && ((got_address + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: `%pA' entry VMA of %#" PRIx64 " outside the 32-bit range "
+              "supported; consider using `-Ttext-segment=...'"),
+            output_bfd,
+            htab->root.sgotplt->output_section,
+            (int64_t) got_address);
+         bfd_set_error (bfd_error_no_error);
+         return FALSE;
+       }
+
       /* Initially point the .got.plt entry at the PLT header.  */
-      loc = (htab->sgotplt->contents
-            + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj));
+      loc = (htab->root.sgotplt->contents
+            + got_index * MIPS_ELF_GOT_SIZE (dynobj));
       if (ABI_64_P (output_bfd))
        bfd_put_64 (output_bfd, header_address, loc);
       else
        bfd_put_32 (output_bfd, header_address, loc);
 
-      /* Find out where the .plt entry should go.  */
-      loc = htab->splt->contents + h->plt.offset;
+      /* Now handle the PLT itself.  First the standard entry (the order
+        does not matter, we just have to pick one).  */
+      if (h->plt.plist->mips_offset != MINUS_ONE)
+       {
+         const bfd_vma *plt_entry;
+         bfd_vma plt_offset;
 
-      /* Pick the load opcode.  */
-      load = MIPS_ELF_LOAD_WORD (output_bfd);
+         plt_offset = htab->plt_header_size + h->plt.plist->mips_offset;
 
-      /* Fill in the PLT entry itself.  */
-      plt_entry = mips_exec_plt_entry;
-      bfd_put_32 (output_bfd, plt_entry[0] | got_address_high, loc);
-      bfd_put_32 (output_bfd, plt_entry[1] | got_address_low | load, loc + 4);
+         BFD_ASSERT (plt_offset <= htab->root.splt->size);
 
-      if (! LOAD_INTERLOCKS_P (output_bfd))
-       {
-         bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8);
-         bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
+         /* Find out where the .plt entry should go.  */
+         loc = htab->root.splt->contents + plt_offset;
+
+         /* Pick the load opcode.  */
+         load = MIPS_ELF_LOAD_WORD (output_bfd);
+
+         /* Fill in the PLT entry itself.  */
+
+         if (MIPSR6_P (output_bfd))
+           plt_entry = mipsr6_exec_plt_entry;
+         else
+           plt_entry = mips_exec_plt_entry;
+         bfd_put_32 (output_bfd, plt_entry[0] | got_address_high, loc);
+         bfd_put_32 (output_bfd, plt_entry[1] | got_address_low | load,
+                     loc + 4);
+
+         if (! LOAD_INTERLOCKS_P (output_bfd))
+           {
+             bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8);
+             bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
+           }
+         else
+           {
+             bfd_put_32 (output_bfd, plt_entry[3], loc + 8);
+             bfd_put_32 (output_bfd, plt_entry[2] | got_address_low,
+                         loc + 12);
+           }
        }
-      else
+
+      /* Now the compressed entry.  They come after any standard ones.  */
+      if (h->plt.plist->comp_offset != MINUS_ONE)
        {
-         bfd_put_32 (output_bfd, plt_entry[3], loc + 8);
-         bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 12);
+         bfd_vma plt_offset;
+
+         plt_offset = (htab->plt_header_size + htab->plt_mips_offset
+                       + h->plt.plist->comp_offset);
+
+         BFD_ASSERT (plt_offset <= htab->root.splt->size);
+
+         /* Find out where the .plt entry should go.  */
+         loc = htab->root.splt->contents + plt_offset;
+
+         /* Fill in the PLT entry itself.  */
+         if (!MICROMIPS_P (output_bfd))
+           {
+             const bfd_vma *plt_entry = mips16_o32_exec_plt_entry;
+
+             bfd_put_16 (output_bfd, plt_entry[0], loc);
+             bfd_put_16 (output_bfd, plt_entry[1], loc + 2);
+             bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+             bfd_put_16 (output_bfd, plt_entry[3], loc + 6);
+             bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+             bfd_put_16 (output_bfd, plt_entry[5], loc + 10);
+             bfd_put_32 (output_bfd, got_address, loc + 12);
+           }
+         else if (htab->insn32)
+           {
+             const bfd_vma *plt_entry = micromips_insn32_o32_exec_plt_entry;
+
+             bfd_put_16 (output_bfd, plt_entry[0], loc);
+             bfd_put_16 (output_bfd, got_address_high, loc + 2);
+             bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+             bfd_put_16 (output_bfd, got_address_low, loc + 6);
+             bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+             bfd_put_16 (output_bfd, plt_entry[5], loc + 10);
+             bfd_put_16 (output_bfd, plt_entry[6], loc + 12);
+             bfd_put_16 (output_bfd, got_address_low, loc + 14);
+           }
+         else
+           {
+             const bfd_vma *plt_entry = micromips_o32_exec_plt_entry;
+             bfd_signed_vma gotpc_offset;
+             bfd_vma loc_address;
+
+             BFD_ASSERT (got_address % 4 == 0);
+
+             loc_address = (htab->root.splt->output_section->vma
+                            + htab->root.splt->output_offset + plt_offset);
+             gotpc_offset = got_address - ((loc_address | 3) ^ 3);
+
+             /* ADDIUPC has a span of +/-16MB, check we're in range.  */
+             if (gotpc_offset + 0x1000000 >= 0x2000000)
+               {
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: `%pA' offset of %" PRId64 " from `%pA' "
+                      "beyond the range of ADDIUPC"),
+                    output_bfd,
+                    htab->root.sgotplt->output_section,
+                    (int64_t) gotpc_offset,
+                    htab->root.splt->output_section);
+                 bfd_set_error (bfd_error_no_error);
+                 return FALSE;
+               }
+             bfd_put_16 (output_bfd,
+                         plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc);
+             bfd_put_16 (output_bfd, (gotpc_offset >> 2) & 0xffff, loc + 2);
+             bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+             bfd_put_16 (output_bfd, plt_entry[3], loc + 6);
+             bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+             bfd_put_16 (output_bfd, plt_entry[5], loc + 10);
+           }
        }
 
       /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry.  */
-      mips_elf_output_dynamic_relocation (output_bfd, htab->srelplt,
-                                         plt_index, h->dynindx,
+      mips_elf_output_dynamic_relocation (output_bfd, htab->root.srelplt,
+                                         got_index - 2, h->dynindx,
                                          R_MIPS_JUMP_SLOT, got_address);
 
       /* We distinguish between PLT entries and lazy-binding stubs by
@@ -9905,21 +10770,36 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
         binary where pointer equality matters.  */
       sym->st_shndx = SHN_UNDEF;
       if (h->pointer_equality_needed)
-       sym->st_other = STO_MIPS_PLT;
+       sym->st_other = ELF_ST_SET_MIPS_PLT (sym->st_other);
       else
-       sym->st_value = 0;
+       {
+         sym->st_value = 0;
+         sym->st_other = 0;
+       }
     }
-  else if (h->plt.offset != MINUS_ONE)
+
+  if (h->plt.plist != NULL && h->plt.plist->stub_offset != MINUS_ONE)
     {
       /* We've decided to create a lazy-binding stub.  */
+      bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
+      unsigned int other = micromips_p ? STO_MICROMIPS : 0;
+      bfd_vma stub_size = htab->function_stub_size;
       bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
+      bfd_vma isa_bit = micromips_p;
+      bfd_vma stub_big_size;
+
+      if (!micromips_p)
+       stub_big_size = MIPS_FUNCTION_STUB_BIG_SIZE;
+      else if (htab->insn32)
+       stub_big_size = MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE;
+      else
+       stub_big_size = MICROMIPS_FUNCTION_STUB_BIG_SIZE;
 
       /* This symbol has a stub.  Set it up.  */
 
       BFD_ASSERT (h->dynindx != -1);
 
-      BFD_ASSERT ((htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-                  || (h->dynindx <= 0xffff));
+      BFD_ASSERT (stub_size == stub_big_size || h->dynindx <= 0xffff);
 
       /* Values up to 2^31 - 1 are allowed.  Larger values would cause
         sign extension at runtime in the stub, resulting in a negative
@@ -9928,35 +10808,94 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
        return FALSE;
 
       /* Fill the stub.  */
-      idx = 0;
-      bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub + idx);
-      idx += 4;
-      bfd_put_32 (output_bfd, STUB_MOVE (output_bfd), stub + idx);
-      idx += 4;
-      if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-        {
-          bfd_put_32 (output_bfd, STUB_LUI ((h->dynindx >> 16) & 0x7fff),
-                      stub + idx);
-          idx += 4;
-        }
-      bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
-      idx += 4;
-
-      /* If a large stub is not required and sign extension is not a
-         problem, then use legacy code in the stub.  */
-      if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-       bfd_put_32 (output_bfd, STUB_ORI (h->dynindx & 0xffff), stub + idx);
-      else if (h->dynindx & ~0x7fff)
-        bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff), stub + idx);
+      if (micromips_p)
+       {
+         idx = 0;
+         bfd_put_micromips_32 (output_bfd, STUB_LW_MICROMIPS (output_bfd),
+                               stub + idx);
+         idx += 4;
+         if (htab->insn32)
+           {
+             bfd_put_micromips_32 (output_bfd,
+                                   STUB_MOVE32_MICROMIPS, stub + idx);
+             idx += 4;
+           }
+         else
+           {
+             bfd_put_16 (output_bfd, STUB_MOVE_MICROMIPS, stub + idx);
+             idx += 2;
+           }
+         if (stub_size == stub_big_size)
+           {
+             long dynindx_hi = (h->dynindx >> 16) & 0x7fff;
+
+             bfd_put_micromips_32 (output_bfd,
+                                   STUB_LUI_MICROMIPS (dynindx_hi),
+                                   stub + idx);
+             idx += 4;
+           }
+         if (htab->insn32)
+           {
+             bfd_put_micromips_32 (output_bfd, STUB_JALR32_MICROMIPS,
+                                   stub + idx);
+             idx += 4;
+           }
+         else
+           {
+             bfd_put_16 (output_bfd, STUB_JALR_MICROMIPS, stub + idx);
+             idx += 2;
+           }
+
+         /* If a large stub is not required and sign extension is not a
+            problem, then use legacy code in the stub.  */
+         if (stub_size == stub_big_size)
+           bfd_put_micromips_32 (output_bfd,
+                                 STUB_ORI_MICROMIPS (h->dynindx & 0xffff),
+                                 stub + idx);
+         else if (h->dynindx & ~0x7fff)
+           bfd_put_micromips_32 (output_bfd,
+                                 STUB_LI16U_MICROMIPS (h->dynindx & 0xffff),
+                                 stub + idx);
+         else
+           bfd_put_micromips_32 (output_bfd,
+                                 STUB_LI16S_MICROMIPS (output_bfd,
+                                                       h->dynindx),
+                                 stub + idx);
+       }
       else
-        bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
-                   stub + idx);
+       {
+         idx = 0;
+         bfd_put_32 (output_bfd, STUB_LW (output_bfd), stub + idx);
+         idx += 4;
+         bfd_put_32 (output_bfd, STUB_MOVE, stub + idx);
+         idx += 4;
+         if (stub_size == stub_big_size)
+           {
+             bfd_put_32 (output_bfd, STUB_LUI ((h->dynindx >> 16) & 0x7fff),
+                         stub + idx);
+             idx += 4;
+           }
+         bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
+         idx += 4;
+
+         /* If a large stub is not required and sign extension is not a
+            problem, then use legacy code in the stub.  */
+         if (stub_size == stub_big_size)
+           bfd_put_32 (output_bfd, STUB_ORI (h->dynindx & 0xffff),
+                       stub + idx);
+         else if (h->dynindx & ~0x7fff)
+           bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff),
+                       stub + idx);
+         else
+           bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
+                       stub + idx);
+       }
 
-      BFD_ASSERT (h->plt.offset <= htab->sstubs->size);
-      memcpy (htab->sstubs->contents + h->plt.offset,
-             stub, htab->function_stub_size);
+      BFD_ASSERT (h->plt.plist->stub_offset <= htab->sstubs->size);
+      memcpy (htab->sstubs->contents + h->plt.plist->stub_offset,
+             stub, stub_size);
 
-      /* Mark the symbol as undefined.  plt.offset != -1 occurs
+      /* Mark the symbol as undefined.  stub_offset != -1 occurs
         only for the referenced symbol.  */
       sym->st_shndx = SHN_UNDEF;
 
@@ -9965,7 +10904,9 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
         to its stub address when unlinking a shared object.  */
       sym->st_value = (htab->sstubs->output_section->vma
                       + htab->sstubs->output_offset
-                      + h->plt.offset);
+                      + h->plt.plist->stub_offset
+                      + isa_bit);
+      sym->st_other = other;
     }
 
   /* If we have a MIPS16 function with a stub, the dynamic symbol must
@@ -9983,7 +10924,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
   BFD_ASSERT (h->dynindx != -1
              || h->forced_local);
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   g = htab->got_info;
   BFD_ASSERT (g != NULL);
 
@@ -10019,8 +10960,8 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
                                                           &e)))
            {
              offset = p->gotidx;
-             BFD_ASSERT (offset > 0 && offset < htab->sgot->size);
-             if (info->shared
+             BFD_ASSERT (offset > 0 && offset < htab->root.sgot->size);
+             if (bfd_link_pic (info)
                  || (elf_hash_table (info)->dynamic_sections_created
                      && p->d.h != NULL
                      && p->d.h->root.def_dynamic
@@ -10065,12 +11006,6 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
       sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
       sym->st_value = 1;
     }
-  else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (output_bfd))
-    {
-      sym->st_shndx = SHN_ABS;
-      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
-      sym->st_value = elf_gp (output_bfd);
-    }
   else if (SGI_COMPAT (output_bfd))
     {
       if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
@@ -10153,30 +11088,32 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
   dynobj = elf_hash_table (info)->dynobj;
   hmips = (struct mips_elf_link_hash_entry *) h;
 
-  if (h->plt.offset != (bfd_vma) -1)
+  if (h->plt.plist != NULL && h->plt.plist->mips_offset != MINUS_ONE)
     {
       bfd_byte *loc;
-      bfd_vma plt_address, plt_index, got_address, got_offset, branch_offset;
+      bfd_vma plt_address, got_address, got_offset, branch_offset;
       Elf_Internal_Rela rel;
       static const bfd_vma *plt_entry;
+      bfd_vma gotplt_index;
+      bfd_vma plt_offset;
+
+      plt_offset = htab->plt_header_size + h->plt.plist->mips_offset;
+      gotplt_index = h->plt.plist->gotplt_index;
 
       BFD_ASSERT (h->dynindx != -1);
-      BFD_ASSERT (htab->splt != NULL);
-      BFD_ASSERT (h->plt.offset <= htab->splt->size);
+      BFD_ASSERT (htab->root.splt != NULL);
+      BFD_ASSERT (gotplt_index != MINUS_ONE);
+      BFD_ASSERT (plt_offset <= htab->root.splt->size);
 
       /* Calculate the address of the .plt entry.  */
-      plt_address = (htab->splt->output_section->vma
-                    + htab->splt->output_offset
-                    + h->plt.offset);
-
-      /* Calculate the index of the entry.  */
-      plt_index = ((h->plt.offset - htab->plt_header_size)
-                  / htab->plt_entry_size);
+      plt_address = (htab->root.splt->output_section->vma
+                    + htab->root.splt->output_offset
+                    + plt_offset);
 
       /* Calculate the address of the .got.plt entry.  */
-      got_address = (htab->sgotplt->output_section->vma
-                    + htab->sgotplt->output_offset
-                    + plt_index * 4);
+      got_address = (htab->root.sgotplt->output_section->vma
+                    + htab->root.sgotplt->output_offset
+                    + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd));
 
       /* Calculate the offset of the .got.plt entry from
         _GLOBAL_OFFSET_TABLE_.  */
@@ -10184,20 +11121,21 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
 
       /* Calculate the offset for the branch at the start of the PLT
         entry.  The branch jumps to the beginning of .plt.  */
-      branch_offset = -(h->plt.offset / 4 + 1) & 0xffff;
+      branch_offset = -(plt_offset / 4 + 1) & 0xffff;
 
       /* Fill in the initial value of the .got.plt entry.  */
       bfd_put_32 (output_bfd, plt_address,
-                 htab->sgotplt->contents + plt_index * 4);
+                 (htab->root.sgotplt->contents
+                  + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd)));
 
       /* Find out where the .plt entry should go.  */
-      loc = htab->splt->contents + h->plt.offset;
+      loc = htab->root.splt->contents + plt_offset;
 
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          plt_entry = mips_vxworks_shared_plt_entry;
          bfd_put_32 (output_bfd, plt_entry[0] | branch_offset, loc);
-         bfd_put_32 (output_bfd, plt_entry[1] | plt_index, loc + 4);
+         bfd_put_32 (output_bfd, plt_entry[1] | gotplt_index, loc + 4);
        }
       else
        {
@@ -10208,7 +11146,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
          got_address_low = got_address & 0xffff;
 
          bfd_put_32 (output_bfd, plt_entry[0] | branch_offset, loc);
-         bfd_put_32 (output_bfd, plt_entry[1] | plt_index, loc + 4);
+         bfd_put_32 (output_bfd, plt_entry[1] | gotplt_index, loc + 4);
          bfd_put_32 (output_bfd, plt_entry[2] | got_address_high, loc + 8);
          bfd_put_32 (output_bfd, plt_entry[3] | got_address_low, loc + 12);
          bfd_put_32 (output_bfd, plt_entry[4], loc + 16);
@@ -10217,12 +11155,12 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
          bfd_put_32 (output_bfd, plt_entry[7], loc + 28);
 
          loc = (htab->srelplt2->contents
-                + (plt_index * 3 + 2) * sizeof (Elf32_External_Rela));
+                + (gotplt_index * 3 + 2) * sizeof (Elf32_External_Rela));
 
          /* Emit a relocation for the .got.plt entry.  */
          rel.r_offset = got_address;
          rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_MIPS_32);
-         rel.r_addend = h->plt.offset;
+         rel.r_addend = plt_offset;
          bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
 
          /* Emit a relocation for the lui of %hi(<.got.plt slot>).  */
@@ -10240,7 +11178,8 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
        }
 
       /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry.  */
-      loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rela);
+      loc = (htab->root.srelplt->contents
+            + gotplt_index * sizeof (Elf32_External_Rela));
       rel.r_offset = got_address;
       rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_JUMP_SLOT);
       rel.r_addend = 0;
@@ -10252,7 +11191,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
 
   BFD_ASSERT (h->dynindx != -1 || h->forced_local);
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   g = htab->got_info;
   BFD_ASSERT (g != NULL);
 
@@ -10283,6 +11222,8 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
   if (h->needs_copy)
     {
       Elf_Internal_Rela rel;
+      asection *srel;
+      bfd_byte *loc;
 
       BFD_ASSERT (h->dynindx != -1);
 
@@ -10291,11 +11232,13 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
                      + h->root.u.def.value);
       rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_COPY);
       rel.r_addend = 0;
-      bfd_elf32_swap_reloca_out (output_bfd, &rel,
-                                htab->srelbss->contents
-                                + (htab->srelbss->reloc_count
-                                   * sizeof (Elf32_External_Rela)));
-      ++htab->srelbss->reloc_count;
+      if (h->root.u.def.section == htab->root.sdynrelro)
+       srel = htab->root.sreldynrelro;
+      else
+       srel = htab->root.srelbss;
+      loc = srel->contents + srel->reloc_count * sizeof (Elf32_External_Rela);
+      bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
+      ++srel->reloc_count;
     }
 
   /* If this is a mips16/microMIPS symbol, force the value to be even.  */
@@ -10307,7 +11250,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
 
 /* Write out a plt0 entry to the beginning of .plt.  */
 
-static void
+static bfd_boolean
 mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
 {
   bfd_byte *loc;
@@ -10322,30 +11265,95 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
     plt_entry = mips_n64_exec_plt0_entry;
   else if (ABI_N32_P (output_bfd))
     plt_entry = mips_n32_exec_plt0_entry;
-  else
+  else if (!htab->plt_header_is_comp)
     plt_entry = mips_o32_exec_plt0_entry;
+  else if (htab->insn32)
+    plt_entry = micromips_insn32_o32_exec_plt0_entry;
+  else
+    plt_entry = micromips_o32_exec_plt0_entry;
 
   /* Calculate the value of .got.plt.  */
-  gotplt_value = (htab->sgotplt->output_section->vma
-                 + htab->sgotplt->output_offset);
+  gotplt_value = (htab->root.sgotplt->output_section->vma
+                 + htab->root.sgotplt->output_offset);
   gotplt_value_high = ((gotplt_value + 0x8000) >> 16) & 0xffff;
   gotplt_value_low = gotplt_value & 0xffff;
 
   /* The PLT sequence is not safe for N64 if .got.plt's address can
      not be loaded in two instructions.  */
-  BFD_ASSERT ((gotplt_value & ~(bfd_vma) 0x7fffffff) == 0
-             || ~(gotplt_value | 0x7fffffff) == 0);
+  if (ABI_64_P (output_bfd)
+      && ((gotplt_value + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+    {
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: `%pA' start VMA of %#" PRIx64 " outside the 32-bit range "
+          "supported; consider using `-Ttext-segment=...'"),
+        output_bfd,
+        htab->root.sgotplt->output_section,
+        (int64_t) gotplt_value);
+      bfd_set_error (bfd_error_no_error);
+      return FALSE;
+    }
 
   /* Install the PLT header.  */
-  loc = htab->splt->contents;
-  bfd_put_32 (output_bfd, plt_entry[0] | gotplt_value_high, loc);
-  bfd_put_32 (output_bfd, plt_entry[1] | gotplt_value_low, loc + 4);
-  bfd_put_32 (output_bfd, plt_entry[2] | gotplt_value_low, loc + 8);
-  bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
-  bfd_put_32 (output_bfd, plt_entry[4], loc + 16);
-  bfd_put_32 (output_bfd, plt_entry[5], loc + 20);
-  bfd_put_32 (output_bfd, plt_entry[6], loc + 24);
-  bfd_put_32 (output_bfd, plt_entry[7], loc + 28);
+  loc = htab->root.splt->contents;
+  if (plt_entry == micromips_o32_exec_plt0_entry)
+    {
+      bfd_vma gotpc_offset;
+      bfd_vma loc_address;
+      size_t i;
+
+      BFD_ASSERT (gotplt_value % 4 == 0);
+
+      loc_address = (htab->root.splt->output_section->vma
+                    + htab->root.splt->output_offset);
+      gotpc_offset = gotplt_value - ((loc_address | 3) ^ 3);
+
+      /* ADDIUPC has a span of +/-16MB, check we're in range.  */
+      if (gotpc_offset + 0x1000000 >= 0x2000000)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: `%pA' offset of %" PRId64 " from `%pA' "
+              "beyond the range of ADDIUPC"),
+            output_bfd,
+            htab->root.sgotplt->output_section,
+            (int64_t) gotpc_offset,
+            htab->root.splt->output_section);
+         bfd_set_error (bfd_error_no_error);
+         return FALSE;
+       }
+      bfd_put_16 (output_bfd,
+                 plt_entry[0] | ((gotpc_offset >> 18) & 0x7f), loc);
+      bfd_put_16 (output_bfd, (gotpc_offset >> 2) & 0xffff, loc + 2);
+      for (i = 2; i < ARRAY_SIZE (micromips_o32_exec_plt0_entry); i++)
+       bfd_put_16 (output_bfd, plt_entry[i], loc + (i * 2));
+    }
+  else if (plt_entry == micromips_insn32_o32_exec_plt0_entry)
+    {
+      size_t i;
+
+      bfd_put_16 (output_bfd, plt_entry[0], loc);
+      bfd_put_16 (output_bfd, gotplt_value_high, loc + 2);
+      bfd_put_16 (output_bfd, plt_entry[2], loc + 4);
+      bfd_put_16 (output_bfd, gotplt_value_low, loc + 6);
+      bfd_put_16 (output_bfd, plt_entry[4], loc + 8);
+      bfd_put_16 (output_bfd, gotplt_value_low, loc + 10);
+      for (i = 6; i < ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry); i++)
+       bfd_put_16 (output_bfd, plt_entry[i], loc + (i * 2));
+    }
+  else
+    {
+      bfd_put_32 (output_bfd, plt_entry[0] | gotplt_value_high, loc);
+      bfd_put_32 (output_bfd, plt_entry[1] | gotplt_value_low, loc + 4);
+      bfd_put_32 (output_bfd, plt_entry[2] | gotplt_value_low, loc + 8);
+      bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
+      bfd_put_32 (output_bfd, plt_entry[4], loc + 16);
+      bfd_put_32 (output_bfd, plt_entry[5], loc + 20);
+      bfd_put_32 (output_bfd, plt_entry[6], loc + 24);
+      bfd_put_32 (output_bfd, plt_entry[7], loc + 28);
+    }
+
+  return TRUE;
 }
 
 /* Install the PLT header for a VxWorks executable and finalize the
@@ -10374,10 +11382,11 @@ mips_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
   got_value_low = got_value & 0xffff;
 
   /* Calculate the address of the PLT header.  */
-  plt_address = htab->splt->output_section->vma + htab->splt->output_offset;
+  plt_address = (htab->root.splt->output_section->vma
+                + htab->root.splt->output_offset);
 
   /* Install the PLT header.  */
-  loc = htab->splt->contents;
+  loc = htab->root.splt->contents;
   bfd_put_32 (output_bfd, plt_entry[0] | got_value_high, loc);
   bfd_put_32 (output_bfd, plt_entry[1] | got_value_low, loc + 4);
   bfd_put_32 (output_bfd, plt_entry[2], loc + 8);
@@ -10438,7 +11447,7 @@ mips_vxworks_finish_shared_plt (bfd *output_bfd, struct bfd_link_info *info)
   /* We just need to copy the entry byte-by-byte.  */
   for (i = 0; i < ARRAY_SIZE (mips_vxworks_shared_plt0_entry); i++)
     bfd_put_32 (output_bfd, mips_vxworks_shared_plt0_entry[i],
-               htab->splt->contents + i * 4);
+               htab->root.splt->contents + i * 4);
 }
 
 /* Finish up the dynamic sections.  */
@@ -10460,7 +11469,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 
   sdyn = bfd_get_linker_section (dynobj, ".dynamic");
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   gg = htab->got_info;
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -10508,12 +11517,12 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              break;
 
            case DT_PLTGOT:
-             s = htab->sgot;
+             s = htab->root.sgot;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_MIPS_PLTGOT:
-             s = htab->sgotplt;
+             s = htab->root.sgotplt;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
@@ -10568,15 +11577,18 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                }
              /* In case if we don't have global got symbols we default
                 to setting DT_MIPS_GOTSYM to the same value as
-                DT_MIPS_SYMTABNO, so we just fall through.  */
+                DT_MIPS_SYMTABNO.  */
+             /* Fall through.  */
 
            case DT_MIPS_SYMTABNO:
              name = ".dynsym";
              elemsize = MIPS_ELF_SYM_SIZE (output_bfd);
-             s = bfd_get_section_by_name (output_bfd, name);
-             BFD_ASSERT (s != NULL);
+             s = bfd_get_linker_section (dynobj, name);
 
-             dyn.d_un.d_val = s->size / elemsize;
+             if (s != NULL)
+               dyn.d_un.d_val = s->size / elemsize;
+             else
+               dyn.d_un.d_val = 0;
              break;
 
            case DT_MIPS_HIPAGENO:
@@ -10594,24 +11606,43 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                    break;
                  }
                s = h->root.u.def.section;
+
+               /* The MIPS_RLD_MAP tag stores the absolute address of the
+                  debug pointer.  */
                dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset
                                  + h->root.u.def.value);
              }
              break;
 
+           case DT_MIPS_RLD_MAP_REL:
+             {
+               struct elf_link_hash_entry *h;
+               bfd_vma dt_addr, rld_addr;
+               h = mips_elf_hash_table (info)->rld_symbol;
+               if (!h)
+                 {
+                   dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
+                   swap_out_p = FALSE;
+                   break;
+                 }
+               s = h->root.u.def.section;
+
+               /* The MIPS_RLD_MAP_REL tag stores the offset to the debug
+                  pointer, relative to the address of the tag.  */
+               dt_addr = (sdyn->output_section->vma + sdyn->output_offset
+                          + (b - sdyn->contents));
+               rld_addr = (s->output_section->vma + s->output_offset
+                           + h->root.u.def.value);
+               dyn.d_un.d_ptr = rld_addr - dt_addr;
+             }
+             break;
+
            case DT_MIPS_OPTIONS:
              s = (bfd_get_section_by_name
                   (output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (output_bfd)));
              dyn.d_un.d_ptr = s->vma;
              break;
 
-           case DT_RELASZ:
-             BFD_ASSERT (htab->is_vxworks);
-             /* The count does not include the JUMP_SLOT relocations.  */
-             if (htab->srelplt)
-               dyn.d_un.d_val -= htab->srelplt->size;
-             break;
-
            case DT_PLTREL:
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
              if (htab->is_vxworks)
@@ -10622,13 +11653,13 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 
            case DT_PLTRELSZ:
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
-             dyn.d_un.d_val = htab->srelplt->size;
+             dyn.d_un.d_val = htab->root.srelplt->size;
              break;
 
            case DT_JMPREL:
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
-             dyn.d_un.d_ptr = (htab->srelplt->output_section->vma
-                               + htab->srelplt->output_offset);
+             dyn.d_un.d_ptr = (htab->root.srelplt->output_section->vma
+                               + htab->root.srelplt->output_offset);
              break;
 
            case DT_TEXTREL:
@@ -10727,13 +11758,17 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                             sgot->contents
                             + got_index++ * MIPS_ELF_GOT_SIZE (output_bfd));
 
-         if (! info->shared)
+         if (! bfd_link_pic (info))
            continue;
 
-         while (got_index < g->assigned_gotno)
+         for (; got_index < g->local_gotno; got_index++)
            {
+             if (got_index >= g->assigned_low_gotno
+                 && got_index <= g->assigned_high_gotno)
+               continue;
+
              rel[0].r_offset = rel[1].r_offset = rel[2].r_offset
-               = got_index++ * MIPS_ELF_GOT_SIZE (output_bfd);
+               = got_index * MIPS_ELF_GOT_SIZE (output_bfd);
              if (!(mips_elf_create_dynamic_relocation
                    (output_bfd, info, rel, NULL,
                     bfd_abs_section_ptr,
@@ -10782,6 +11817,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                                   : sizeof (Elf32_External_Rel)));
              /* Adjust the section size too.  Tools like the prelinker
                 can reasonably expect the values to the same.  */
+             BFD_ASSERT (!bfd_is_abs_section (s->output_section));
              elf_section_data (s->output_section)->this_hdr.sh_size
                = dyn.d_un.d_val;
              break;
@@ -10855,19 +11891,20 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
       }
   }
 
-  if (htab->splt && htab->splt->size > 0)
+  if (htab->root.splt && htab->root.splt->size > 0)
     {
       if (htab->is_vxworks)
        {
-         if (info->shared)
+         if (bfd_link_pic (info))
            mips_vxworks_finish_shared_plt (output_bfd, info);
          else
            mips_vxworks_finish_exec_plt (output_bfd, info);
        }
       else
        {
-         BFD_ASSERT (!info->shared);
-         mips_finish_exec_plt (output_bfd, info);
+         BFD_ASSERT (!bfd_link_pic (info));
+         if (!mips_finish_exec_plt (output_bfd, info))
+           return FALSE;
        }
     }
   return TRUE;
@@ -10896,6 +11933,10 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_2;
       break;
 
+    case bfd_mach_mips4010:
+      val = E_MIPS_ARCH_2 | E_MIPS_MACH_4010;
+      break;
+
     case bfd_mach_mips4000:
     case bfd_mach_mips4300:
     case bfd_mach_mips4400:
@@ -10903,10 +11944,6 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_3;
       break;
 
-    case bfd_mach_mips4010:
-      val = E_MIPS_ARCH_3 | E_MIPS_MACH_4010;
-      break;
-
     case bfd_mach_mips4100:
       val = E_MIPS_ARCH_3 | E_MIPS_MACH_4100;
       break;
@@ -10965,8 +12002,16 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
       break;
 
-    case bfd_mach_mips_loongson_3a:
-      val = E_MIPS_ARCH_64 | E_MIPS_MACH_LS3A;
+    case bfd_mach_mips_gs464:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464;
+      break;
+
+    case bfd_mach_mips_gs464e:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464E;
+      break;
+
+    case bfd_mach_mips_gs264e:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS264E;
       break;
 
     case bfd_mach_mips_octeon:
@@ -10974,6 +12019,10 @@ mips_set_isa_flags (bfd *abfd)
       val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON;
       break;
 
+    case bfd_mach_mips_octeon3:
+      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON3;
+      break;
+
     case bfd_mach_mips_xlr:
       val = E_MIPS_ARCH_64 | E_MIPS_MACH_XLR;
       break;
@@ -10991,12 +12040,28 @@ mips_set_isa_flags (bfd *abfd)
       break;
 
     case bfd_mach_mipsisa32r2:
+    case bfd_mach_mipsisa32r3:
+    case bfd_mach_mipsisa32r5:
       val = E_MIPS_ARCH_32R2;
       break;
 
+    case bfd_mach_mips_interaptiv_mr2:
+      val = E_MIPS_ARCH_32R2 | E_MIPS_MACH_IAMR2;
+      break;
+
     case bfd_mach_mipsisa64r2:
+    case bfd_mach_mipsisa64r3:
+    case bfd_mach_mipsisa64r5:
       val = E_MIPS_ARCH_64R2;
       break;
+
+    case bfd_mach_mipsisa32r6:
+      val = E_MIPS_ARCH_32R6;
+      break;
+
+    case bfd_mach_mipsisa64r6:
+      val = E_MIPS_ARCH_64R6;
+      break;
     }
   elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
   elf_elfheader (abfd)->e_flags |= val;
@@ -11004,6 +12069,18 @@ mips_set_isa_flags (bfd *abfd)
 }
 
 
+/* Whether to sort relocs output by ld -r or ld --emit-relocs, by r_offset.
+   Don't do so for code sections.  We want to keep ordering of HI16/LO16
+   as is.  On the other hand, elf-eh-frame.c processing requires .eh_frame
+   relocs to be sorted.  */
+
+bfd_boolean
+_bfd_mips_elf_sort_relocs_p (asection *sec)
+{
+  return (sec->flags & SEC_CODE) == 0;
+}
+
+
 /* The final processing done just before writing out a MIPS ELF object
    file.  This gets the MIPS architecture right based on the machine
    number.  This is used by both the 32-bit and the 64-bit ABI.  */
@@ -11105,6 +12182,10 @@ _bfd_mips_elf_additional_program_headers (bfd *abfd,
   if (s && (s->flags & SEC_LOAD))
     ++ret;
 
+  /* See if we need a PT_MIPS_ABIFLAGS segment.  */
+  if (bfd_get_section_by_name (abfd, ".MIPS.abiflags"))
+    ++ret;
+
   /* See if we need a PT_MIPS_OPTIONS segment.  */
   if (IRIX_COMPAT (abfd) == ict_irix6
       && bfd_get_section_by_name (abfd,
@@ -11141,7 +12222,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
   s = bfd_get_section_by_name (abfd, ".reginfo");
   if (s != NULL && (s->flags & SEC_LOAD) != 0)
     {
-      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+      for (m = elf_seg_map (abfd); m != NULL; m = m->next)
        if (m->p_type == PT_MIPS_REGINFO)
          break;
       if (m == NULL)
@@ -11156,7 +12237,38 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
          m->sections[0] = s;
 
          /* We want to put it after the PHDR and INTERP segments.  */
-         pm = &elf_tdata (abfd)->segment_map;
+         pm = &elf_seg_map (abfd);
+         while (*pm != NULL
+                && ((*pm)->p_type == PT_PHDR
+                    || (*pm)->p_type == PT_INTERP))
+           pm = &(*pm)->next;
+
+         m->next = *pm;
+         *pm = m;
+       }
+    }
+
+  /* If there is a .MIPS.abiflags section, we need a PT_MIPS_ABIFLAGS
+     segment.  */
+  s = bfd_get_section_by_name (abfd, ".MIPS.abiflags");
+  if (s != NULL && (s->flags & SEC_LOAD) != 0)
+    {
+      for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+       if (m->p_type == PT_MIPS_ABIFLAGS)
+         break;
+      if (m == NULL)
+       {
+         amt = sizeof *m;
+         m = bfd_zalloc (abfd, amt);
+         if (m == NULL)
+           return FALSE;
+
+         m->p_type = PT_MIPS_ABIFLAGS;
+         m->count = 1;
+         m->sections[0] = s;
+
+         /* We want to put it after the PHDR and INTERP segments.  */
+         pm = &elf_seg_map (abfd);
          while (*pm != NULL
                 && ((*pm)->p_type == PT_PHDR
                     || (*pm)->p_type == PT_INTERP))
@@ -11186,7 +12298,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
        {
          struct elf_segment_map *options_segment;
 
-         pm = &elf_tdata (abfd)->segment_map;
+         pm = &elf_seg_map (abfd);
          while (*pm != NULL
                 && ((*pm)->p_type == PT_PHDR
                     || (*pm)->p_type == PT_INTERP))
@@ -11216,7 +12328,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
              && bfd_get_section_by_name (abfd, ".dynamic") != NULL
              && bfd_get_section_by_name (abfd, ".mdebug") != NULL)
            {
-             for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+             for (m = elf_seg_map (abfd); m != NULL; m = m->next)
                if (m->p_type == PT_MIPS_RTPROC)
                  break;
              if (m == NULL)
@@ -11242,7 +12354,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
                    }
 
                  /* We want to put it after the DYNAMIC segment.  */
-                 pm = &elf_tdata (abfd)->segment_map;
+                 pm = &elf_seg_map (abfd);
                  while (*pm != NULL && (*pm)->p_type != PT_DYNAMIC)
                    pm = &(*pm)->next;
                  if (*pm != NULL)
@@ -11256,23 +12368,11 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
       /* On IRIX5, the PT_DYNAMIC segment includes the .dynamic,
         .dynstr, .dynsym, and .hash sections, and everything in
         between.  */
-      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL;
+      for (pm = &elf_seg_map (abfd); *pm != NULL;
           pm = &(*pm)->next)
        if ((*pm)->p_type == PT_DYNAMIC)
          break;
       m = *pm;
-      if (m != NULL && IRIX_COMPAT (abfd) == ict_none)
-       {
-         /* For a normal mips executable the permissions for the PT_DYNAMIC
-            segment are read, write and execute. We do that here since
-            the code in elf.c sets only the read permission. This matters
-            sometimes for the dynamic linker.  */
-         if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
-           {
-             m->p_flags = PF_R | PF_W | PF_X;
-             m->p_flags_valid = 1;
-           }
-       }
       /* GNU/Linux binaries do not need the extended PT_DYNAMIC section.
         glibc's dynamic linker has traditionally derived the number of
         tags from the p_filesz field, and sometimes allocates stack
@@ -11363,7 +12463,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
       && !SGI_COMPAT (abfd)
       && bfd_get_section_by_name (abfd, ".dynamic"))
     {
-      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next)
+      for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next)
        if ((*pm)->p_type == PT_NULL)
          break;
       if (*pm == NULL)
@@ -11403,62 +12503,32 @@ _bfd_mips_elf_gc_mark_hook (asection *sec,
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
 
-/* Update the got entry reference counts for the section being removed.  */
+/* Prevent .MIPS.abiflags from being discarded with --gc-sections.  */
 
 bfd_boolean
-_bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
-                            struct bfd_link_info *info ATTRIBUTE_UNUSED,
-                            asection *sec ATTRIBUTE_UNUSED,
-                            const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
+_bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info,
+                                     elf_gc_mark_hook_fn gc_mark_hook)
 {
-#if 0
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  const Elf_Internal_Rela *rel, *relend;
-  unsigned long r_symndx;
-  struct elf_link_hash_entry *h;
+  bfd *sub;
 
-  if (info->relocatable)
-    return TRUE;
+  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
+    {
+      asection *o;
 
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
-    switch (ELF_R_TYPE (abfd, rel->r_info))
-      {
-      case R_MIPS16_GOT16:
-      case R_MIPS16_CALL16:
-      case R_MIPS_GOT16:
-      case R_MIPS_CALL16:
-      case R_MIPS_CALL_HI16:
-      case R_MIPS_CALL_LO16:
-      case R_MIPS_GOT_HI16:
-      case R_MIPS_GOT_LO16:
-      case R_MIPS_GOT_DISP:
-      case R_MIPS_GOT_PAGE:
-      case R_MIPS_GOT_OFST:
-      case R_MICROMIPS_GOT16:
-      case R_MICROMIPS_CALL16:
-      case R_MICROMIPS_CALL_HI16:
-      case R_MICROMIPS_CALL_LO16:
-      case R_MICROMIPS_GOT_HI16:
-      case R_MICROMIPS_GOT_LO16:
-      case R_MICROMIPS_GOT_DISP:
-      case R_MICROMIPS_GOT_PAGE:
-      case R_MICROMIPS_GOT_OFST:
-       /* ??? It would seem that the existing MIPS code does no sort
-          of reference counting or whatnot on its GOT and PLT entries,
-          so it is not possible to garbage collect them at this time.  */
-       break;
+      if (! is_mips_elf (sub))
+       continue;
 
-      default:
-       break;
-      }
-#endif
+      for (o = sub->sections; o != NULL; o = o->next)
+       if (!o->gc_mark
+           && MIPS_ELF_ABIFLAGS_SECTION_NAME_P
+                (bfd_get_section_name (sub, o)))
+         {
+           if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+             return FALSE;
+         }
+    }
 
   return TRUE;
 }
@@ -11569,6 +12639,8 @@ _bfd_mips_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
   if (skip != 0)
     {
       mips_elf_section_data (o)->u.tdata = tdata;
+      if (o->rawsize == 0)
+       o->rawsize = o->size;
       o->size -= skip * PDR_SIZE;
       ret = TRUE;
     }
@@ -11592,7 +12664,7 @@ _bfd_mips_elf_ignore_discarded_relocs (asection *sec)
 bfd_boolean
 _bfd_mips_elf_write_section (bfd *output_bfd,
                             struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
-                             asection *sec, bfd_byte *contents)
+                            asection *sec, bfd_byte *contents)
 {
   bfd_byte *to, *from, *end;
   int i;
@@ -11639,25 +12711,43 @@ struct mips_elf_find_line
 };
 
 bfd_boolean
-_bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
-                                asymbol **symbols, bfd_vma offset,
+_bfd_mips_elf_find_nearest_line (bfd *abfd, asymbol **symbols,
+                                asection *section, bfd_vma offset,
                                 const char **filename_ptr,
                                 const char **functionname_ptr,
-                                unsigned int *line_ptr)
+                                unsigned int *line_ptr,
+                                unsigned int *discriminator_ptr)
 {
   asection *msec;
 
-  if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset,
+  if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr))
-    return TRUE;
+                                    line_ptr, discriminator_ptr,
+                                    dwarf_debug_sections,
+                                    ABI_64_P (abfd) ? 8 : 0,
+                                    &elf_tdata (abfd)->dwarf2_find_line_info)
+      || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+                                       filename_ptr, functionname_ptr,
+                                       line_ptr))
+    {
+      /* PR 22789: If the function name or filename was not found through
+        the debug information, then try an ordinary lookup instead.  */
+      if ((functionname_ptr != NULL && *functionname_ptr == NULL)
+         || (filename_ptr != NULL && *filename_ptr == NULL))
+       {
+         /* Do not override already discovered names.  */
+         if (functionname_ptr != NULL && *functionname_ptr != NULL)
+           functionname_ptr = NULL;
 
-  if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
-                                     section, symbols, offset,
-                                    filename_ptr, functionname_ptr,
-                                    line_ptr, NULL, ABI_64_P (abfd) ? 8 : 0,
-                                    &elf_tdata (abfd)->dwarf2_find_line_info))
-    return TRUE;
+         if (filename_ptr != NULL && *filename_ptr != NULL)
+           filename_ptr = NULL;
+
+         _bfd_elf_find_function (abfd, symbols, section, offset,
+                                 filename_ptr, functionname_ptr);
+       }
+
+      return TRUE;
+    }
 
   msec = bfd_get_section_by_name (abfd, ".mdebug");
   if (msec != NULL)
@@ -11715,11 +12805,11 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
          mips_elf_tdata (abfd)->find_line_info = fi;
 
          /* Note that we don't bother to ever free this information.
-             find_nearest_line is either called all the time, as in
-             objdump -l, so the information should be saved, or it is
-             rarely called, as in ld error messages, so the memory
-             wasted is unimportant.  Still, it would probably be a
-             good idea for free_cached_info to throw it away.  */
+            find_nearest_line is either called all the time, as in
+            objdump -l, so the information should be saved, or it is
+            rarely called, as in ld error messages, so the memory
+            wasted is unimportant.  Still, it would probably be a
+            good idea for free_cached_info to throw it away.  */
        }
 
       if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap,
@@ -11735,9 +12825,9 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section,
 
   /* Fall back on the generic ELF find_nearest_line routine.  */
 
-  return _bfd_elf_find_nearest_line (abfd, section, symbols, offset,
+  return _bfd_elf_find_nearest_line (abfd, symbols, section, offset,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr);
+                                    line_ptr, discriminator_ptr);
 }
 
 bfd_boolean
@@ -11916,25 +13006,22 @@ _bfd_elf_mips_get_relocated_section_contents
              switch (r)
                {
                case bfd_reloc_undefined:
-                 if (!((*link_info->callbacks->undefined_symbol)
-                       (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
-                        input_bfd, input_section, (*parent)->address, TRUE)))
-                   goto error_return;
+                 (*link_info->callbacks->undefined_symbol)
+                   (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                    input_bfd, input_section, (*parent)->address, TRUE);
                  break;
                case bfd_reloc_dangerous:
                  BFD_ASSERT (error_message != NULL);
-                 if (!((*link_info->callbacks->reloc_dangerous)
-                       (link_info, error_message, input_bfd, input_section,
-                        (*parent)->address)))
-                   goto error_return;
+                 (*link_info->callbacks->reloc_dangerous)
+                   (link_info, error_message,
+                    input_bfd, input_section, (*parent)->address);
                  break;
                case bfd_reloc_overflow:
-                 if (!((*link_info->callbacks->reloc_overflow)
-                       (link_info, NULL,
-                        bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
-                        (*parent)->howto->name, (*parent)->addend,
-                        input_bfd, input_section, (*parent)->address)))
-                   goto error_return;
+                 (*link_info->callbacks->reloc_overflow)
+                   (link_info, NULL,
+                    bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                    (*parent)->howto->name, (*parent)->addend,
+                    input_bfd, input_section, (*parent)->address);
                  break;
                case bfd_reloc_outofrange:
                default:
@@ -12110,9 +13197,8 @@ static const struct opcode_descriptor bz_insns_16[] = {
 
 /* Switch between a 5-bit register index and its 3-bit shorthand.  */
 
-#define BZ16_REG(opcode) ((((((opcode) >> 7) & 7) + 0x1e) & 0x17) + 2)
-#define BZ16_REG_FIELD(r) \
-  (((2 <= (r) && (r) <= 7) ? (r) : ((r) - 16)) << 7)
+#define BZ16_REG(opcode) ((((((opcode) >> 7) & 7) + 0x1e) & 0xf) + 2)
+#define BZ16_REG_FIELD(r) (((r) & 7) << 7)
 
 
 /* 32-bit instructions with a delay slot.  */
@@ -12211,8 +13297,8 @@ static const struct opcode_descriptor addiupc_insn =
 #define MOVE16_RS_FIELD(r) (((r) & 0x1f)     )
 
 static const struct opcode_descriptor move_insns_32[] = {
-  { /* "move", "d,s",          */ 0x00000150, 0xffe007ff }, /* addu d,s,$0 */
   { /* "move", "d,s",          */ 0x00000290, 0xffe007ff }, /* or   d,s,$0 */
+  { /* "move", "d,s",          */ 0x00000150, 0xffe007ff }, /* addu d,s,$0 */
   { 0, 0 }  /* End marker for find_match().  */
 };
 
@@ -12385,6 +13471,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
                             struct bfd_link_info *link_info,
                             bfd_boolean *again)
 {
+  bfd_boolean insn32 = mips_elf_hash_table (link_info)->insn32;
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *internal_relocs;
   Elf_Internal_Rela *irel, *irelend;
@@ -12398,7 +13485,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
      this section does not have relocs, or if this is not a
      code section.  */
 
-  if (link_info->relocatable
+  if (bfd_link_relocatable (link_info)
       || (sec->flags & SEC_RELOC) == 0
       || sec->reloc_count == 0
       || (sec->flags & SEC_CODE) == 0)
@@ -12427,12 +13514,12 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
       int fndopc;
 
       /* The number of bytes to delete for relaxation and from where
-         to delete these bytes starting at irel->r_offset.  */
+        to delete these bytes starting at irel->r_offset.  */
       int delcnt = 0;
       int deloff = 0;
 
       /* If this isn't something that can be relaxed, then ignore
-         this reloc.  */
+        this reloc.  */
       if (r_type != R_MICROMIPS_HI16
          && r_type != R_MICROMIPS_PC16_S1
          && r_type != R_MICROMIPS_26_S1)
@@ -12509,12 +13596,12 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
 
 
       /* For simplicity of coding, we are going to modify the
-         section contents, the section relocs, and the BFD symbol
-         table.  We must tell the rest of the code not to free up this
-         information.  It would be possible to instead create a table
-         of changes which have to be made, as is done in coff-mips.c;
-         that would be more work, but would require less memory when
-         the linker is run.  */
+        section contents, the section relocs, and the BFD symbol
+        table.  We must tell the rest of the code not to free up this
+        information.  It would be possible to instead create a table
+        of changes which have to be made, as is done in coff-mips.c;
+        that would be more work, but would require less memory when
+        the linker is run.  */
 
       /* Only 32-bit instructions relaxed.  */
       if (irel->r_offset + 4 > sec->size)
@@ -12523,20 +13610,20 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
       opcode = bfd_get_micromips_32 (abfd, ptr);
 
       /* This is the pc-relative distance from the instruction the
-         relocation is applied to, to the symbol referred.  */
+        relocation is applied to, to the symbol referred.  */
       pcrval = (symval
                - (sec->output_section->vma + sec->output_offset)
                - irel->r_offset);
 
       /* R_MICROMIPS_HI16 / LUI relaxation to nil, performing relaxation
-         of corresponding R_MICROMIPS_LO16 to R_MICROMIPS_HI0_LO16 or
-         R_MICROMIPS_PC23_S2.  The R_MICROMIPS_PC23_S2 condition is
+        of corresponding R_MICROMIPS_LO16 to R_MICROMIPS_HI0_LO16 or
+        R_MICROMIPS_PC23_S2.  The R_MICROMIPS_PC23_S2 condition is
 
-           (symval % 4 == 0 && IS_BITSIZE (pcrval, 25))
+          (symval % 4 == 0 && IS_BITSIZE (pcrval, 25))
 
-         where pcrval has first to be adjusted to apply against the LO16
-         location (we make the adjustment later on, when we have figured
-         out the offset).  */
+        where pcrval has first to be adjusted to apply against the LO16
+        location (we make the adjustment later on, when we have figured
+        out the offset).  */
       if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
        {
          bfd_boolean bzc = FALSE;
@@ -12620,8 +13707,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
              irel[1].r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_HI0_LO16);
 
              /* Instructions using R_MICROMIPS_LO16 have the base or
-                source register in bits 20:16.  This register becomes $0
-                (zero) as the result of the R_MICROMIPS_HI16 being 0.  */
+                source register in bits 20:16.  This register becomes $0
+                (zero) as the result of the R_MICROMIPS_HI16 being 0.  */
              nextopc &= ~0x001f0000;
              bfd_put_16 (abfd, (nextopc >> 16) & 0xffff,
                          contents + irel[1].r_offset);
@@ -12660,14 +13747,20 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
        }
 
       /* Compact branch relaxation -- due to the multitude of macros
-         employed by the compiler/assembler, compact branches are not
-         always generated.  Obviously, this can/will be fixed elsewhere,
-         but there is no drawback in double checking it here.  */
+        employed by the compiler/assembler, compact branches are not
+        always generated.  Obviously, this can/will be fixed elsewhere,
+        but there is no drawback in double checking it here.  */
       else if (r_type == R_MICROMIPS_PC16_S1
               && irel->r_offset + 5 < sec->size
               && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
                   || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
-              && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
+              && ((!insn32
+                   && (delcnt = MATCH (bfd_get_16 (abfd, ptr + 4),
+                                       nop_insn_16) ? 2 : 0))
+                  || (irel->r_offset + 7 < sec->size
+                      && (delcnt = MATCH (bfd_get_micromips_32 (abfd,
+                                                                ptr + 4),
+                                          nop_insn_32) ? 4 : 0))))
        {
          unsigned long reg;
 
@@ -12680,15 +13773,15 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
 
          bfd_put_micromips_32 (abfd, opcode, ptr);
 
-         /* Delete the 16-bit delay slot NOP: two bytes from
-            irel->offset + 4.  */
-         delcnt = 2;
+         /* Delete the delay slot NOP: two or four bytes from
+            irel->offset + 4; delcnt has already been set above.  */
          deloff = 4;
        }
 
       /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC10_S1.  We need
-         to check the distance from the next instruction, so subtract 2.  */
-      else if (r_type == R_MICROMIPS_PC16_S1
+        to check the distance from the next instruction, so subtract 2.  */
+      else if (!insn32
+              && r_type == R_MICROMIPS_PC16_S1
               && IS_BITSIZE (pcrval - 2, 11)
               && find_match (opcode, b_insns_32) >= 0)
        {
@@ -12707,8 +13800,9 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
        }
 
       /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC7_S1.  We need
-         to check the distance from the next instruction, so subtract 2.  */
-      else if (r_type == R_MICROMIPS_PC16_S1
+        to check the distance from the next instruction, so subtract 2.  */
+      else if (!insn32
+              && r_type == R_MICROMIPS_PC16_S1
               && IS_BITSIZE (pcrval - 2, 8)
               && (((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
                    && OP16_VALID_REG (OP32_SREG (opcode)))
@@ -12735,7 +13829,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
        }
 
       /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets.  */
-      else if (r_type == R_MICROMIPS_26_S1
+      else if (!insn32
+              && r_type == R_MICROMIPS_26_S1
               && target_is_micromips_code_p
               && irel->r_offset + 7 < sec->size
               && MATCH (opcode, jal_insn_32_bd32))
@@ -12769,7 +13864,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
          if (relaxed)
            {
              /* JAL with 32-bit delay slot that is changed to a JALS
-                with 16-bit delay slot.  */
+                with 16-bit delay slot.  */
              bfd_put_micromips_32 (abfd, jal_insn_32_bd16.match, ptr);
 
              /* Delete 2 bytes from irel->r_offset + 6.  */
@@ -12860,6 +13955,8 @@ _bfd_mips_elf_link_hash_table_create (bfd *abfd)
       free (ret);
       return NULL;
     }
+  ret->root.init_plt_refcount.plist = NULL;
+  ret->root.init_plt_offset.plist = NULL;
 
   return &ret->root.root;
 }
@@ -12891,7 +13988,298 @@ _bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
 {
   mips_elf_hash_table (info)->use_plts_and_copy_relocs = TRUE;
 }
+
+/* A function that the linker calls to select between all or only
+   32-bit microMIPS instructions, and between making or ignoring
+   branch relocation checks for invalid transitions between ISA modes.  */
+
+void
+_bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
+                           bfd_boolean ignore_branch_isa)
+{
+  mips_elf_hash_table (info)->insn32 = insn32;
+  mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
+}
 \f
+/* Structure for saying that BFD machine EXTENSION extends BASE.  */
+
+struct mips_mach_extension
+{
+  unsigned long extension, base;
+};
+
+
+/* An array describing how BFD machines relate to one another.  The entries
+   are ordered topologically with MIPS I extensions listed last.  */
+
+static const struct mips_mach_extension mips_mach_extensions[] =
+{
+  /* MIPS64r2 extensions.  */
+  { bfd_mach_mips_octeon3, bfd_mach_mips_octeon2 },
+  { bfd_mach_mips_octeon2, bfd_mach_mips_octeonp },
+  { bfd_mach_mips_octeonp, bfd_mach_mips_octeon },
+  { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
+  { bfd_mach_mips_gs264e, bfd_mach_mips_gs464e },
+  { bfd_mach_mips_gs464e, bfd_mach_mips_gs464 },
+  { bfd_mach_mips_gs464, bfd_mach_mipsisa64r2 },
+
+  /* MIPS64 extensions.  */
+  { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
+  { bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
+  { bfd_mach_mips_xlr, bfd_mach_mipsisa64 },
+
+  /* MIPS V extensions.  */
+  { bfd_mach_mipsisa64, bfd_mach_mips5 },
+
+  /* R10000 extensions.  */
+  { bfd_mach_mips12000, bfd_mach_mips10000 },
+  { bfd_mach_mips14000, bfd_mach_mips10000 },
+  { bfd_mach_mips16000, bfd_mach_mips10000 },
+
+  /* R5000 extensions.  Note: the vr5500 ISA is an extension of the core
+     vr5400 ISA, but doesn't include the multimedia stuff.  It seems
+     better to allow vr5400 and vr5500 code to be merged anyway, since
+     many libraries will just use the core ISA.  Perhaps we could add
+     some sort of ASE flag if this ever proves a problem.  */
+  { bfd_mach_mips5500, bfd_mach_mips5400 },
+  { bfd_mach_mips5400, bfd_mach_mips5000 },
+
+  /* MIPS IV extensions.  */
+  { bfd_mach_mips5, bfd_mach_mips8000 },
+  { bfd_mach_mips10000, bfd_mach_mips8000 },
+  { bfd_mach_mips5000, bfd_mach_mips8000 },
+  { bfd_mach_mips7000, bfd_mach_mips8000 },
+  { bfd_mach_mips9000, bfd_mach_mips8000 },
+
+  /* VR4100 extensions.  */
+  { bfd_mach_mips4120, bfd_mach_mips4100 },
+  { bfd_mach_mips4111, bfd_mach_mips4100 },
+
+  /* MIPS III extensions.  */
+  { bfd_mach_mips_loongson_2e, bfd_mach_mips4000 },
+  { bfd_mach_mips_loongson_2f, bfd_mach_mips4000 },
+  { bfd_mach_mips8000, bfd_mach_mips4000 },
+  { bfd_mach_mips4650, bfd_mach_mips4000 },
+  { bfd_mach_mips4600, bfd_mach_mips4000 },
+  { bfd_mach_mips4400, bfd_mach_mips4000 },
+  { bfd_mach_mips4300, bfd_mach_mips4000 },
+  { bfd_mach_mips4100, bfd_mach_mips4000 },
+  { bfd_mach_mips5900, bfd_mach_mips4000 },
+
+  /* MIPS32r3 extensions.  */
+  { bfd_mach_mips_interaptiv_mr2, bfd_mach_mipsisa32r3 },
+
+  /* MIPS32r2 extensions.  */
+  { bfd_mach_mipsisa32r3, bfd_mach_mipsisa32r2 },
+
+  /* MIPS32 extensions.  */
+  { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 },
+
+  /* MIPS II extensions.  */
+  { bfd_mach_mips4000, bfd_mach_mips6000 },
+  { bfd_mach_mipsisa32, bfd_mach_mips6000 },
+  { bfd_mach_mips4010, bfd_mach_mips6000 },
+
+  /* MIPS I extensions.  */
+  { bfd_mach_mips6000, bfd_mach_mips3000 },
+  { bfd_mach_mips3900, bfd_mach_mips3000 }
+};
+
+/* Return true if bfd machine EXTENSION is an extension of machine BASE.  */
+
+static bfd_boolean
+mips_mach_extends_p (unsigned long base, unsigned long extension)
+{
+  size_t i;
+
+  if (extension == base)
+    return TRUE;
+
+  if (base == bfd_mach_mipsisa32
+      && mips_mach_extends_p (bfd_mach_mipsisa64, extension))
+    return TRUE;
+
+  if (base == bfd_mach_mipsisa32r2
+      && mips_mach_extends_p (bfd_mach_mipsisa64r2, extension))
+    return TRUE;
+
+  for (i = 0; i < ARRAY_SIZE (mips_mach_extensions); i++)
+    if (extension == mips_mach_extensions[i].extension)
+      {
+       extension = mips_mach_extensions[i].base;
+       if (extension == base)
+         return TRUE;
+      }
+
+  return FALSE;
+}
+
+/* Return the BFD mach for each .MIPS.abiflags ISA Extension.  */
+
+static unsigned long
+bfd_mips_isa_ext_mach (unsigned int isa_ext)
+{
+  switch (isa_ext)
+    {
+    case AFL_EXT_3900:       return bfd_mach_mips3900;
+    case AFL_EXT_4010:       return bfd_mach_mips4010;
+    case AFL_EXT_4100:       return bfd_mach_mips4100;
+    case AFL_EXT_4111:       return bfd_mach_mips4111;
+    case AFL_EXT_4120:       return bfd_mach_mips4120;
+    case AFL_EXT_4650:       return bfd_mach_mips4650;
+    case AFL_EXT_5400:       return bfd_mach_mips5400;
+    case AFL_EXT_5500:       return bfd_mach_mips5500;
+    case AFL_EXT_5900:       return bfd_mach_mips5900;
+    case AFL_EXT_10000:              return bfd_mach_mips10000;
+    case AFL_EXT_LOONGSON_2E: return bfd_mach_mips_loongson_2e;
+    case AFL_EXT_LOONGSON_2F: return bfd_mach_mips_loongson_2f;
+    case AFL_EXT_SB1:        return bfd_mach_mips_sb1;
+    case AFL_EXT_OCTEON:      return bfd_mach_mips_octeon;
+    case AFL_EXT_OCTEONP:     return bfd_mach_mips_octeonp;
+    case AFL_EXT_OCTEON2:     return bfd_mach_mips_octeon2;
+    case AFL_EXT_XLR:        return bfd_mach_mips_xlr;
+    default:                 return bfd_mach_mips3000;
+    }
+}
+
+/* Return the .MIPS.abiflags value representing each ISA Extension.  */
+
+unsigned int
+bfd_mips_isa_ext (bfd *abfd)
+{
+  switch (bfd_get_mach (abfd))
+    {
+    case bfd_mach_mips3900:        return AFL_EXT_3900;
+    case bfd_mach_mips4010:        return AFL_EXT_4010;
+    case bfd_mach_mips4100:        return AFL_EXT_4100;
+    case bfd_mach_mips4111:        return AFL_EXT_4111;
+    case bfd_mach_mips4120:        return AFL_EXT_4120;
+    case bfd_mach_mips4650:        return AFL_EXT_4650;
+    case bfd_mach_mips5400:        return AFL_EXT_5400;
+    case bfd_mach_mips5500:        return AFL_EXT_5500;
+    case bfd_mach_mips5900:        return AFL_EXT_5900;
+    case bfd_mach_mips10000:       return AFL_EXT_10000;
+    case bfd_mach_mips_loongson_2e: return AFL_EXT_LOONGSON_2E;
+    case bfd_mach_mips_loongson_2f: return AFL_EXT_LOONGSON_2F;
+    case bfd_mach_mips_sb1:        return AFL_EXT_SB1;
+    case bfd_mach_mips_octeon:     return AFL_EXT_OCTEON;
+    case bfd_mach_mips_octeonp:            return AFL_EXT_OCTEONP;
+    case bfd_mach_mips_octeon3:            return AFL_EXT_OCTEON3;
+    case bfd_mach_mips_octeon2:            return AFL_EXT_OCTEON2;
+    case bfd_mach_mips_xlr:        return AFL_EXT_XLR;
+    case bfd_mach_mips_interaptiv_mr2:
+      return AFL_EXT_INTERAPTIV_MR2;
+    default:                       return 0;
+    }
+}
+
+/* Encode ISA level and revision as a single value.  */
+#define LEVEL_REV(LEV,REV) ((LEV) << 3 | (REV))
+
+/* Decode a single value into level and revision.  */
+#define ISA_LEVEL(LEVREV)  ((LEVREV) >> 3)
+#define ISA_REV(LEVREV)    ((LEVREV) & 0x7)
+
+/* Update the isa_level, isa_rev, isa_ext fields of abiflags.  */
+
+static void
+update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags)
+{
+  int new_isa = 0;
+  switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH)
+    {
+    case E_MIPS_ARCH_1:    new_isa = LEVEL_REV (1, 0); break;
+    case E_MIPS_ARCH_2:    new_isa = LEVEL_REV (2, 0); break;
+    case E_MIPS_ARCH_3:    new_isa = LEVEL_REV (3, 0); break;
+    case E_MIPS_ARCH_4:    new_isa = LEVEL_REV (4, 0); break;
+    case E_MIPS_ARCH_5:    new_isa = LEVEL_REV (5, 0); break;
+    case E_MIPS_ARCH_32:   new_isa = LEVEL_REV (32, 1); break;
+    case E_MIPS_ARCH_32R2: new_isa = LEVEL_REV (32, 2); break;
+    case E_MIPS_ARCH_32R6: new_isa = LEVEL_REV (32, 6); break;
+    case E_MIPS_ARCH_64:   new_isa = LEVEL_REV (64, 1); break;
+    case E_MIPS_ARCH_64R2: new_isa = LEVEL_REV (64, 2); break;
+    case E_MIPS_ARCH_64R6: new_isa = LEVEL_REV (64, 6); break;
+    default:
+      _bfd_error_handler
+       /* xgettext:c-format */
+       (_("%pB: unknown architecture %s"),
+        abfd, bfd_printable_name (abfd));
+    }
+
+  if (new_isa > LEVEL_REV (abiflags->isa_level, abiflags->isa_rev))
+    {
+      abiflags->isa_level = ISA_LEVEL (new_isa);
+      abiflags->isa_rev = ISA_REV (new_isa);
+    }
+
+  /* Update the isa_ext if ABFD describes a further extension.  */
+  if (mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags->isa_ext),
+                          bfd_get_mach (abfd)))
+    abiflags->isa_ext = bfd_mips_isa_ext (abfd);
+}
+
+/* Return true if the given ELF header flags describe a 32-bit binary.  */
+
+static bfd_boolean
+mips_32bit_flags_p (flagword flags)
+{
+  return ((flags & EF_MIPS_32BITMODE) != 0
+         || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32
+         || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2
+         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6);
+}
+
+/* Infer the content of the ABI flags based on the elf header.  */
+
+static void
+infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags)
+{
+  obj_attribute *in_attr;
+
+  memset (abiflags, 0, sizeof (Elf_Internal_ABIFlags_v0));
+  update_mips_abiflags_isa (abfd, abiflags);
+
+  if (mips_32bit_flags_p (elf_elfheader (abfd)->e_flags))
+    abiflags->gpr_size = AFL_REG_32;
+  else
+    abiflags->gpr_size = AFL_REG_64;
+
+  abiflags->cpr1_size = AFL_REG_NONE;
+
+  in_attr = elf_known_obj_attributes (abfd)[OBJ_ATTR_GNU];
+  abiflags->fp_abi = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+
+  if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_SINGLE
+      || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_XX
+      || (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE
+         && abiflags->gpr_size == AFL_REG_32))
+    abiflags->cpr1_size = AFL_REG_32;
+  else if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE
+          || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64
+          || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64A)
+    abiflags->cpr1_size = AFL_REG_64;
+
+  abiflags->cpr2_size = AFL_REG_NONE;
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MDMX)
+    abiflags->ases |= AFL_ASE_MDMX;
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
+    abiflags->ases |= AFL_ASE_MIPS16;
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+    abiflags->ases |= AFL_ASE_MICROMIPS;
+
+  if (abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_ANY
+      && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT
+      && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A
+      && abiflags->isa_level >= 32
+      && abiflags->ases != AFL_ASE_LOONGSON_EXT)
+    abiflags->flags1 |= AFL_FLAGS1_ODDSPREG;
+}
+
 /* We need to use a special link routine to handle the .reginfo and
    the .mdebug sections.  We need to merge all instances of these
    sections together, not write them all out sequentially.  */
@@ -12902,7 +14290,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   asection *o;
   struct bfd_link_order *p;
   asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec;
-  asection *rtproc_sec;
+  asection *rtproc_sec, *abiflags_sec;
   Elf32_RegInfo reginfo;
   struct ecoff_debug_info debug;
   struct mips_htab_traverse_info hti;
@@ -12927,11 +14315,11 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     scRData, scSData, scSBss, scBss
   };
 
-  /* Sort the dynamic symbols so that those with GOT entries come after
-     those without.  */
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
+  /* Sort the dynamic symbols so that those with GOT entries come after
+     those without.  */
   if (!mips_elf_sort_hash_table (abfd, info))
     return FALSE;
 
@@ -12961,7 +14349,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        elf_gp (abfd) = (h->u.def.section->output_section->vma
                         + h->u.def.section->output_offset
                         + h->u.def.value);
-      else if (info->relocatable)
+      else if (bfd_link_relocatable (info))
        {
          bfd_vma lo = MINUS_ONE;
 
@@ -12984,12 +14372,46 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* Go through the sections and collect the .reginfo and .mdebug
      information.  */
+  abiflags_sec = NULL;
   reginfo_sec = NULL;
   mdebug_sec = NULL;
   gptab_data_sec = NULL;
   gptab_bss_sec = NULL;
   for (o = abfd->sections; o != NULL; o = o->next)
     {
+      if (strcmp (o->name, ".MIPS.abiflags") == 0)
+       {
+         /* We have found the .MIPS.abiflags section in the output file.
+            Look through all the link_orders comprising it and remove them.
+            The data is merged in _bfd_mips_elf_merge_private_bfd_data.  */
+         for (p = o->map_head.link_order; p != NULL; p = p->next)
+           {
+             asection *input_section;
+
+             if (p->type != bfd_indirect_link_order)
+               {
+                 if (p->type == bfd_data_link_order)
+                   continue;
+                 abort ();
+               }
+
+             input_section = p->u.indirect.section;
+
+             /* Hack: reset the SEC_HAS_CONTENTS flag so that
+                elf_link_input_bfd ignores this section.  */
+             input_section->flags &= ~SEC_HAS_CONTENTS;
+           }
+
+         /* Size has been set in _bfd_mips_elf_always_size_sections.  */
+         BFD_ASSERT(o->size == sizeof (Elf_External_ABIFlags_v0));
+
+         /* Skip this section later on (I don't think this currently
+            matters, but someday it might).  */
+         o->map_head.link_order = NULL;
+
+         abiflags_sec = o;
+       }
+
       if (strcmp (o->name, ".reginfo") == 0)
        {
          memset (&reginfo, 0, sizeof reginfo);
@@ -13003,6 +14425,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              bfd *input_bfd;
              Elf32_External_RegInfo ext;
              Elf32_RegInfo sub;
+             bfd_size_type sz;
 
              if (p->type != bfd_indirect_link_order)
                {
@@ -13014,8 +14437,11 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              input_section = p->u.indirect.section;
              input_bfd = input_section->owner;
 
+             sz = (input_section->size < sizeof (ext)
+                   ? input_section->size : sizeof (ext));
+             memset (&ext, 0, sizeof (ext));
              if (! bfd_get_section_contents (input_bfd, input_section,
-                                             &ext, 0, sizeof ext))
+                                             &ext, 0, sz))
                return FALSE;
 
              bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub);
@@ -13027,7 +14453,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              reginfo.ri_cprmask[3] |= sub.ri_cprmask[3];
 
              /* ri_gp_value is set by the function
-                mips_elf32_section_processing when the section is
+                `_bfd_mips_elf_section_processing' when the section is
                 finally written out.  */
 
              /* Hack: reset the SEC_HAS_CONTENTS flag so that
@@ -13213,7 +14639,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              input_section->flags &= ~SEC_HAS_CONTENTS;
            }
 
-         if (SGI_COMPAT (abfd) && info->shared)
+         if (SGI_COMPAT (abfd) && bfd_link_pic (info))
            {
              /* Create .rtproc section.  */
              rtproc_sec = bfd_get_linker_section (abfd, ".rtproc");
@@ -13269,7 +14695,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
             information describing how the small data area would
             change depending upon the -G switch.  These sections
             not used in executables files.  */
-         if (! info->relocatable)
+         if (! bfd_link_relocatable (info))
            {
              for (p = o->map_head.link_order; p != NULL; p = p->next)
                {
@@ -13308,9 +14734,9 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            gptab_bss_sec = o;
          else
            {
-             (*_bfd_error_handler)
-               (_("%s: illegal section name `%s'"),
-                bfd_get_filename (abfd), o->name);
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB: illegal section name `%pA'"), abfd, o);
              bfd_set_error (bfd_error_nonrepresentable_section);
              return FALSE;
            }
@@ -13474,6 +14900,24 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* Now write out the computed sections.  */
 
+  if (abiflags_sec != NULL)
+    {
+      Elf_External_ABIFlags_v0 ext;
+      Elf_Internal_ABIFlags_v0 *abiflags;
+
+      abiflags = &mips_elf_tdata (abfd)->abiflags;
+
+      /* Set up the abiflags if no valid input sections were found.  */
+      if (!mips_elf_tdata (abfd)->abiflags_valid)
+       {
+         infer_mips_abiflags (abfd, abiflags);
+         mips_elf_tdata (abfd)->abiflags_valid = TRUE;
+       }
+      bfd_mips_elf_swap_abiflags_v0_out (abfd, abiflags, &ext);
+      if (! bfd_set_section_contents (abfd, abiflags_sec, &ext, 0, sizeof ext))
+       return FALSE;
+    }
+
   if (reginfo_sec != NULL)
     {
       Elf32_External_RegInfo ext;
@@ -13525,139 +14969,226 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 \f
-/* Structure for saying that BFD machine EXTENSION extends BASE.  */
+/* Merge object file header flags from IBFD into OBFD.  Raise an error
+   if there are conflicting settings.  */
 
-struct mips_mach_extension {
-  unsigned long extension, base;
-};
+static bfd_boolean
+mips_elf_merge_obj_e_flags (bfd *ibfd, struct bfd_link_info *info)
+{
+  bfd *obfd = info->output_bfd;
+  struct mips_elf_obj_tdata *out_tdata = mips_elf_tdata (obfd);
+  flagword old_flags;
+  flagword new_flags;
+  bfd_boolean ok;
 
+  new_flags = elf_elfheader (ibfd)->e_flags;
+  elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
+  old_flags = elf_elfheader (obfd)->e_flags;
 
-/* An array describing how BFD machines relate to one another.  The entries
-   are ordered topologically with MIPS I extensions listed last.  */
+  /* Check flag compatibility.  */
 
-static const struct mips_mach_extension mips_mach_extensions[] = {
-  /* MIPS64r2 extensions.  */
-  { bfd_mach_mips_octeon2, bfd_mach_mips_octeonp },
-  { bfd_mach_mips_octeonp, bfd_mach_mips_octeon },
-  { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
+  new_flags &= ~EF_MIPS_NOREORDER;
+  old_flags &= ~EF_MIPS_NOREORDER;
 
-  /* MIPS64 extensions.  */
-  { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
-  { bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
-  { bfd_mach_mips_xlr, bfd_mach_mipsisa64 },
-  { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64 },
+  /* Some IRIX 6 BSD-compatibility objects have this bit set.  It
+     doesn't seem to matter.  */
+  new_flags &= ~EF_MIPS_XGOT;
+  old_flags &= ~EF_MIPS_XGOT;
 
-  /* MIPS V extensions.  */
-  { bfd_mach_mipsisa64, bfd_mach_mips5 },
+  /* MIPSpro generates ucode info in n64 objects.  Again, we should
+     just be able to ignore this.  */
+  new_flags &= ~EF_MIPS_UCODE;
+  old_flags &= ~EF_MIPS_UCODE;
 
-  /* R10000 extensions.  */
-  { bfd_mach_mips12000, bfd_mach_mips10000 },
-  { bfd_mach_mips14000, bfd_mach_mips10000 },
-  { bfd_mach_mips16000, bfd_mach_mips10000 },
+  /* DSOs should only be linked with CPIC code.  */
+  if ((ibfd->flags & DYNAMIC) != 0)
+    new_flags |= EF_MIPS_PIC | EF_MIPS_CPIC;
 
-  /* R5000 extensions.  Note: the vr5500 ISA is an extension of the core
-     vr5400 ISA, but doesn't include the multimedia stuff.  It seems
-     better to allow vr5400 and vr5500 code to be merged anyway, since
-     many libraries will just use the core ISA.  Perhaps we could add
-     some sort of ASE flag if this ever proves a problem.  */
-  { bfd_mach_mips5500, bfd_mach_mips5400 },
-  { bfd_mach_mips5400, bfd_mach_mips5000 },
+  if (new_flags == old_flags)
+    return TRUE;
 
-  /* MIPS IV extensions.  */
-  { bfd_mach_mips5, bfd_mach_mips8000 },
-  { bfd_mach_mips10000, bfd_mach_mips8000 },
-  { bfd_mach_mips5000, bfd_mach_mips8000 },
-  { bfd_mach_mips7000, bfd_mach_mips8000 },
-  { bfd_mach_mips9000, bfd_mach_mips8000 },
+  ok = TRUE;
 
-  /* VR4100 extensions.  */
-  { bfd_mach_mips4120, bfd_mach_mips4100 },
-  { bfd_mach_mips4111, bfd_mach_mips4100 },
+  if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
+      != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
+    {
+      _bfd_error_handler
+       (_("%pB: warning: linking abicalls files with non-abicalls files"),
+        ibfd);
+      ok = TRUE;
+    }
 
-  /* MIPS III extensions.  */
-  { bfd_mach_mips_loongson_2e, bfd_mach_mips4000 },
-  { bfd_mach_mips_loongson_2f, bfd_mach_mips4000 },
-  { bfd_mach_mips8000, bfd_mach_mips4000 },
-  { bfd_mach_mips4650, bfd_mach_mips4000 },
-  { bfd_mach_mips4600, bfd_mach_mips4000 },
-  { bfd_mach_mips4400, bfd_mach_mips4000 },
-  { bfd_mach_mips4300, bfd_mach_mips4000 },
-  { bfd_mach_mips4100, bfd_mach_mips4000 },
-  { bfd_mach_mips4010, bfd_mach_mips4000 },
-  { bfd_mach_mips5900, bfd_mach_mips4000 },
+  if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC))
+    elf_elfheader (obfd)->e_flags |= EF_MIPS_CPIC;
+  if (! (new_flags & EF_MIPS_PIC))
+    elf_elfheader (obfd)->e_flags &= ~EF_MIPS_PIC;
 
-  /* MIPS32 extensions.  */
-  { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 },
+  new_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
+  old_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
 
-  /* MIPS II extensions.  */
-  { bfd_mach_mips4000, bfd_mach_mips6000 },
-  { bfd_mach_mipsisa32, bfd_mach_mips6000 },
+  /* Compare the ISAs.  */
+  if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))
+    {
+      _bfd_error_handler
+       (_("%pB: linking 32-bit code with 64-bit code"),
+        ibfd);
+      ok = FALSE;
+    }
+  else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd)))
+    {
+      /* OBFD's ISA isn't the same as, or an extension of, IBFD's.  */
+      if (mips_mach_extends_p (bfd_get_mach (obfd), bfd_get_mach (ibfd)))
+       {
+         /* Copy the architecture info from IBFD to OBFD.  Also copy
+            the 32-bit flag (if set) so that we continue to recognise
+            OBFD as a 32-bit binary.  */
+         bfd_set_arch_info (obfd, bfd_get_arch_info (ibfd));
+         elf_elfheader (obfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
+         elf_elfheader (obfd)->e_flags
+           |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
 
-  /* MIPS I extensions.  */
-  { bfd_mach_mips6000, bfd_mach_mips3000 },
-  { bfd_mach_mips3900, bfd_mach_mips3000 }
-};
+         /* Update the ABI flags isa_level, isa_rev, isa_ext fields.  */
+         update_mips_abiflags_isa (obfd, &out_tdata->abiflags);
 
+         /* Copy across the ABI flags if OBFD doesn't use them
+            and if that was what caused us to treat IBFD as 32-bit.  */
+         if ((old_flags & EF_MIPS_ABI) == 0
+             && mips_32bit_flags_p (new_flags)
+             && !mips_32bit_flags_p (new_flags & ~EF_MIPS_ABI))
+           elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ABI;
+       }
+      else
+       {
+         /* The ISAs aren't compatible.  */
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: linking %s module with previous %s modules"),
+            ibfd,
+            bfd_printable_name (ibfd),
+            bfd_printable_name (obfd));
+         ok = FALSE;
+       }
+    }
 
-/* Return true if bfd machine EXTENSION is an extension of machine BASE.  */
+  new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
+  old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
 
-static bfd_boolean
-mips_mach_extends_p (unsigned long base, unsigned long extension)
-{
-  size_t i;
+  /* Compare ABIs.  The 64-bit ABI does not use EF_MIPS_ABI.  But, it
+     does set EI_CLASS differently from any 32-bit ABI.  */
+  if ((new_flags & EF_MIPS_ABI) != (old_flags & EF_MIPS_ABI)
+      || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
+         != elf_elfheader (obfd)->e_ident[EI_CLASS]))
+    {
+      /* Only error if both are set (to different values).  */
+      if (((new_flags & EF_MIPS_ABI) && (old_flags & EF_MIPS_ABI))
+         || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
+             != elf_elfheader (obfd)->e_ident[EI_CLASS]))
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: ABI mismatch: linking %s module with previous %s modules"),
+            ibfd,
+            elf_mips_abi_name (ibfd),
+            elf_mips_abi_name (obfd));
+         ok = FALSE;
+       }
+      new_flags &= ~EF_MIPS_ABI;
+      old_flags &= ~EF_MIPS_ABI;
+    }
 
-  if (extension == base)
-    return TRUE;
+  /* Compare ASEs.  Forbid linking MIPS16 and microMIPS ASE modules together
+     and allow arbitrary mixing of the remaining ASEs (retain the union).  */
+  if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE))
+    {
+      int old_micro = old_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
+      int new_micro = new_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
+      int old_m16 = old_flags & EF_MIPS_ARCH_ASE_M16;
+      int new_m16 = new_flags & EF_MIPS_ARCH_ASE_M16;
+      int micro_mis = old_m16 && new_micro;
+      int m16_mis = old_micro && new_m16;
 
-  if (base == bfd_mach_mipsisa32
-      && mips_mach_extends_p (bfd_mach_mipsisa64, extension))
-    return TRUE;
+      if (m16_mis || micro_mis)
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: ASE mismatch: linking %s module with previous %s modules"),
+            ibfd,
+            m16_mis ? "MIPS16" : "microMIPS",
+            m16_mis ? "microMIPS" : "MIPS16");
+         ok = FALSE;
+       }
 
-  if (base == bfd_mach_mipsisa32r2
-      && mips_mach_extends_p (bfd_mach_mipsisa64r2, extension))
-    return TRUE;
+      elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
 
-  for (i = 0; i < ARRAY_SIZE (mips_mach_extensions); i++)
-    if (extension == mips_mach_extensions[i].extension)
-      {
-       extension = mips_mach_extensions[i].base;
-       if (extension == base)
-         return TRUE;
-      }
+      new_flags &= ~ EF_MIPS_ARCH_ASE;
+      old_flags &= ~ EF_MIPS_ARCH_ASE;
+    }
 
-  return FALSE;
-}
+  /* Compare NaN encodings.  */
+  if ((new_flags & EF_MIPS_NAN2008) != (old_flags & EF_MIPS_NAN2008))
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: linking %s module with previous %s modules"),
+                         ibfd,
+                         (new_flags & EF_MIPS_NAN2008
+                          ? "-mnan=2008" : "-mnan=legacy"),
+                         (old_flags & EF_MIPS_NAN2008
+                          ? "-mnan=2008" : "-mnan=legacy"));
+      ok = FALSE;
+      new_flags &= ~EF_MIPS_NAN2008;
+      old_flags &= ~EF_MIPS_NAN2008;
+    }
 
+  /* Compare FP64 state.  */
+  if ((new_flags & EF_MIPS_FP64) != (old_flags & EF_MIPS_FP64))
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: linking %s module with previous %s modules"),
+                         ibfd,
+                         (new_flags & EF_MIPS_FP64
+                          ? "-mfp64" : "-mfp32"),
+                         (old_flags & EF_MIPS_FP64
+                          ? "-mfp64" : "-mfp32"));
+      ok = FALSE;
+      new_flags &= ~EF_MIPS_FP64;
+      old_flags &= ~EF_MIPS_FP64;
+    }
 
-/* Return true if the given ELF header flags describe a 32-bit binary.  */
+  /* Warn about any other mismatches */
+  if (new_flags != old_flags)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler
+       (_("%pB: uses different e_flags (%#x) fields than previous modules "
+          "(%#x)"),
+        ibfd, new_flags, old_flags);
+      ok = FALSE;
+    }
 
-static bfd_boolean
-mips_32bit_flags_p (flagword flags)
-{
-  return ((flags & EF_MIPS_32BITMODE) != 0
-         || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32
-         || (flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI32
-         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1
-         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2
-         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32
-         || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2);
+  return ok;
 }
 
-
 /* Merge object attributes from IBFD into OBFD.  Raise an error if
    there are conflicting attributes.  */
 static bfd_boolean
-mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+mips_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
+  bfd *obfd = info->output_bfd;
   obj_attribute *in_attr;
   obj_attribute *out_attr;
   bfd *abi_fp_bfd;
+  bfd *abi_msa_bfd;
 
   abi_fp_bfd = mips_elf_tdata (obfd)->abi_fp_bfd;
   in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
-  if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != 0)
+  if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != Val_GNU_MIPS_ABI_FP_ANY)
     mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
 
+  abi_msa_bfd = mips_elf_tdata (obfd)->abi_msa_bfd;
+  if (!abi_msa_bfd
+      && in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY)
+    mips_elf_tdata (obfd)->abi_msa_bfd = ibfd;
+
   if (!elf_known_obj_attributes_proc (obfd)[0].i)
     {
       /* This is the first object.  Copy the attributes.  */
@@ -13675,180 +15206,152 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
   out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
   if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i)
     {
-      out_attr[Tag_GNU_MIPS_ABI_FP].type = 1;
-      if (out_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
-       out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
-      else if (in_attr[Tag_GNU_MIPS_ABI_FP].i != 0)
-       switch (out_attr[Tag_GNU_MIPS_ABI_FP].i)
-         {
-         case 1:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 2:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd, "-mdouble-float", "-msingle-float");
-               break;
-
-             case 3:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
-               break;
-
-             case 4:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-mdouble-float", "-mips32r2 -mfp64");
-               break;
-
-             default:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), "
-                    "%B uses unknown floating point ABI %d"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-mdouble-float", in_attr[Tag_GNU_MIPS_ABI_FP].i);
-               break;
-             }
-           break;
-
-         case 2:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 1:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd, "-msingle-float", "-mdouble-float");
-               break;
-
-             case 3:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
-               break;
-
-             case 4:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-msingle-float", "-mips32r2 -mfp64");
-               break;
-
-             default:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), "
-                    "%B uses unknown floating point ABI %d"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-msingle-float", in_attr[Tag_GNU_MIPS_ABI_FP].i);
-               break;
-             }
-           break;
-
-         case 3:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 1:
-             case 2:
-             case 4:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd, "-msoft-float", "-mhard-float");
-               break;
-
-             default:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), "
-                    "%B uses unknown floating point ABI %d"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-msoft-float", in_attr[Tag_GNU_MIPS_ABI_FP].i);
-               break;
-             }
-           break;
+      int out_fp, in_fp;
 
-         case 4:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
-             {
-             case 1:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-mips32r2 -mfp64", "-mdouble-float");
-               break;
-
-             case 2:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-mips32r2 -mfp64", "-msingle-float");
-               break;
-
-             case 3:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
-               break;
+      out_fp = out_attr[Tag_GNU_MIPS_ABI_FP].i;
+      in_fp = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+      out_attr[Tag_GNU_MIPS_ABI_FP].type = 1;
+      if (out_fp == Val_GNU_MIPS_ABI_FP_ANY)
+       out_attr[Tag_GNU_MIPS_ABI_FP].i = in_fp;
+      else if (out_fp == Val_GNU_MIPS_ABI_FP_XX
+              && (in_fp == Val_GNU_MIPS_ABI_FP_DOUBLE
+                  || in_fp == Val_GNU_MIPS_ABI_FP_64
+                  || in_fp == Val_GNU_MIPS_ABI_FP_64A))
+       {
+         mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+         out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+       }
+      else if (in_fp == Val_GNU_MIPS_ABI_FP_XX
+              && (out_fp == Val_GNU_MIPS_ABI_FP_DOUBLE
+                  || out_fp == Val_GNU_MIPS_ABI_FP_64
+                  || out_fp == Val_GNU_MIPS_ABI_FP_64A))
+       /* Keep the current setting.  */;
+      else if (out_fp == Val_GNU_MIPS_ABI_FP_64A
+              && in_fp == Val_GNU_MIPS_ABI_FP_64)
+       {
+         mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+         out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+       }
+      else if (in_fp == Val_GNU_MIPS_ABI_FP_64A
+              && out_fp == Val_GNU_MIPS_ABI_FP_64)
+       /* Keep the current setting.  */;
+      else if (in_fp != Val_GNU_MIPS_ABI_FP_ANY)
+       {
+         const char *out_string, *in_string;
+
+         out_string = _bfd_mips_fp_abi_string (out_fp);
+         in_string = _bfd_mips_fp_abi_string (in_fp);
+         /* First warn about cases involving unrecognised ABIs.  */
+         if (!out_string && !in_string)
+           /* xgettext:c-format */
+           _bfd_error_handler
+             (_("warning: %pB uses unknown floating point ABI %d "
+                "(set by %pB), %pB uses unknown floating point ABI %d"),
+              obfd, out_fp, abi_fp_bfd, ibfd, in_fp);
+         else if (!out_string)
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("warning: %pB uses unknown floating point ABI %d "
+                "(set by %pB), %pB uses %s"),
+              obfd, out_fp, abi_fp_bfd, ibfd, in_string);
+         else if (!in_string)
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("warning: %pB uses %s (set by %pB), "
+                "%pB uses unknown floating point ABI %d"),
+              obfd, out_string, abi_fp_bfd, ibfd, in_fp);
+         else
+           {
+             /* If one of the bfds is soft-float, the other must be
+                hard-float.  The exact choice of hard-float ABI isn't
+                really relevant to the error message.  */
+             if (in_fp == Val_GNU_MIPS_ABI_FP_SOFT)
+               out_string = "-mhard-float";
+             else if (out_fp == Val_GNU_MIPS_ABI_FP_SOFT)
+               in_string = "-mhard-float";
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("warning: %pB uses %s (set by %pB), %pB uses %s"),
+                obfd, out_string, abi_fp_bfd, ibfd, in_string);
+           }
+       }
+    }
 
-             default:
-               _bfd_error_handler
-                 (_("Warning: %B uses %s (set by %B), "
-                    "%B uses unknown floating point ABI %d"),
-                  obfd, abi_fp_bfd, ibfd,
-                  "-mips32r2 -mfp64", in_attr[Tag_GNU_MIPS_ABI_FP].i);
-               break;
-             }
+  /* Check for conflicting Tag_GNU_MIPS_ABI_MSA attributes and merge
+     non-conflicting ones.  */
+  if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != out_attr[Tag_GNU_MIPS_ABI_MSA].i)
+    {
+      out_attr[Tag_GNU_MIPS_ABI_MSA].type = 1;
+      if (out_attr[Tag_GNU_MIPS_ABI_MSA].i == Val_GNU_MIPS_ABI_MSA_ANY)
+       out_attr[Tag_GNU_MIPS_ABI_MSA].i = in_attr[Tag_GNU_MIPS_ABI_MSA].i;
+      else if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY)
+       switch (out_attr[Tag_GNU_MIPS_ABI_MSA].i)
+         {
+         case Val_GNU_MIPS_ABI_MSA_128:
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("warning: %pB uses %s (set by %pB), "
+                "%pB uses unknown MSA ABI %d"),
+              obfd, "-mmsa", abi_msa_bfd,
+              ibfd, in_attr[Tag_GNU_MIPS_ABI_MSA].i);
            break;
 
          default:
-           switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
+           switch (in_attr[Tag_GNU_MIPS_ABI_MSA].i)
              {
-             case 1:
-               _bfd_error_handler
-                 (_("Warning: %B uses unknown floating point ABI %d "
-                    "(set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mdouble-float");
-               break;
-
-             case 2:
-               _bfd_error_handler
-                 (_("Warning: %B uses unknown floating point ABI %d "
-                    "(set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msingle-float");
-               break;
-
-             case 3:
-               _bfd_error_handler
-                 (_("Warning: %B uses unknown floating point ABI %d "
-                    "(set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msoft-float");
-               break;
-
-             case 4:
+             case Val_GNU_MIPS_ABI_MSA_128:
                _bfd_error_handler
-                 (_("Warning: %B uses unknown floating point ABI %d "
-                    "(set by %B), %B uses %s"),
-                  obfd, abi_fp_bfd, ibfd,
-                  out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mips32r2 -mfp64");
-               break;
+                 /* xgettext:c-format */
+                 (_("warning: %pB uses unknown MSA ABI %d "
+                    "(set by %pB), %pB uses %s"),
+                    obfd, out_attr[Tag_GNU_MIPS_ABI_MSA].i,
+                  abi_msa_bfd, ibfd, "-mmsa");
+                 break;
 
              default:
                _bfd_error_handler
-                 (_("Warning: %B uses unknown floating point ABI %d "
-                    "(set by %B), %B uses unknown floating point ABI %d"),
-                  obfd, abi_fp_bfd, ibfd,
-                  out_attr[Tag_GNU_MIPS_ABI_FP].i,
-                  in_attr[Tag_GNU_MIPS_ABI_FP].i);
+                 /* xgettext:c-format */
+                 (_("warning: %pB uses unknown MSA ABI %d "
+                    "(set by %pB), %pB uses unknown MSA ABI %d"),
+                  obfd, out_attr[Tag_GNU_MIPS_ABI_MSA].i,
+                  abi_msa_bfd, ibfd, in_attr[Tag_GNU_MIPS_ABI_MSA].i);
                break;
              }
-           break;
          }
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, obfd);
+  return _bfd_elf_merge_object_attributes (ibfd, info);
+}
+
+/* Merge object ABI flags from IBFD into OBFD.  Raise an error if
+   there are conflicting settings.  */
+
+static bfd_boolean
+mips_elf_merge_obj_abiflags (bfd *ibfd, bfd *obfd)
+{
+  obj_attribute *out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+  struct mips_elf_obj_tdata *out_tdata = mips_elf_tdata (obfd);
+  struct mips_elf_obj_tdata *in_tdata = mips_elf_tdata (ibfd);
+
+  /* Update the output abiflags fp_abi using the computed fp_abi.  */
+  out_tdata->abiflags.fp_abi = out_attr[Tag_GNU_MIPS_ABI_FP].i;
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+  /* Merge abiflags.  */
+  out_tdata->abiflags.isa_level = max (out_tdata->abiflags.isa_level,
+                                      in_tdata->abiflags.isa_level);
+  out_tdata->abiflags.isa_rev = max (out_tdata->abiflags.isa_rev,
+                                    in_tdata->abiflags.isa_rev);
+  out_tdata->abiflags.gpr_size = max (out_tdata->abiflags.gpr_size,
+                                     in_tdata->abiflags.gpr_size);
+  out_tdata->abiflags.cpr1_size = max (out_tdata->abiflags.cpr1_size,
+                                      in_tdata->abiflags.cpr1_size);
+  out_tdata->abiflags.cpr2_size = max (out_tdata->abiflags.cpr2_size,
+                                      in_tdata->abiflags.cpr2_size);
+#undef max
+  out_tdata->abiflags.ases |= in_tdata->abiflags.ases;
+  out_tdata->abiflags.flags1 |= in_tdata->abiflags.flags1;
 
   return TRUE;
 }
@@ -13857,86 +15360,41 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
    object file when linking.  */
 
 bfd_boolean
-_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
-  flagword old_flags;
-  flagword new_flags;
-  bfd_boolean ok;
+  bfd *obfd = info->output_bfd;
+  struct mips_elf_obj_tdata *out_tdata;
+  struct mips_elf_obj_tdata *in_tdata;
   bfd_boolean null_input_bfd = TRUE;
   asection *sec;
+  bfd_boolean ok;
 
   /* Check if we have the same endianness.  */
-  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
-    {
-      (*_bfd_error_handler)
-       (_("%B: endianness incompatible with that of the selected emulation"),
-        ibfd);
-      return FALSE;
-    }
-
-  if (!is_mips_elf (ibfd) || !is_mips_elf (obfd))
-    return TRUE;
-
-  if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
-    {
-      (*_bfd_error_handler)
-       (_("%B: ABI is incompatible with that of the selected emulation"),
-        ibfd);
-      return FALSE;
-    }
-
-  if (!mips_elf_merge_obj_attributes (ibfd, obfd))
-    return FALSE;
-
-  new_flags = elf_elfheader (ibfd)->e_flags;
-  elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
-  old_flags = elf_elfheader (obfd)->e_flags;
-
-  if (! elf_flags_init (obfd))
-    {
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = new_flags;
-      elf_elfheader (obfd)->e_ident[EI_CLASS]
-       = elf_elfheader (ibfd)->e_ident[EI_CLASS];
-
-      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
-         && (bfd_get_arch_info (obfd)->the_default
-             || mips_mach_extends_p (bfd_get_mach (obfd),
-                                     bfd_get_mach (ibfd))))
-       {
-         if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
-                                  bfd_get_mach (ibfd)))
-           return FALSE;
-       }
-
-      return TRUE;
-    }
-
-  /* Check flag compatibility.  */
-
-  new_flags &= ~EF_MIPS_NOREORDER;
-  old_flags &= ~EF_MIPS_NOREORDER;
-
-  /* Some IRIX 6 BSD-compatibility objects have this bit set.  It
-     doesn't seem to matter.  */
-  new_flags &= ~EF_MIPS_XGOT;
-  old_flags &= ~EF_MIPS_XGOT;
-
-  /* MIPSpro generates ucode info in n64 objects.  Again, we should
-     just be able to ignore this.  */
-  new_flags &= ~EF_MIPS_UCODE;
-  old_flags &= ~EF_MIPS_UCODE;
-
-  /* DSOs should only be linked with CPIC code.  */
-  if ((ibfd->flags & DYNAMIC) != 0)
-    new_flags |= EF_MIPS_PIC | EF_MIPS_CPIC;
+  if (! _bfd_generic_verify_endian_match (ibfd, info))
+    {
+      _bfd_error_handler
+       (_("%pB: endianness incompatible with that of the selected emulation"),
+        ibfd);
+      return FALSE;
+    }
 
-  if (new_flags == old_flags)
+  if (!is_mips_elf (ibfd) || !is_mips_elf (obfd))
     return TRUE;
 
-  /* Check to see if the input BFD actually contains any sections.
-     If not, its flags may not have been initialised either, but it cannot
-     actually cause any incompatibility.  */
+  in_tdata = mips_elf_tdata (ibfd);
+  out_tdata = mips_elf_tdata (obfd);
+
+  if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
+    {
+      _bfd_error_handler
+       (_("%pB: ABI is incompatible with that of the selected emulation"),
+        ibfd);
+      return FALSE;
+    }
+
+  /* Check to see if the input BFD actually contains any sections.  If not,
+     then it has no attributes, and its flags may not have been initialized
+     either, but it cannot actually cause any incompatibility.  */
   for (sec = ibfd->sections; sec != NULL; sec = sec->next)
     {
       /* Ignore synthetic sections and empty .text, .data and .bss sections
@@ -13958,128 +15416,96 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   if (null_input_bfd)
     return TRUE;
 
-  ok = TRUE;
-
-  if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
-      != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
-    {
-      (*_bfd_error_handler)
-       (_("%B: warning: linking abicalls files with non-abicalls files"),
-        ibfd);
-      ok = TRUE;
-    }
-
-  if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC))
-    elf_elfheader (obfd)->e_flags |= EF_MIPS_CPIC;
-  if (! (new_flags & EF_MIPS_PIC))
-    elf_elfheader (obfd)->e_flags &= ~EF_MIPS_PIC;
-
-  new_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
-  old_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
-
-  /* Compare the ISAs.  */
-  if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))
-    {
-      (*_bfd_error_handler)
-       (_("%B: linking 32-bit code with 64-bit code"),
-        ibfd);
-      ok = FALSE;
+  /* Populate abiflags using existing information.  */
+  if (in_tdata->abiflags_valid)
+    {
+      obj_attribute *in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+      Elf_Internal_ABIFlags_v0 in_abiflags;
+      Elf_Internal_ABIFlags_v0 abiflags;
+
+      /* Set up the FP ABI attribute from the abiflags if it is not already
+        set.  */
+      if (in_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY)
+       in_attr[Tag_GNU_MIPS_ABI_FP].i = in_tdata->abiflags.fp_abi;
+
+      infer_mips_abiflags (ibfd, &abiflags);
+      in_abiflags = in_tdata->abiflags;
+
+      /* It is not possible to infer the correct ISA revision
+        for R3 or R5 so drop down to R2 for the checks.  */
+      if (in_abiflags.isa_rev == 3 || in_abiflags.isa_rev == 5)
+       in_abiflags.isa_rev = 2;
+
+      if (LEVEL_REV (in_abiflags.isa_level, in_abiflags.isa_rev)
+         < LEVEL_REV (abiflags.isa_level, abiflags.isa_rev))
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent ISA between e_flags and "
+            ".MIPS.abiflags"), ibfd);
+      if (abiflags.fp_abi != Val_GNU_MIPS_ABI_FP_ANY
+         && in_abiflags.fp_abi != abiflags.fp_abi)
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent FP ABI between .gnu.attributes and "
+            ".MIPS.abiflags"), ibfd);
+      if ((in_abiflags.ases & abiflags.ases) != abiflags.ases)
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent ASEs between e_flags and "
+            ".MIPS.abiflags"), ibfd);
+      /* The isa_ext is allowed to be an extension of what can be inferred
+        from e_flags.  */
+      if (!mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags.isa_ext),
+                               bfd_mips_isa_ext_mach (in_abiflags.isa_ext)))
+       _bfd_error_handler
+         (_("%pB: warning: inconsistent ISA extensions between e_flags and "
+            ".MIPS.abiflags"), ibfd);
+      if (in_abiflags.flags2 != 0)
+       _bfd_error_handler
+         (_("%pB: warning: unexpected flag in the flags2 field of "
+            ".MIPS.abiflags (0x%lx)"), ibfd,
+          in_abiflags.flags2);
     }
-  else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd)))
+  else
     {
-      /* OBFD's ISA isn't the same as, or an extension of, IBFD's.  */
-      if (mips_mach_extends_p (bfd_get_mach (obfd), bfd_get_mach (ibfd)))
-       {
-         /* Copy the architecture info from IBFD to OBFD.  Also copy
-            the 32-bit flag (if set) so that we continue to recognise
-            OBFD as a 32-bit binary.  */
-         bfd_set_arch_info (obfd, bfd_get_arch_info (ibfd));
-         elf_elfheader (obfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
-         elf_elfheader (obfd)->e_flags
-           |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
-
-         /* Copy across the ABI flags if OBFD doesn't use them
-            and if that was what caused us to treat IBFD as 32-bit.  */
-         if ((old_flags & EF_MIPS_ABI) == 0
-             && mips_32bit_flags_p (new_flags)
-             && !mips_32bit_flags_p (new_flags & ~EF_MIPS_ABI))
-           elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ABI;
-       }
-      else
-       {
-         /* The ISAs aren't compatible.  */
-         (*_bfd_error_handler)
-           (_("%B: linking %s module with previous %s modules"),
-            ibfd,
-            bfd_printable_name (ibfd),
-            bfd_printable_name (obfd));
-         ok = FALSE;
-       }
+      infer_mips_abiflags (ibfd, &in_tdata->abiflags);
+      in_tdata->abiflags_valid = TRUE;
     }
 
-  new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
-  old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE);
-
-  /* Compare ABIs.  The 64-bit ABI does not use EF_MIPS_ABI.  But, it
-     does set EI_CLASS differently from any 32-bit ABI.  */
-  if ((new_flags & EF_MIPS_ABI) != (old_flags & EF_MIPS_ABI)
-      || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
-         != elf_elfheader (obfd)->e_ident[EI_CLASS]))
+  if (!out_tdata->abiflags_valid)
     {
-      /* Only error if both are set (to different values).  */
-      if (((new_flags & EF_MIPS_ABI) && (old_flags & EF_MIPS_ABI))
-         || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
-             != elf_elfheader (obfd)->e_ident[EI_CLASS]))
-       {
-         (*_bfd_error_handler)
-           (_("%B: ABI mismatch: linking %s module with previous %s modules"),
-            ibfd,
-            elf_mips_abi_name (ibfd),
-            elf_mips_abi_name (obfd));
-         ok = FALSE;
-       }
-      new_flags &= ~EF_MIPS_ABI;
-      old_flags &= ~EF_MIPS_ABI;
+      /* Copy input abiflags if output abiflags are not already valid.  */
+      out_tdata->abiflags = in_tdata->abiflags;
+      out_tdata->abiflags_valid = TRUE;
     }
 
-  /* Compare ASEs.  Forbid linking MIPS16 and microMIPS ASE modules together
-     and allow arbitrary mixing of the remaining ASEs (retain the union).  */
-  if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE))
+  if (! elf_flags_init (obfd))
     {
-      int old_micro = old_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
-      int new_micro = new_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
-      int old_m16 = old_flags & EF_MIPS_ARCH_ASE_M16;
-      int new_m16 = new_flags & EF_MIPS_ARCH_ASE_M16;
-      int micro_mis = old_m16 && new_micro;
-      int m16_mis = old_micro && new_m16;
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+      elf_elfheader (obfd)->e_ident[EI_CLASS]
+       = elf_elfheader (ibfd)->e_ident[EI_CLASS];
 
-      if (m16_mis || micro_mis)
+      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+         && (bfd_get_arch_info (obfd)->the_default
+             || mips_mach_extends_p (bfd_get_mach (obfd),
+                                     bfd_get_mach (ibfd))))
        {
-         (*_bfd_error_handler)
-           (_("%B: ASE mismatch: linking %s module with previous %s modules"),
-            ibfd,
-            m16_mis ? "MIPS16" : "microMIPS",
-            m16_mis ? "microMIPS" : "MIPS16");
-         ok = FALSE;
-       }
+         if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+                                  bfd_get_mach (ibfd)))
+           return FALSE;
 
-      elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
+         /* Update the ABI flags isa_level, isa_rev and isa_ext fields.  */
+         update_mips_abiflags_isa (obfd, &out_tdata->abiflags);
+       }
 
-      new_flags &= ~ EF_MIPS_ARCH_ASE;
-      old_flags &= ~ EF_MIPS_ARCH_ASE;
+      ok = TRUE;
     }
+  else
+    ok = mips_elf_merge_obj_e_flags (ibfd, info);
 
-  /* Warn about any other mismatches */
-  if (new_flags != old_flags)
-    {
-      (*_bfd_error_handler)
-       (_("%B: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
-        ibfd, (unsigned long) new_flags,
-        (unsigned long) old_flags);
-      ok = FALSE;
-    }
+  ok = mips_elf_merge_obj_attributes (ibfd, info) && ok;
 
-  if (! ok)
+  ok = mips_elf_merge_obj_abiflags (ibfd, obfd) && ok;
+
+  if (!ok)
     {
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
@@ -14141,6 +15567,8 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag)
       return "MIPS_HIPAGENO";
     case DT_MIPS_RLD_MAP:
       return "MIPS_RLD_MAP";
+    case DT_MIPS_RLD_MAP_REL:
+      return "MIPS_RLD_MAP_REL";
     case DT_MIPS_DELTA_CLASS:
       return "MIPS_DELTA_CLASS";
     case DT_MIPS_DELTA_CLASS_NO:
@@ -14200,6 +15628,209 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag)
     }
 }
 
+/* Return the meaning of Tag_GNU_MIPS_ABI_FP value FP, or null if
+   not known.  */
+
+const char *
+_bfd_mips_fp_abi_string (int fp)
+{
+  switch (fp)
+    {
+      /* These strings aren't translated because they're simply
+        option lists.  */
+    case Val_GNU_MIPS_ABI_FP_DOUBLE:
+      return "-mdouble-float";
+
+    case Val_GNU_MIPS_ABI_FP_SINGLE:
+      return "-msingle-float";
+
+    case Val_GNU_MIPS_ABI_FP_SOFT:
+      return "-msoft-float";
+
+    case Val_GNU_MIPS_ABI_FP_OLD_64:
+      return _("-mips32r2 -mfp64 (12 callee-saved)");
+
+    case Val_GNU_MIPS_ABI_FP_XX:
+      return "-mfpxx";
+
+    case Val_GNU_MIPS_ABI_FP_64:
+      return "-mgp32 -mfp64";
+
+    case Val_GNU_MIPS_ABI_FP_64A:
+      return "-mgp32 -mfp64 -mno-odd-spreg";
+
+    default:
+      return 0;
+    }
+}
+
+static void
+print_mips_ases (FILE *file, unsigned int mask)
+{
+  if (mask & AFL_ASE_DSP)
+    fputs ("\n\tDSP ASE", file);
+  if (mask & AFL_ASE_DSPR2)
+    fputs ("\n\tDSP R2 ASE", file);
+  if (mask & AFL_ASE_DSPR3)
+    fputs ("\n\tDSP R3 ASE", file);
+  if (mask & AFL_ASE_EVA)
+    fputs ("\n\tEnhanced VA Scheme", file);
+  if (mask & AFL_ASE_MCU)
+    fputs ("\n\tMCU (MicroController) ASE", file);
+  if (mask & AFL_ASE_MDMX)
+    fputs ("\n\tMDMX ASE", file);
+  if (mask & AFL_ASE_MIPS3D)
+    fputs ("\n\tMIPS-3D ASE", file);
+  if (mask & AFL_ASE_MT)
+    fputs ("\n\tMT ASE", file);
+  if (mask & AFL_ASE_SMARTMIPS)
+    fputs ("\n\tSmartMIPS ASE", file);
+  if (mask & AFL_ASE_VIRT)
+    fputs ("\n\tVZ ASE", file);
+  if (mask & AFL_ASE_MSA)
+    fputs ("\n\tMSA ASE", file);
+  if (mask & AFL_ASE_MIPS16)
+    fputs ("\n\tMIPS16 ASE", file);
+  if (mask & AFL_ASE_MICROMIPS)
+    fputs ("\n\tMICROMIPS ASE", file);
+  if (mask & AFL_ASE_XPA)
+    fputs ("\n\tXPA ASE", file);
+  if (mask & AFL_ASE_MIPS16E2)
+    fputs ("\n\tMIPS16e2 ASE", file);
+  if (mask & AFL_ASE_CRC)
+    fputs ("\n\tCRC ASE", file);
+  if (mask & AFL_ASE_GINV)
+    fputs ("\n\tGINV ASE", file);
+  if (mask & AFL_ASE_LOONGSON_MMI)
+    fputs ("\n\tLoongson MMI ASE", file);
+  if (mask & AFL_ASE_LOONGSON_CAM)
+    fputs ("\n\tLoongson CAM ASE", file);
+  if (mask & AFL_ASE_LOONGSON_EXT)
+    fputs ("\n\tLoongson EXT ASE", file);
+  if (mask & AFL_ASE_LOONGSON_EXT2)
+    fputs ("\n\tLoongson EXT2 ASE", file);
+  if (mask == 0)
+    fprintf (file, "\n\t%s", _("None"));
+  else if ((mask & ~AFL_ASE_MASK) != 0)
+    fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~AFL_ASE_MASK);
+}
+
+static void
+print_mips_isa_ext (FILE *file, unsigned int isa_ext)
+{
+  switch (isa_ext)
+    {
+    case 0:
+      fputs (_("None"), file);
+      break;
+    case AFL_EXT_XLR:
+      fputs ("RMI XLR", file);
+      break;
+    case AFL_EXT_OCTEON3:
+      fputs ("Cavium Networks Octeon3", file);
+      break;
+    case AFL_EXT_OCTEON2:
+      fputs ("Cavium Networks Octeon2", file);
+      break;
+    case AFL_EXT_OCTEONP:
+      fputs ("Cavium Networks OcteonP", file);
+      break;
+    case AFL_EXT_OCTEON:
+      fputs ("Cavium Networks Octeon", file);
+      break;
+    case AFL_EXT_5900:
+      fputs ("Toshiba R5900", file);
+      break;
+    case AFL_EXT_4650:
+      fputs ("MIPS R4650", file);
+      break;
+    case AFL_EXT_4010:
+      fputs ("LSI R4010", file);
+      break;
+    case AFL_EXT_4100:
+      fputs ("NEC VR4100", file);
+      break;
+    case AFL_EXT_3900:
+      fputs ("Toshiba R3900", file);
+      break;
+    case AFL_EXT_10000:
+      fputs ("MIPS R10000", file);
+      break;
+    case AFL_EXT_SB1:
+      fputs ("Broadcom SB-1", file);
+      break;
+    case AFL_EXT_4111:
+      fputs ("NEC VR4111/VR4181", file);
+      break;
+    case AFL_EXT_4120:
+      fputs ("NEC VR4120", file);
+      break;
+    case AFL_EXT_5400:
+      fputs ("NEC VR5400", file);
+      break;
+    case AFL_EXT_5500:
+      fputs ("NEC VR5500", file);
+      break;
+    case AFL_EXT_LOONGSON_2E:
+      fputs ("ST Microelectronics Loongson 2E", file);
+      break;
+    case AFL_EXT_LOONGSON_2F:
+      fputs ("ST Microelectronics Loongson 2F", file);
+      break;
+    case AFL_EXT_INTERAPTIV_MR2:
+      fputs ("Imagination interAptiv MR2", file);
+      break;
+    default:
+      fprintf (file, "%s (%d)", _("Unknown"), isa_ext);
+      break;
+    }
+}
+
+static void
+print_mips_fp_abi_value (FILE *file, int val)
+{
+  switch (val)
+    {
+    case Val_GNU_MIPS_ABI_FP_ANY:
+      fprintf (file, _("Hard or soft float\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_DOUBLE:
+      fprintf (file, _("Hard float (double precision)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_SINGLE:
+      fprintf (file, _("Hard float (single precision)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_SOFT:
+      fprintf (file, _("Soft float\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_OLD_64:
+      fprintf (file, _("Hard float (MIPS32r2 64-bit FPU 12 callee-saved)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_XX:
+      fprintf (file, _("Hard float (32-bit CPU, Any FPU)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_64:
+      fprintf (file, _("Hard float (32-bit CPU, 64-bit FPU)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_64A:
+      fprintf (file, _("Hard float compat (32-bit CPU, 64-bit FPU)\n"));
+      break;
+    default:
+      fprintf (file, "??? (%d)\n", val);
+      break;
+    }
+}
+
+static int
+get_mips_reg_size (int reg_size)
+{
+  return (reg_size == AFL_REG_NONE) ? 0
+        : (reg_size == AFL_REG_32) ? 32
+        : (reg_size == AFL_REG_64) ? 64
+        : (reg_size == AFL_REG_128) ? 128
+        : -1;
+}
+
 bfd_boolean
 _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
 {
@@ -14248,6 +15879,10 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
     fprintf (file, " [mips32r2]");
   else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R2)
     fprintf (file, " [mips64r2]");
+  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6)
+    fprintf (file, " [mips32r6]");
+  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6)
+    fprintf (file, " [mips64r6]");
   else
     fprintf (file, _(" [unknown ISA]"));
 
@@ -14260,6 +15895,12 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
   if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
     fprintf (file, " [micromips]");
 
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_NAN2008)
+    fprintf (file, " [nan2008]");
+
+  if (elf_elfheader (abfd)->e_flags & EF_MIPS_FP64)
+    fprintf (file, " [old fp64]");
+
   if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
     fprintf (file, " [32bitmode]");
   else
@@ -14282,18 +15923,42 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
 
   fputc ('\n', file);
 
+  if (mips_elf_tdata (abfd)->abiflags_valid)
+    {
+      Elf_Internal_ABIFlags_v0 *abiflags = &mips_elf_tdata (abfd)->abiflags;
+      fprintf (file, "\nMIPS ABI Flags Version: %d\n", abiflags->version);
+      fprintf (file, "\nISA: MIPS%d", abiflags->isa_level);
+      if (abiflags->isa_rev > 1)
+       fprintf (file, "r%d", abiflags->isa_rev);
+      fprintf (file, "\nGPR size: %d",
+              get_mips_reg_size (abiflags->gpr_size));
+      fprintf (file, "\nCPR1 size: %d",
+              get_mips_reg_size (abiflags->cpr1_size));
+      fprintf (file, "\nCPR2 size: %d",
+              get_mips_reg_size (abiflags->cpr2_size));
+      fputs ("\nFP ABI: ", file);
+      print_mips_fp_abi_value (file, abiflags->fp_abi);
+      fputs ("ISA Extension: ", file);
+      print_mips_isa_ext (file, abiflags->isa_ext);
+      fputs ("\nASEs:", file);
+      print_mips_ases (file, abiflags->ases);
+      fprintf (file, "\nFLAGS 1: %8.8lx", abiflags->flags1);
+      fprintf (file, "\nFLAGS 2: %8.8lx", abiflags->flags2);
+      fputc ('\n', file);
+    }
+
   return TRUE;
 }
 
 const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
 {
-  { STRING_COMMA_LEN (".lit4"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
-  { STRING_COMMA_LEN (".lit8"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".lit4"),          0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".lit8"),          0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
   { STRING_COMMA_LEN (".mdebug"), 0, SHT_MIPS_DEBUG, 0 },
-  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+  { STRING_COMMA_LEN (".sbss"),         -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
   { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
   { STRING_COMMA_LEN (".ucode"),  0, SHT_MIPS_UCODE, 0 },
-  { NULL,                     0,  0, 0,              0 }
+  { NULL,                    0,  0, 0,              0 }
 };
 
 /* Merge non visibility st_other attributes.  Ensure that the
@@ -14347,6 +16012,268 @@ _bfd_mips_elf_plt_sym_val (bfd_vma i, const asection *plt,
          + i * 4 * ARRAY_SIZE (mips_exec_plt_entry));
 }
 
+/* Build a table of synthetic symbols to represent the PLT.  As with MIPS16
+   and microMIPS PLT slots we may have a many-to-one mapping between .plt
+   and .got.plt and also the slots may be of a different size each we walk
+   the PLT manually fetching instructions and matching them against known
+   patterns.  To make things easier standard MIPS slots, if any, always come
+   first.  As we don't create proper ELF symbols we use the UDATA.I member
+   of ASYMBOL to carry ISA annotation.  The encoding used is the same as
+   with the ST_OTHER member of the ELF symbol.  */
+
+long
+_bfd_mips_elf_get_synthetic_symtab (bfd *abfd,
+                                   long symcount ATTRIBUTE_UNUSED,
+                                   asymbol **syms ATTRIBUTE_UNUSED,
+                                   long dynsymcount, asymbol **dynsyms,
+                                   asymbol **ret)
+{
+  static const char pltname[] = "_PROCEDURE_LINKAGE_TABLE_";
+  static const char microsuffix[] = "@micromipsplt";
+  static const char m16suffix[] = "@mips16plt";
+  static const char mipssuffix[] = "@plt";
+
+  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  bfd_boolean micromips_p = MICROMIPS_P (abfd);
+  Elf_Internal_Shdr *hdr;
+  bfd_byte *plt_data;
+  bfd_vma plt_offset;
+  unsigned int other;
+  bfd_vma entry_size;
+  bfd_vma plt0_size;
+  asection *relplt;
+  bfd_vma opcode;
+  asection *plt;
+  asymbol *send;
+  size_t size;
+  char *names;
+  long counti;
+  arelent *p;
+  asymbol *s;
+  char *nend;
+  long count;
+  long pi;
+  long i;
+  long n;
+
+  *ret = NULL;
+
+  if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0 || dynsymcount <= 0)
+    return 0;
+
+  relplt = bfd_get_section_by_name (abfd, ".rel.plt");
+  if (relplt == NULL)
+    return 0;
+
+  hdr = &elf_section_data (relplt)->this_hdr;
+  if (hdr->sh_link != elf_dynsymtab (abfd) || hdr->sh_type != SHT_REL)
+    return 0;
+
+  plt = bfd_get_section_by_name (abfd, ".plt");
+  if (plt == NULL)
+    return 0;
+
+  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+  if (!(*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+    return -1;
+  p = relplt->relocation;
+
+  /* Calculating the exact amount of space required for symbols would
+     require two passes over the PLT, so just pessimise assuming two
+     PLT slots per relocation.  */
+  count = relplt->size / hdr->sh_entsize;
+  counti = count * bed->s->int_rels_per_ext_rel;
+  size = 2 * count * sizeof (asymbol);
+  size += count * (sizeof (mipssuffix) +
+                  (micromips_p ? sizeof (microsuffix) : sizeof (m16suffix)));
+  for (pi = 0; pi < counti; pi += bed->s->int_rels_per_ext_rel)
+    size += 2 * strlen ((*p[pi].sym_ptr_ptr)->name);
+
+  /* Add the size of "_PROCEDURE_LINKAGE_TABLE_" too.  */
+  size += sizeof (asymbol) + sizeof (pltname);
+
+  if (!bfd_malloc_and_get_section (abfd, plt, &plt_data))
+    return -1;
+
+  if (plt->size < 16)
+    return -1;
+
+  s = *ret = bfd_malloc (size);
+  if (s == NULL)
+    return -1;
+  send = s + 2 * count + 1;
+
+  names = (char *) send;
+  nend = (char *) s + size;
+  n = 0;
+
+  opcode = bfd_get_micromips_32 (abfd, plt_data + 12);
+  if (opcode == 0x3302fffe)
+    {
+      if (!micromips_p)
+       return -1;
+      plt0_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry);
+      other = STO_MICROMIPS;
+    }
+  else if (opcode == 0x0398c1d0)
+    {
+      if (!micromips_p)
+       return -1;
+      plt0_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry);
+      other = STO_MICROMIPS;
+    }
+  else
+    {
+      plt0_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry);
+      other = 0;
+    }
+
+  s->the_bfd = abfd;
+  s->flags = BSF_SYNTHETIC | BSF_FUNCTION | BSF_LOCAL;
+  s->section = plt;
+  s->value = 0;
+  s->name = names;
+  s->udata.i = other;
+  memcpy (names, pltname, sizeof (pltname));
+  names += sizeof (pltname);
+  ++s, ++n;
+
+  pi = 0;
+  for (plt_offset = plt0_size;
+       plt_offset + 8 <= plt->size && s < send;
+       plt_offset += entry_size)
+    {
+      bfd_vma gotplt_addr;
+      const char *suffix;
+      bfd_vma gotplt_hi;
+      bfd_vma gotplt_lo;
+      size_t suffixlen;
+
+      opcode = bfd_get_micromips_32 (abfd, plt_data + plt_offset + 4);
+
+      /* Check if the second word matches the expected MIPS16 instruction.  */
+      if (opcode == 0x651aeb00)
+       {
+         if (micromips_p)
+           return -1;
+         /* Truncated table???  */
+         if (plt_offset + 16 > plt->size)
+           break;
+         gotplt_addr = bfd_get_32 (abfd, plt_data + plt_offset + 12);
+         entry_size = 2 * ARRAY_SIZE (mips16_o32_exec_plt_entry);
+         suffixlen = sizeof (m16suffix);
+         suffix = m16suffix;
+         other = STO_MIPS16;
+       }
+      /* Likewise the expected microMIPS instruction (no insn32 mode).  */
+      else if (opcode == 0xff220000)
+       {
+         if (!micromips_p)
+           return -1;
+         gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset) & 0x7f;
+         gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff;
+         gotplt_hi = ((gotplt_hi ^ 0x40) - 0x40) << 18;
+         gotplt_lo <<= 2;
+         gotplt_addr = gotplt_hi + gotplt_lo;
+         gotplt_addr += ((plt->vma + plt_offset) | 3) ^ 3;
+         entry_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt_entry);
+         suffixlen = sizeof (microsuffix);
+         suffix = microsuffix;
+         other = STO_MICROMIPS;
+       }
+      /* Likewise the expected microMIPS instruction (insn32 mode).  */
+      else if ((opcode & 0xffff0000) == 0xff2f0000)
+       {
+         gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff;
+         gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 6) & 0xffff;
+         gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16;
+         gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000;
+         gotplt_addr = gotplt_hi + gotplt_lo;
+         entry_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt_entry);
+         suffixlen = sizeof (microsuffix);
+         suffix = microsuffix;
+         other = STO_MICROMIPS;
+       }
+      /* Otherwise assume standard MIPS code.  */
+      else
+       {
+         gotplt_hi = bfd_get_32 (abfd, plt_data + plt_offset) & 0xffff;
+         gotplt_lo = bfd_get_32 (abfd, plt_data + plt_offset + 4) & 0xffff;
+         gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16;
+         gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000;
+         gotplt_addr = gotplt_hi + gotplt_lo;
+         entry_size = 4 * ARRAY_SIZE (mips_exec_plt_entry);
+         suffixlen = sizeof (mipssuffix);
+         suffix = mipssuffix;
+         other = 0;
+       }
+      /* Truncated table???  */
+      if (plt_offset + entry_size > plt->size)
+       break;
+
+      for (i = 0;
+          i < count && p[pi].address != gotplt_addr;
+          i++, pi = (pi + bed->s->int_rels_per_ext_rel) % counti);
+
+      if (i < count)
+       {
+         size_t namelen;
+         size_t len;
+
+         *s = **p[pi].sym_ptr_ptr;
+         /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
+            we are defining a symbol, ensure one of them is set.  */
+         if ((s->flags & BSF_LOCAL) == 0)
+           s->flags |= BSF_GLOBAL;
+         s->flags |= BSF_SYNTHETIC;
+         s->section = plt;
+         s->value = plt_offset;
+         s->name = names;
+         s->udata.i = other;
+
+         len = strlen ((*p[pi].sym_ptr_ptr)->name);
+         namelen = len + suffixlen;
+         if (names + namelen > nend)
+           break;
+
+         memcpy (names, (*p[pi].sym_ptr_ptr)->name, len);
+         names += len;
+         memcpy (names, suffix, suffixlen);
+         names += suffixlen;
+
+         ++s, ++n;
+         pi = (pi + bed->s->int_rels_per_ext_rel) % counti;
+       }
+    }
+
+  free (plt_data);
+
+  return n;
+}
+
+/* Return the ABI flags associated with ABFD if available.  */
+
+Elf_Internal_ABIFlags_v0 *
+bfd_mips_elf_get_abiflags (bfd *abfd)
+{
+  struct mips_elf_obj_tdata *tdata = mips_elf_tdata (abfd);
+
+  return tdata->abiflags_valid ? &tdata->abiflags : NULL;
+}
+
+/* MIPS libc ABI versions, used with the EI_ABIVERSION ELF file header
+   field.  Taken from `libc-abis.h' generated at GNU libc build time.
+   Using a MIPS_ prefix as other libc targets use different values.  */
+enum
+{
+  MIPS_LIBC_ABI_DEFAULT = 0,
+  MIPS_LIBC_ABI_MIPS_PLT,
+  MIPS_LIBC_ABI_UNIQUE,
+  MIPS_LIBC_ABI_MIPS_O32_FP64,
+  MIPS_LIBC_ABI_MAX
+};
+
 void
 _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
 {
@@ -14360,6 +16287,28 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
       BFD_ASSERT (htab != NULL);
 
       if (htab->use_plts_and_copy_relocs && !htab->is_vxworks)
-       i_ehdrp->e_ident[EI_ABIVERSION] = 1;
+       i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
     }
+
+  if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64
+      || mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_O32_FP64;
+
+  _bfd_elf_post_process_headers (abfd, link_info);
+}
+
+int
+_bfd_mips_elf_compact_eh_encoding
+  (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+{
+  return DW_EH_PE_pcrel | DW_EH_PE_sdata4;
+}
+
+/* Return the opcode for can't unwind.  */
+
+int
+_bfd_mips_elf_cant_unwind_opcode
+  (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+{
+  return COMPACT_EH_CANT_UNWIND_OPCODE;
 }
This page took 0.129906 seconds and 4 git commands to generate.