]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elfxx-mips.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / bfd / elfxx-mips.c
index d91942301c3223b615c81e1b362e44452dcd7a73..3cbb3cf949541e076b2954b2cb32492106e1d2ae 100644 (file)
@@ -1,5 +1,5 @@
 /* MIPS-specific support for ELF
-   Copyright (C) 1993-2018 Free Software Foundation, Inc.
+   Copyright (C) 1993-2021 Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
@@ -33,6 +33,7 @@
 #include "libbfd.h"
 #include "libiberty.h"
 #include "elf-bfd.h"
+#include "ecoff-bfd.h"
 #include "elfxx-mips.h"
 #include "elf/mips.h"
 #include "elf-vxworks.h"
@@ -292,6 +293,7 @@ struct mips_elf_la25_stub {
 
 #define LA25_LUI(VAL) (0x3c190000 | (VAL))     /* lui t9,VAL */
 #define LA25_J(VAL) (0x08000000 | (((VAL) >> 2) & 0x3ffffff)) /* j VAL */
+#define LA25_BC(VAL) (0xc8000000 | (((VAL) >> 2) & 0x3ffffff)) /* bc VAL */
 #define LA25_ADDIU(VAL) (0x27390000 | (VAL))   /* addiu t9,t9,VAL */
 #define LA25_LUI_MICROMIPS(VAL)                                                \
   (0x41b90000 | (VAL))                         /* lui t9,VAL */
@@ -321,6 +323,11 @@ struct mips_elf_hash_sort_data
   /* The greatest dynamic symbol table index corresponding to an external
      symbol without a GOT entry.  */
   bfd_size_type max_non_got_dynindx;
+  /* If non-NULL, output BFD for .MIPS.xhash finalization.  */
+  bfd *output_bfd;
+  /* If non-NULL, pointer to contents of .MIPS.xhash for filling in
+     real final dynindx.  */
+  bfd_byte *mipsxhash;
 };
 
 /* We make up to two PLT entries if needed, one for standard MIPS code
@@ -378,6 +385,9 @@ struct mips_elf_link_hash_entry
      being called returns a floating point value.  */
   asection *call_fp_stub;
 
+  /* If non-zero, location in .MIPS.xhash to write real final dynindx.  */
+  bfd_vma mipsxhash_loc;
+
   /* The highest GGA_* value that satisfies all references to this symbol.  */
   unsigned int global_got_area : 2;
 
@@ -449,12 +459,18 @@ struct mips_elf_link_hash_table
   /* 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;
+  /* True if we are targetting R6 compact branches.  */
+  bfd_boolean compact_branches;
 
   /* True if we already reported the small-data section overflow.  */
   bfd_boolean small_data_overflow_reported;
 
+  /* True if we use the special `__gnu_absolute_zero' symbol.  */
+  bfd_boolean use_absolute_zero;
+
+  /* True if we have been configured for a GNU target.  */
+  bfd_boolean gnu_target;
+
   /* Shortcuts to some dynamic sections, or NULL if they are not
      being used.  */
   asection *srelplt2;
@@ -511,9 +527,6 @@ struct mips_elf_link_hash_table
      returns null.  */
   asection *(*add_stub_section) (const char *, asection *, asection *);
 
-  /* Small local sym cache.  */
-  struct sym_cache sym_cache;
-
   /* Is the PLT header compressed?  */
   unsigned int plt_header_is_comp : 1;
 };
@@ -521,8 +534,9 @@ struct mips_elf_link_hash_table
 /* Get the MIPS ELF linker hash table from a link_info structure.  */
 
 #define mips_elf_hash_table(p) \
-  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
-  == MIPS_ELF_DATA ? ((struct mips_elf_link_hash_table *) ((p)->hash)) : NULL)
+  ((is_elf_hash_table ((p)->hash)                                      \
+    && elf_hash_table_id (elf_hash_table (p)) == MIPS_ELF_DATA)                \
+   ? (struct mips_elf_link_hash_table *) (p)->hash : NULL)
 
 /* A structure used to communicate with htab_traverse callbacks.  */
 struct mips_htab_traverse_info
@@ -684,13 +698,13 @@ typedef struct
 
 /* These are the constants used to swap the bitfields in a crinfo.  */
 
-#define CRINFO_CTYPE (0x1)
+#define CRINFO_CTYPE (0x1U)
 #define CRINFO_CTYPE_SH (31)
-#define CRINFO_RTYPE (0xf)
+#define CRINFO_RTYPE (0xfU)
 #define CRINFO_RTYPE_SH (27)
-#define CRINFO_DIST2TO (0xff)
+#define CRINFO_DIST2TO (0xffU)
 #define CRINFO_DIST2TO_SH (19)
-#define CRINFO_RELVADDR (0x7ffff)
+#define CRINFO_RELVADDR (0x7ffffU)
 #define CRINFO_RELVADDR_SH (0)
 
 /* A compact relocation info has long (3 words) or short (2 words)
@@ -885,7 +899,8 @@ static bfd *reldyn_sorting_bfd;
 
 /* The name of the dynamic relocation section.  */
 #define MIPS_ELF_REL_DYN_NAME(INFO) \
-  (mips_elf_hash_table (INFO)->is_vxworks ? ".rela.dyn" : ".rel.dyn")
+  (mips_elf_hash_table (INFO)->root.target_os == is_vxworks \
+   ? ".rela.dyn" : ".rel.dyn")
 
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value
    from smaller values.  Start with zero, widen, *then* decrement.  */
@@ -900,7 +915,8 @@ static bfd *reldyn_sorting_bfd;
 
 /* The offset of $gp from the beginning of the .got section.  */
 #define ELF_MIPS_GP_OFFSET(INFO) \
-  (mips_elf_hash_table (INFO)->is_vxworks ? 0x0 : 0x7ff0)
+  (mips_elf_hash_table (INFO)->root.target_os == is_vxworks \
+   ? 0x0 : 0x7ff0)
 
 /* The maximum size of the GOT for it to be addressable using 16-bit
    offsets from $gp.  */
@@ -914,6 +930,7 @@ static bfd *reldyn_sorting_bfd;
 #define STUB_MOVE 0x03e07825                   /* or t7,ra,zero */
 #define STUB_LUI(VAL) (0x3c180000 + (VAL))     /* lui t8,VAL */
 #define STUB_JALR 0x0320f809                   /* jalr ra,t9 */
+#define STUB_JALRC 0xf8190000                  /* jalrc 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)                                          \
@@ -1030,6 +1047,20 @@ static const bfd_vma mips_o32_exec_plt0_entry[] =
   0x2718fffe   /* subu $24, $24, 2                                     */
 };
 
+/* The format of the first PLT entry in an O32 executable using compact
+   jumps.  */
+static const bfd_vma mipsr6_o32_exec_plt0_entry_compact[] =
+{
+  0x3c1c0000,  /* lui $28, %hi(&GOTPLT[0])                             */
+  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)            */
+  0x0018c082,  /* srl $24, $24, 2                                      */
+  0x2718fffe,  /* subu $24, $24, 2                                     */
+  0xf8190000   /* jalrc $25                                            */
+};
+
 /* The format of the first PLT entry in an N32 executable.  Different
    because gp ($28) is not available; we use t2 ($14) instead.  */
 static const bfd_vma mips_n32_exec_plt0_entry[] =
@@ -1044,6 +1075,21 @@ static const bfd_vma mips_n32_exec_plt0_entry[] =
   0x2718fffe   /* subu $24, $24, 2                                     */
 };
 
+/* The format of the first PLT entry in an N32 executable using compact
+   jumps.  Different because gp ($28) is not available; we use t2 ($14)
+   instead.  */
+static const bfd_vma mipsr6_n32_exec_plt0_entry_compact[] =
+{
+  0x3c0e0000,  /* lui $14, %hi(&GOTPLT[0])                             */
+  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)            */
+  0x0018c082,  /* srl $24, $24, 2                                      */
+  0x2718fffe,  /* subu $24, $24, 2                                     */
+  0xf8190000   /* jalrc $25                                            */
+};
+
 /* The format of the first PLT entry in an N64 executable.  Different
    from N32 because of the increased size of GOT entries.  */
 static const bfd_vma mips_n64_exec_plt0_entry[] =
@@ -1058,6 +1104,22 @@ static const bfd_vma mips_n64_exec_plt0_entry[] =
   0x2718fffe   /* subu $24, $24, 2                                     */
 };
 
+/* The format of the first PLT entry in an N64 executable using compact
+   jumps.  Different from N32 because of the increased size of GOT
+   entries.  */
+static const bfd_vma mipsr6_n64_exec_plt0_entry_compact[] =
+{
+  0x3c0e0000,  /* lui $14, %hi(&GOTPLT[0])                             */
+  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)           */
+  0x0018c0c2,  /* srl $24, $24, 3                                      */
+  0x2718fffe,  /* subu $24, $24, 2                                     */
+  0xf8190000   /* jalrc $25                                            */
+};
+
+
 /* 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
@@ -1100,9 +1162,6 @@ 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)                 */
@@ -1111,6 +1170,14 @@ static const bfd_vma mipsr6_exec_plt_entry[] =
   0x03200009   /* jr $25                                       */
 };
 
+static const bfd_vma mipsr6_exec_plt_entry_compact[] =
+{
+  0x3c0f0000,  /* lui $15, %hi(.got.plt entry)                 */
+  0x01f90000,  /* l[wd] $25, %lo(.got.plt entry)($15)          */
+  0x25f80000,  /* addiu $24, $15, %lo(.got.plt entry)          */
+  0xd8190000   /* jic $25, 0                                   */
+};
+
 /* 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.  */
@@ -1274,6 +1341,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       ret->fn_stub = NULL;
       ret->call_stub = NULL;
       ret->call_fp_stub = NULL;
+      ret->mipsxhash_loc = 0;
       ret->global_got_area = GGA_NONE;
       ret->got_only_for_calls = TRUE;
       ret->readonly_reloc = FALSE;
@@ -1303,7 +1371,7 @@ _bfd_mips_elf_new_section_hook (bfd *abfd, asection *sec)
   if (!sec->used_by_bfd)
     {
       struct _mips_elf_section_data *sdata;
-      bfd_size_type amt = sizeof (*sdata);
+      size_t amt = sizeof (*sdata);
 
       sdata = bfd_zalloc (abfd, amt);
       if (sdata == NULL)
@@ -1342,18 +1410,23 @@ _bfd_mips_elf_read_ecoff_info (bfd *abfd, asection *section,
   /* The symbolic header contains absolute file offsets and sizes to
      read.  */
 #define READ(ptr, offset, count, size, type)                           \
-  if (symhdr->count == 0)                                              \
-    debug->ptr = NULL;                                                 \
-  else                                                                 \
+  do                                                                   \
     {                                                                  \
-      bfd_size_type amt = (bfd_size_type) size * symhdr->count;                \
-      debug->ptr = bfd_malloc (amt);                                   \
-      if (debug->ptr == NULL)                                          \
+      size_t amt;                                                      \
+      debug->ptr = NULL;                                               \
+      if (symhdr->count == 0)                                          \
+       break;                                                          \
+      if (_bfd_mul_overflow (size, symhdr->count, &amt))               \
+       {                                                               \
+         bfd_set_error (bfd_error_file_too_big);                       \
+         goto error_return;                                            \
+       }                                                               \
+      if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0)              \
        goto error_return;                                              \
-      if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0               \
-         || bfd_bread (debug->ptr, amt, abfd) != amt)                  \
+      debug->ptr = (type) _bfd_malloc_and_read (abfd, amt, amt);       \
+      if (debug->ptr == NULL)                                          \
        goto error_return;                                              \
-    }
+    } while (0)
 
   READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
   READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *);
@@ -1374,30 +1447,18 @@ _bfd_mips_elf_read_ecoff_info (bfd *abfd, asection *section,
   return TRUE;
 
  error_return:
-  if (ext_hdr != NULL)
-    free (ext_hdr);
-  if (debug->line != NULL)
-    free (debug->line);
-  if (debug->external_dnr != NULL)
-    free (debug->external_dnr);
-  if (debug->external_pdr != NULL)
-    free (debug->external_pdr);
-  if (debug->external_sym != NULL)
-    free (debug->external_sym);
-  if (debug->external_opt != NULL)
-    free (debug->external_opt);
-  if (debug->external_aux != NULL)
-    free (debug->external_aux);
-  if (debug->ss != NULL)
-    free (debug->ss);
-  if (debug->ssext != NULL)
-    free (debug->ssext);
-  if (debug->external_fdr != NULL)
-    free (debug->external_fdr);
-  if (debug->external_rfd != NULL)
-    free (debug->external_rfd);
-  if (debug->external_ext != NULL)
-    free (debug->external_ext);
+  free (ext_hdr);
+  free (debug->line);
+  free (debug->external_dnr);
+  free (debug->external_pdr);
+  free (debug->external_sym);
+  free (debug->external_opt);
+  free (debug->external_aux);
+  free (debug->ss);
+  free (debug->ssext);
+  free (debug->external_fdr);
+  free (debug->external_rfd);
+  free (debug->external_ext);
   return FALSE;
 }
 \f
@@ -1542,30 +1603,19 @@ mips_elf_create_procedure_table (void *handle, bfd *abfd,
      matters, but someday it might).  */
   s->map_head.link_order = NULL;
 
-  if (epdr != NULL)
-    free (epdr);
-  if (rpdr != NULL)
-    free (rpdr);
-  if (esym != NULL)
-    free (esym);
-  if (ss != NULL)
-    free (ss);
-  if (sv != NULL)
-    free (sv);
-
+  free (epdr);
+  free (rpdr);
+  free (esym);
+  free (ss);
+  free (sv);
   return TRUE;
 
  error_return:
-  if (epdr != NULL)
-    free (epdr);
-  if (rpdr != NULL)
-    free (rpdr);
-  if (esym != NULL)
-    free (esym);
-  if (ss != NULL)
-    free (ss);
-  if (sv != NULL)
-    free (sv);
+  free (epdr);
+  free (rpdr);
+  free (esym);
+  free (ss);
+  free (sv);
   return FALSE;
 }
 \f
@@ -1656,7 +1706,7 @@ section_allows_mips16_refs_p (asection *section)
 {
   const char *name;
 
-  name = bfd_get_section_name (section->owner, section);
+  name = bfd_section_name (section);
   return (FN_STUB_P (name)
          || CALL_STUB_P (name)
          || CALL_FP_STUB_P (name)
@@ -1867,7 +1917,7 @@ mips_elf_add_la25_intro (struct mips_elf_la25_stub *stub,
 
   /* Make sure that any padding goes before the stub.  */
   align = input_section->alignment_power;
-  if (!bfd_set_section_alignment (s->owner, s, align))
+  if (!bfd_set_section_alignment (s, align))
     return FALSE;
   if (align > 3)
     s->size = (1 << align) - 8;
@@ -1904,7 +1954,7 @@ mips_elf_add_la25_trampoline (struct mips_elf_la25_stub *stub,
       asection *input_section = stub->h->root.root.u.def.section;
       s = htab->add_stub_section (".text", NULL,
                                  input_section->output_section);
-      if (s == NULL || !bfd_set_section_alignment (s->owner, s, 4))
+      if (s == NULL || !bfd_set_section_alignment (s, 4))
        return FALSE;
       htab->strampoline = s;
     }
@@ -2461,8 +2511,8 @@ _bfd_mips_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                           bfd *output_bfd, char **error_message)
 {
   if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
-      || bfd_is_und_section (bfd_get_section (symbol))
-      || bfd_is_com_section (bfd_get_section (symbol)))
+      || bfd_is_und_section (bfd_asymbol_section (symbol))
+      || bfd_is_com_section (bfd_asymbol_section (symbol)))
     /* The relocation is against a global symbol.  */
     return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                                        input_section, output_bfd,
@@ -2922,7 +2972,7 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
            h->esym.asym.sc = scUndefined;
          else
            {
-             name = bfd_section_name (output_section->owner, output_section);
+             name = bfd_section_name (output_section);
 
              if (strcmp (name, ".text") == 0)
                h->esym.asym.sc = scText;
@@ -3195,8 +3245,8 @@ mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p)
                                                    | SEC_LINKER_CREATED
                                                    | SEC_READONLY));
       if (sreloc == NULL
-         || ! bfd_set_section_alignment (dynobj, sreloc,
-                                         MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
+         || !bfd_set_section_alignment (sreloc,
+                                        MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
        return NULL;
     }
   return sreloc;
@@ -3768,7 +3818,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
   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)
+  if (htab->root.target_os == is_vxworks)
     {
       Elf_Internal_Rela outrel;
       asection *s;
@@ -3846,6 +3896,18 @@ mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
      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;
+  hsd.output_bfd = abfd;
+  if (htab->root.dynobj != NULL
+      && htab->root.dynamic_sections_created
+      && info->emit_gnu_hash)
+    {
+      asection *s = bfd_get_linker_section (htab->root.dynobj, ".MIPS.xhash");
+      BFD_ASSERT (s != NULL);
+      hsd.mipsxhash = s->contents;
+      BFD_ASSERT (hsd.mipsxhash != NULL);
+    }
+  else
+    hsd.mipsxhash = NULL;
   mips_elf_link_hash_traverse (htab, mips_elf_sort_hash_table_f, &hsd);
 
   /* There should have been enough room in the symbol table to
@@ -3897,6 +3959,12 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
       break;
     }
 
+  /* Populate the .MIPS.xhash translation table entry with
+     the symbol dynindx.  */
+  if (h->mipsxhash_loc != 0 && hsd->mipsxhash != NULL)
+    bfd_put_32 (hsd->output_bfd, h->root.dynindx,
+               hsd->mipsxhash + h->mipsxhash_loc);
+
   return TRUE;
 }
 
@@ -3977,7 +4045,7 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
        {
        case STV_INTERNAL:
        case STV_HIDDEN:
-         _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+         _bfd_mips_elf_hide_symbol (info, h, TRUE);
          break;
        }
       if (!bfd_elf_link_record_dynamic_symbol (info, h))
@@ -4095,7 +4163,7 @@ mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
   s = mips_elf_rel_dyn_section (info, FALSE);
   BFD_ASSERT (s != NULL);
 
-  if (htab->is_vxworks)
+  if (htab->root.target_os == is_vxworks)
     s->size += n * MIPS_ELF_RELA_SIZE (abfd);
   else
     {
@@ -4331,7 +4399,7 @@ mips_elf_resolve_got_page_ref (void **refp, void *data)
       Elf_Internal_Sym *isym;
 
       /* Read in the symbol.  */
-      isym = bfd_sym_from_r_symndx (&htab->sym_cache, ref->u.abfd,
+      isym = bfd_sym_from_r_symndx (&htab->root.sym_cache, ref->u.abfd,
                                    ref->symndx);
       if (isym == NULL)
        {
@@ -4434,6 +4502,12 @@ mips_use_local_got_p (struct bfd_link_info *info,
   if (h->root.dynindx == -1)
     return TRUE;
 
+  /* Absolute symbols, if ever they need a GOT entry, cannot ever go
+     to the local GOT, as they would be implicitly relocated by the
+     base address by the dynamic loader.  */
+  if (bfd_is_abs_symbol (&h->root.root))
+    return FALSE;
+
   /* 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
@@ -4475,7 +4549,7 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
           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
+      else if (htab->root.target_os == is_vxworks
               && h->got_only_for_calls
               && h->root.plt.plist->mips_offset != MINUS_ONE)
        /* On VxWorks, calls can refer directly to the .got.plt entry;
@@ -5107,8 +5181,7 @@ mips_elf_create_compact_rel_section
 
       s = bfd_make_section_anyway_with_flags (abfd, ".compact_rel", flags);
       if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s,
-                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+         || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return FALSE;
 
       s->size = sizeof (Elf32_External_compact_rel);
@@ -5142,7 +5215,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
      in the function stub generation and in the linker script.  */
   s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
   if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s, 4))
+      || !bfd_set_section_alignment (s, 4))
     return FALSE;
   htab->root.sgot = s;
 
@@ -5190,7 +5263,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
 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
+  return (mips_elf_hash_table (info)->root.target_os == is_vxworks
          && bfd_link_pic (info)
          && (strcmp (h->root.root.string, "__GOTT_BASE__") == 0
              || strcmp (h->root.root.string, "__GOTT_INDEX__") == 0));
@@ -5234,6 +5307,85 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
     }
 }
 \f
+/* Obtain the field relocated by RELOCATION.  */
+
+static bfd_vma
+mips_elf_obtain_contents (reloc_howto_type *howto,
+                         const Elf_Internal_Rela *relocation,
+                         bfd *input_bfd, bfd_byte *contents)
+{
+  bfd_vma x = 0;
+  bfd_byte *location = contents + relocation->r_offset;
+  unsigned int size = bfd_get_reloc_size (howto);
+
+  /* Obtain the bytes.  */
+  if (size != 0)
+    x = bfd_get (8 * size, input_bfd, location);
+
+  return x;
+}
+
+/* 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);
+}
+
+/* Try to patch a load from GOT instruction in CONTENTS pointed to by
+   RELOCATION described by HOWTO, with a move of 0 to the load target
+   register, returning TRUE if that is successful and FALSE otherwise.
+   If DOIT is FALSE, then only determine it patching is possible and
+   return status without actually changing CONTENTS.
+*/
+
+static bfd_boolean
+mips_elf_nullify_got_load (bfd *input_bfd, bfd_byte *contents,
+                          const Elf_Internal_Rela *relocation,
+                          reloc_howto_type *howto, bfd_boolean doit)
+{
+  int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
+  bfd_byte *location = contents + relocation->r_offset;
+  bfd_boolean nullified = TRUE;
+  bfd_vma x;
+
+  _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
+
+  /* Obtain the current value.  */
+  x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
+
+  /* Note that in the unshuffled MIPS16 encoding RX is at bits [21:19]
+     while RY is at bits [18:16] of the combined 32-bit instruction word.  */
+  if (mips16_reloc_p (r_type)
+      && (((x >> 22) & 0x3ff) == 0x3d3                         /* LW */
+         || ((x >> 22) & 0x3ff) == 0x3c7))                     /* LD */
+    x = (0x3cdU << 22) | (x & (7 << 16)) << 3;                 /* LI */
+  else if (micromips_reloc_p (r_type)
+          && ((x >> 26) & 0x37) == 0x37)                       /* LW/LD */
+    x = (0xc << 26) | (x & (0x1f << 21));                      /* ADDIU */
+  else if (((x >> 26) & 0x3f) == 0x23                          /* LW */
+          || ((x >> 26) & 0x3f) == 0x37)                       /* LD */
+    x = (0x9 << 26) | (x & (0x1f << 16));                      /* ADDIU */
+  else
+    nullified = FALSE;
+
+  /* Put the value into the output.  */
+  if (doit && nullified)
+    mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
+
+  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, FALSE, location);
+
+  return nullified;
+}
+
 /* 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.
@@ -5249,7 +5401,7 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
 
 static bfd_reloc_status_type
 mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
-                              asection *input_section,
+                              asection *input_section, bfd_byte *contents,
                               struct bfd_link_info *info,
                               const Elf_Internal_Rela *relocation,
                               bfd_vma addend, reloc_howto_type *howto,
@@ -5364,7 +5516,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
                                                symtab_hdr->sh_link,
                                                sym->st_name);
       if (*namep == NULL || **namep == '\0')
-       *namep = bfd_section_name (input_bfd, sec);
+       *namep = bfd_section_name (sec);
 
       /* For relocations against a section symbol and ones against no
         symbol (absolute relocations) infer the ISA mode from the addend.  */
@@ -5471,11 +5623,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        }
       else
        {
-         bfd_boolean reject_undefined
-           = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
-              || ELF_ST_VISIBILITY (h->root.other) != STV_DEFAULT);
+          bfd_boolean reject_undefined
+           = (info->unresolved_syms_in_objects == RM_DIAGNOSE
+              && !info->warn_unresolved_syms)
+           || ELF_ST_VISIBILITY (h->root.other) != STV_DEFAULT;
 
-         (*info->callbacks->undefined_symbol)
+         info->callbacks->undefined_symbol
            (info, h->root.root.root.string, input_bfd,
             input_section, relocation->r_offset, reject_undefined);
 
@@ -5562,7 +5715,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
              sec = NULL;
              for (o = input_bfd->sections; o != NULL; o = o->next)
                {
-                 if (CALL_FP_STUB_P (bfd_get_section_name (input_bfd, o)))
+                 if (CALL_FP_STUB_P (bfd_section_name (o)))
                    {
                      sec = h->call_fp_stub;
                      break;
@@ -5645,6 +5798,48 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
                                && (target_is_16_bit_code_p
                                    || target_is_micromips_code_p))));
 
+  resolved_to_zero = (h != NULL
+                     && UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->root));
+
+  switch (r_type)
+    {
+    case R_MIPS16_CALL16:
+    case R_MIPS16_GOT16:
+    case R_MIPS_CALL16:
+    case R_MIPS_GOT16:
+    case R_MIPS_GOT_PAGE:
+    case R_MIPS_GOT_DISP:
+    case R_MIPS_GOT_LO16:
+    case R_MIPS_CALL_LO16:
+    case R_MICROMIPS_CALL16:
+    case R_MICROMIPS_GOT16:
+    case R_MICROMIPS_GOT_PAGE:
+    case R_MICROMIPS_GOT_DISP:
+    case R_MICROMIPS_GOT_LO16:
+    case R_MICROMIPS_CALL_LO16:
+      if (resolved_to_zero
+         && !bfd_link_relocatable (info)
+         && mips_elf_nullify_got_load (input_bfd, contents,
+                                       relocation, howto, TRUE))
+       return bfd_reloc_continue;
+
+      /* Fall through.  */
+    case R_MIPS_GOT_HI16:
+    case R_MIPS_CALL_HI16:
+    case R_MICROMIPS_GOT_HI16:
+    case R_MICROMIPS_CALL_HI16:
+      if (resolved_to_zero
+         && htab->use_absolute_zero
+         && bfd_link_pic (info))
+       {
+         /* Redirect to the special `__gnu_absolute_zero' symbol.  */
+         h = mips_elf_link_hash_lookup (htab, "__gnu_absolute_zero",
+                                        FALSE, FALSE, FALSE);
+         BFD_ASSERT (h != NULL);
+       }
+      break;
+    }
+
   local_p = (h == NULL || mips_use_local_got_p (info, h));
 
   gp0 = _bfd_get_gp_value (input_bfd);
@@ -5665,10 +5860,6 @@ 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)
@@ -5710,7 +5901,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        {
          /* On VxWorks, CALL relocations should refer to the .got.plt
             entry, which is initialized to point at the PLT stub.  */
-         if (htab->is_vxworks
+         if (htab->root.target_os == is_vxworks
              && (call_hi16_reloc_p (r_type)
                  || call_lo16_reloc_p (r_type)
                  || call16_reloc_p (r_type)))
@@ -5730,7 +5921,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
                MIPS_ELF_PUT_WORD (dynobj, symbol, htab->root.sgot->contents + g);
            }
        }
-      else if (!htab->is_vxworks
+      else if (htab->root.target_os != is_vxworks
               && (call16_reloc_p (r_type) || got16_reloc_p (r_type)))
        /* The calculation below does not involve "g".  */
        break;
@@ -6012,7 +6203,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MICROMIPS_CALL16:
       /* VxWorks does not have separate local and global semantics for
         R_MIPS*_GOT16; every relocation evaluates to "G".  */
-      if (!htab->is_vxworks && local_p)
+      if (htab->root.target_os != is_vxworks && local_p)
        {
          value = mips_elf_got16_entry (abfd, input_bfd, info,
                                        symbol + addend, !was_local_p);
@@ -6142,8 +6333,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
 
     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;
 
@@ -6308,24 +6497,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok;
 }
 
-/* Obtain the field relocated by RELOCATION.  */
-
-static bfd_vma
-mips_elf_obtain_contents (reloc_howto_type *howto,
-                         const Elf_Internal_Rela *relocation,
-                         bfd *input_bfd, bfd_byte *contents)
-{
-  bfd_vma x = 0;
-  bfd_byte *location = contents + relocation->r_offset;
-  unsigned int size = bfd_get_reloc_size (howto);
-
-  /* Obtain the bytes.  */
-  if (size != 0)
-    x = bfd_get (8 * size, input_bfd, location);
-
-  return x;
-}
-
 /* It has been determined that the result of the RELOCATION is the
    VALUE.  Use HOWTO to place VALUE into the output file at the
    appropriate position.  The SECTION is the section to which the
@@ -6346,7 +6517,6 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
   bfd_vma x;
   bfd_byte *location;
   int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
-  unsigned int size;
 
   /* Figure out where the relocation is occurring.  */
   location = contents + relocation->r_offset;
@@ -6412,7 +6582,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
        }
 
       /* Make this the JALX opcode.  */
-      x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
+      x = (x & ~(0x3fu << 26)) | (jalx_opcode << 26);
     }
   else if (cross_mode_jump_p && b_reloc_p (r_type))
     {
@@ -6505,9 +6675,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
     }
 
   /* Put the value into the output.  */
-  size = bfd_get_reloc_size (howto);
-  if (size != 0)
-    bfd_put (8 * size, input_bfd, x, location);
+  mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
 
   _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info),
                               location);
@@ -6574,7 +6742,8 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
      in the relocation.  */
   if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root))
     {
-      BFD_ASSERT (htab->is_vxworks || h->global_got_area != GGA_NONE);
+      BFD_ASSERT (htab->root.target_os == is_vxworks
+                 || h->global_got_area != GGA_NONE);
       indx = h->root.dynindx;
       if (SGI_COMPAT (output_bfd))
        defined_p = h->root.def_regular;
@@ -6633,7 +6802,7 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
   if (defined_p && r_type != R_MIPS_REL32)
     *addendp += symbol;
 
-  if (htab->is_vxworks)
+  if (htab->root.target_os == is_vxworks)
     /* VxWorks uses non-relative relocations for this.  */
     outrel[0].r_info = ELF32_R_INFO (indx, R_MIPS_32);
   else
@@ -6679,7 +6848,7 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
         (sreloc->contents
          + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
     }
-  else if (htab->is_vxworks)
+  else if (htab->root.target_os == is_vxworks)
     {
       /* VxWorks uses RELA rather than REL dynamic relocations.  */
       outrel[0].r_addend = *addendp;
@@ -6787,8 +6956,14 @@ _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;
@@ -6883,15 +7058,21 @@ elf_mips_abi_name (bfd *abfd)
    faster assembler code.  This is what we use for the small common
    section.  This approach is copied from ecoff.c.  */
 static asection mips_elf_scom_section;
-static asymbol mips_elf_scom_symbol;
-static asymbol *mips_elf_scom_symbol_ptr;
+static const asymbol mips_elf_scom_symbol =
+  GLOBAL_SYM_INIT (".scommon", &mips_elf_scom_section);
+static asection mips_elf_scom_section =
+  BFD_FAKE_SECTION (mips_elf_scom_section, &mips_elf_scom_symbol,
+                   ".scommon", 0, SEC_IS_COMMON | SEC_SMALL_DATA);
 
 /* MIPS ELF also uses an acommon section, which represents an
    allocated common symbol which may be overridden by a
    definition in a shared library.  */
 static asection mips_elf_acom_section;
-static asymbol mips_elf_acom_symbol;
-static asymbol *mips_elf_acom_symbol_ptr;
+static const asymbol mips_elf_acom_symbol =
+  GLOBAL_SYM_INIT (".acommon", &mips_elf_acom_section);
+static asection mips_elf_acom_section =
+  BFD_FAKE_SECTION (mips_elf_acom_section, &mips_elf_acom_symbol,
+                   ".acommon", 0, SEC_ALLOC);
 
 /* This is used for both the 32-bit and the 64-bit ABI.  */
 
@@ -6910,19 +7091,6 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
         either resolve these symbols to something in a shared
         library, or it can just leave them here.  For our purposes,
         we can consider these symbols to be in a new section.  */
-      if (mips_elf_acom_section.name == NULL)
-       {
-         /* Initialize the acommon section.  */
-         mips_elf_acom_section.name = ".acommon";
-         mips_elf_acom_section.flags = SEC_ALLOC;
-         mips_elf_acom_section.output_section = &mips_elf_acom_section;
-         mips_elf_acom_section.symbol = &mips_elf_acom_symbol;
-         mips_elf_acom_section.symbol_ptr_ptr = &mips_elf_acom_symbol_ptr;
-         mips_elf_acom_symbol.name = ".acommon";
-         mips_elf_acom_symbol.flags = BSF_SECTION_SYM;
-         mips_elf_acom_symbol.section = &mips_elf_acom_section;
-         mips_elf_acom_symbol_ptr = &mips_elf_acom_symbol;
-       }
       asym->section = &mips_elf_acom_section;
       break;
 
@@ -6935,19 +7103,6 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
        break;
       /* Fall through.  */
     case SHN_MIPS_SCOMMON:
-      if (mips_elf_scom_section.name == NULL)
-       {
-         /* Initialize the small common section.  */
-         mips_elf_scom_section.name = ".scommon";
-         mips_elf_scom_section.flags = SEC_IS_COMMON;
-         mips_elf_scom_section.output_section = &mips_elf_scom_section;
-         mips_elf_scom_section.symbol = &mips_elf_scom_symbol;
-         mips_elf_scom_section.symbol_ptr_ptr = &mips_elf_scom_symbol_ptr;
-         mips_elf_scom_symbol.name = ".scommon";
-         mips_elf_scom_symbol.flags = BSF_SECTION_SYM;
-         mips_elf_scom_symbol.section = &mips_elf_scom_section;
-         mips_elf_scom_symbol_ptr = &mips_elf_scom_symbol;
-       }
       asym->section = &mips_elf_scom_section;
       asym->value = elfsym->internal_elf_sym.st_size;
       break;
@@ -7085,7 +7240,7 @@ _bfd_mips_elf_eh_frame_address_size (bfd *abfd, const asection *sec)
 bfd_boolean
 _bfd_mips_elf_name_local_section_symbols (bfd *abfd)
 {
-  return SGI_COMPAT (abfd);
+  return elf_elfheader (abfd)->e_type == ET_REL && SGI_COMPAT (abfd);
 }
 \f
 /* Work over a section just before writing it out.  This routine is
@@ -7191,7 +7346,7 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
 
   if (hdr->bfd_section != NULL)
     {
-      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
+      const char *name = bfd_section_name (hdr->bfd_section);
 
       /* .sbss is not handled specially here because the GNU/Linux
         prelinker can convert .sbss from NOBITS to PROGBITS and
@@ -7226,10 +7381,7 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
 
 /* Handle a MIPS specific section when reading an object file.  This
    is called when elfcode.h finds a section with an unknown type.
-   This routine supports both the 32-bit and 64-bit ELF ABI.
-
-   FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure
-   how to.  */
+   This routine supports both the 32-bit and 64-bit ELF ABI.  */
 
 bfd_boolean
 _bfd_mips_elf_section_from_shdr (bfd *abfd,
@@ -7308,6 +7460,9 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
          && ! CONST_STRNEQ (name, ".MIPS.post_rel"))
        return FALSE;
       break;
+    case SHT_MIPS_XHASH:
+      if (strcmp (name, ".MIPS.xhash") != 0)
+       return FALSE;
     default:
       break;
     }
@@ -7315,12 +7470,14 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
   if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
     return FALSE;
 
+  if (hdr->sh_flags & SHF_MIPS_GPREL)
+    flags |= SEC_SMALL_DATA;
+
   if (flags)
     {
-      if (! bfd_set_section_flags (abfd, hdr->bfd_section,
-                                  (bfd_get_section_flags (abfd,
-                                                          hdr->bfd_section)
-                                   | flags)))
+      if (!bfd_set_section_flags (hdr->bfd_section,
+                                 (bfd_section_flags (hdr->bfd_section)
+                                  | flags)))
        return FALSE;
     }
 
@@ -7427,7 +7584,7 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
 bfd_boolean
 _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
 {
-  const char *name = bfd_get_section_name (abfd, sec);
+  const char *name = bfd_section_name (sec);
 
   if (strcmp (name, ".liblist") == 0)
     {
@@ -7541,6 +7698,12 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
       hdr->sh_flags |= SHF_ALLOC;
       hdr->sh_entsize = 8;
     }
+  else if (strcmp (name, ".MIPS.xhash") == 0)
+    {
+      hdr->sh_type = SHT_MIPS_XHASH;
+      hdr->sh_flags |= SHF_ALLOC;
+      hdr->sh_entsize = get_elf_backend_data(abfd)->s->arch_size == 64 ? 0 : 4;
+    }
 
   /* The generic elf_fake_sections will set up REL_HDR using the default
    kind of relocations.  We used to set up a second header for the
@@ -7561,12 +7724,12 @@ bfd_boolean
 _bfd_mips_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
                                        asection *sec, int *retval)
 {
-  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
+  if (strcmp (bfd_section_name (sec), ".scommon") == 0)
     {
       *retval = SHN_MIPS_SCOMMON;
       return TRUE;
     }
-  if (strcmp (bfd_get_section_name (abfd, sec), ".acommon") == 0)
+  if (strcmp (bfd_section_name (sec), ".acommon") == 0)
     {
       *retval = SHN_MIPS_ACOMMON;
       return TRUE;
@@ -7618,7 +7781,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
       /* Fall through.  */
     case SHN_MIPS_SCOMMON:
       *secp = bfd_make_section_old_way (abfd, ".scommon");
-      (*secp)->flags |= SEC_IS_COMMON;
+      (*secp)->flags |= SEC_IS_COMMON | SEC_SMALL_DATA;
       *valp = sym->st_size;
       break;
 
@@ -7628,7 +7791,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
        {
          asymbol *elf_text_symbol;
          asection *elf_text_section;
-         bfd_size_type amt = sizeof (asection);
+         size_t amt = sizeof (asection);
 
          elf_text_section = bfd_zalloc (abfd, amt);
          if (elf_text_section == NULL)
@@ -7669,7 +7832,7 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
        {
          asymbol *elf_data_symbol;
          asection *elf_data_section;
-         bfd_size_type amt = sizeof (asection);
+         size_t amt = sizeof (asection);
 
          elf_data_section = bfd_zalloc (abfd, amt);
          if (elf_data_section == NULL)
@@ -7788,12 +7951,12 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   /* The psABI requires a read-only .dynamic section, but the VxWorks
      EABI doesn't.  */
-  if (!htab->is_vxworks)
+  if (htab->root.target_os != is_vxworks)
     {
       s = bfd_get_linker_section (abfd, ".dynamic");
       if (s != NULL)
        {
-         if (! bfd_set_section_flags (abfd, s, flags))
+         if (!bfd_set_section_flags (s, flags))
            return FALSE;
        }
     }
@@ -7810,8 +7973,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
                                          MIPS_ELF_STUB_SECTION_NAME (abfd),
                                          flags | SEC_CODE);
   if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s,
-                                     MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+      || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
     return FALSE;
   htab->sstubs = s;
 
@@ -7822,11 +7984,15 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       s = bfd_make_section_anyway_with_flags (abfd, ".rld_map",
                                              flags &~ (flagword) SEC_READONLY);
       if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s,
-                                         MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+         || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return FALSE;
     }
 
+  /* Create .MIPS.xhash section.  */
+  if (info->emit_gnu_hash)
+    s = bfd_make_section_anyway_with_flags (abfd, ".MIPS.xhash",
+                                           flags | SEC_READONLY);
+
   /* On IRIX5, we adjust add some additional symbols and change the
      alignments of several sections.  There is no ABI documentation
      indicating that this is necessary on IRIX6, nor any evidence that
@@ -7861,24 +8027,24 @@ _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)
-       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
 
       s = bfd_get_linker_section (abfd, ".dynsym");
       if (s != NULL)
-       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
 
       s = bfd_get_linker_section (abfd, ".dynstr");
       if (s != NULL)
-       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
 
       /* ??? */
       s = bfd_get_section_by_name (abfd, ".reginfo");
       if (s != NULL)
-       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
 
       s = bfd_get_linker_section (abfd, ".dynamic");
       if (s != NULL)
-       (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+       bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
     }
 
   if (bfd_link_executable (info))
@@ -7933,7 +8099,7 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
     return FALSE;
 
   /* Do the usual VxWorks handling.  */
-  if (htab->is_vxworks
+  if (htab->root.target_os == is_vxworks
       && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
     return FALSE;
 
@@ -8091,6 +8257,47 @@ mips_elf_make_plt_record (bfd *abfd)
   return entry;
 }
 
+/* Define the special `__gnu_absolute_zero' symbol.  We only need this
+   for PIC code, as otherwise there is no load-time relocation involved
+   and local GOT entries whose value is zero at static link time will
+   retain their value at load time.  */
+
+static bfd_boolean
+mips_elf_define_absolute_zero (bfd *abfd, struct bfd_link_info *info,
+                              struct mips_elf_link_hash_table *htab,
+                              unsigned int r_type)
+{
+  union
+    {
+      struct elf_link_hash_entry *eh;
+      struct bfd_link_hash_entry *bh;
+    }
+  hzero;
+
+  BFD_ASSERT (!htab->use_absolute_zero);
+  BFD_ASSERT (bfd_link_pic (info));
+
+  hzero.bh = NULL;
+  if (!_bfd_generic_link_add_one_symbol (info, abfd, "__gnu_absolute_zero",
+                                        BSF_GLOBAL, bfd_abs_section_ptr, 0,
+                                        NULL, FALSE, FALSE, &hzero.bh))
+    return FALSE;
+
+  BFD_ASSERT (hzero.bh != NULL);
+  hzero.eh->size = 0;
+  hzero.eh->type = STT_NOTYPE;
+  hzero.eh->other = STV_PROTECTED;
+  hzero.eh->def_regular = 1;
+  hzero.eh->non_elf = 0;
+
+  if (!mips_elf_record_global_got_symbol (hzero.eh, abfd, info, TRUE, r_type))
+    return FALSE;
+
+  htab->use_absolute_zero = TRUE;
+
+  return TRUE;
+}
+
 /* Look through the relocs for a section during the first phase, and
    allocate space in the global offset table and record the need for
    standard MIPS and compressed procedure linkage table entries.  */
@@ -8129,7 +8336,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   /* Check for the mips16 stub sections.  */
 
-  name = bfd_get_section_name (abfd, sec);
+  name = bfd_section_name (sec);
   if (FN_STUB_P (name))
     {
       unsigned long r_symndx;
@@ -8425,10 +8632,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       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);
+        into account when deciding how to define the symbol.  */
+      constrain_symbol_p = TRUE;
 
       switch (r_type)
        {
@@ -8443,24 +8648,52 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* Fall through.  */
 
        case R_MIPS_GOT16:
-       case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16:
        case R_MIPS_GOT_PAGE:
-       case R_MIPS_GOT_OFST:
        case R_MIPS_GOT_DISP:
+       case R_MIPS16_GOT16:
+       case R_MICROMIPS_GOT16:
+       case R_MICROMIPS_GOT_LO16:
+       case R_MICROMIPS_GOT_PAGE:
+       case R_MICROMIPS_GOT_DISP:
+         /* If we have a symbol that will resolve to zero at static link
+            time and it is used by a GOT relocation applied to code we
+            cannot relax to an immediate zero load, then we will be using
+            the special `__gnu_absolute_zero' symbol whose value is zero
+            at dynamic load time.  We ignore HI16-type GOT relocations at
+            this stage, because their handling will depend entirely on
+            the corresponding LO16-type GOT relocation.  */
+         if (!call_hi16_reloc_p (r_type)
+             && h != NULL
+             && bfd_link_pic (info)
+             && !htab->use_absolute_zero
+             && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+           {
+             bfd_boolean rel_reloc;
+
+             if (!mips_elf_get_section_contents (abfd, sec, &contents))
+               return FALSE;
+
+             rel_reloc = mips_elf_rel_relocation_p (abfd, sec, relocs, rel);
+             howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, !rel_reloc);
+
+             if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
+                                             FALSE))
+               if (!mips_elf_define_absolute_zero (abfd, info, htab, r_type))
+                 return FALSE;
+           }
+
+         /* Fall through.  */
+       case R_MIPS_GOT_HI16:
+       case R_MIPS_GOT_OFST:
        case R_MIPS_TLS_GOTTPREL:
        case R_MIPS_TLS_GD:
        case R_MIPS_TLS_LDM:
-       case R_MIPS16_GOT16:
        case R_MIPS16_TLS_GOTTPREL:
        case R_MIPS16_TLS_GD:
        case R_MIPS16_TLS_LDM:
-       case R_MICROMIPS_GOT16:
        case R_MICROMIPS_GOT_HI16:
-       case R_MICROMIPS_GOT_LO16:
-       case R_MICROMIPS_GOT_PAGE:
        case R_MICROMIPS_GOT_OFST:
-       case R_MICROMIPS_GOT_DISP:
        case R_MICROMIPS_TLS_GOTTPREL:
        case R_MICROMIPS_TLS_GD:
        case R_MICROMIPS_TLS_LDM:
@@ -8468,7 +8701,8 @@ _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 && !bfd_link_pic (info))
+         if (htab->root.target_os == is_vxworks
+             && !bfd_link_pic (info))
            {
              _bfd_error_handler
                /* xgettext:c-format */
@@ -8514,7 +8748,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             against a read-only section.  */
          if ((bfd_link_pic (info)
               || (h != NULL
-                  && !htab->is_vxworks
+                  && htab->root.target_os != is_vxworks
                   && strcmp (h->root.root.string, "__gnu_local_gp") != 0
                   && !(!info->nocopyreloc
                        && !PIC_OBJECT_P (abfd)
@@ -8556,7 +8790,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                 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))
+             if (htab->root.target_os != is_vxworks
+                 && (!can_make_dynamic_p || !call_reloc_p))
                ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
            }
 
@@ -8581,7 +8816,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       else if (call_lo16_reloc_p (r_type)
               || got_lo16_reloc_p (r_type)
               || got_disp_reloc_p (r_type)
-              || (got16_reloc_p (r_type) && htab->is_vxworks))
+              || (got16_reloc_p (r_type)
+                  && htab->root.target_os == is_vxworks))
        {
          /* We may need a local GOT entry for this relocation.  We
             don't count R_MIPS_GOT_PAGE because we can estimate the
@@ -8809,9 +9045,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_MIPS_GNU_VTENTRY:
-         BFD_ASSERT (h != NULL);
-         if (h != NULL
-             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
            return FALSE;
          break;
 
@@ -8866,6 +9100,18 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        {
          switch (r_type)
            {
+           case R_MIPS_TLS_TPREL_HI16:
+           case R_MIPS16_TLS_TPREL_HI16:
+           case R_MICROMIPS_TLS_TPREL_HI16:
+           case R_MIPS_TLS_TPREL_LO16:
+           case R_MIPS16_TLS_TPREL_LO16:
+           case R_MICROMIPS_TLS_TPREL_LO16:
+             /* These are okay in PIE, but not in a shared library.  */
+             if (bfd_link_executable (info))
+               break;
+
+             /* FALLTHROUGH */
+
            case R_MIPS16_HI16:
            case R_MIPS_HI16:
            case R_MIPS_HIGHER:
@@ -8878,6 +9124,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              if (r_symndx == STN_UNDEF)
                break;
 
+             /* Likewise an absolute symbol.  */
+             if (h != NULL && bfd_is_abs_symbol (&h->root))
+               break;
+
              /* R_MIPS_HI16 against _gp_disp is used for $gp setup,
                 and has a special meaning.  */
              if (!NEWABI_P (abfd) && h != NULL
@@ -8893,15 +9143,17 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_MIPS16_26:
            case R_MIPS_26:
            case R_MICROMIPS_26_S1:
-             howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
-             _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);
-             return FALSE;
+             howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, NEWABI_P (abfd));
+             /* An error for unsupported relocations is raised as part
+                of the above search, so we can skip the following.  */
+             if (howto != NULL)
+               info->callbacks->einfo
+                 /* xgettext:c-format */
+                 (_("%X%H: relocation %s against `%s' cannot be used"
+                    " when making a shared object; recompile with -fPIC\n"),
+                  abfd, sec, rel->r_offset, howto->name,
+                  (h) ? h->root.root.string : "a local symbol");
+             break;
            default:
              break;
            }
@@ -8929,7 +9181,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 && !bfd_link_pic (info))
+  if (htab->root.target_os == is_vxworks && !bfd_link_pic (info))
     return TRUE;
 
   /* Ignore indirect symbols.  All relocations against such symbols
@@ -8974,7 +9226,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             VxWorks does not enforce the same mapping between the GOT
             and the symbol table, so the same requirement does not
             apply there.  */
-         if (!htab->is_vxworks)
+         if (htab->root.target_os != is_vxworks)
            {
              if (hmips->global_got_area > GGA_RELOC_ONLY)
                hmips->global_got_area = GGA_RELOC_ONLY;
@@ -9015,12 +9267,21 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   hmips = (struct mips_elf_link_hash_entry *) h;
 
   /* Make sure we know what is going on here.  */
-  BFD_ASSERT (dynobj != NULL
-             && (h->needs_plt
-                 || h->is_weakalias
-                 || (h->def_dynamic
-                     && h->ref_regular
-                     && !h->def_regular)));
+  if (dynobj == NULL
+      || (! h->needs_plt
+         && ! h->is_weakalias
+         && (! h->def_dynamic
+             || ! h->ref_regular
+             || h->def_regular)))
+    {
+      if (h->type == STT_GNU_IFUNC)
+       _bfd_error_handler (_("IFUNC symbol %s in dynamic symbol table - IFUNCS are not supported"),
+                           h->root.root.string);
+      else
+       _bfd_error_handler (_("non-dynamic symbol %s in dynamic symbol table"),
+                           h->root.root.string);
+      return TRUE;
+    }
 
   hmips = (struct mips_elf_link_hash_entry *) h;
 
@@ -9032,7 +9293,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
      Traditional stubs are only available on SVR4 psABI-based systems;
      VxWorks always uses PLTs instead.  */
-  if (!htab->is_vxworks && h->needs_plt && !hmips->no_fn_stub)
+  if (htab->root.target_os != is_vxworks
+      && h->needs_plt
+      && !hmips->no_fn_stub)
     {
       if (! elf_hash_table (info)->dynamic_sections_created)
        return TRUE;
@@ -9081,33 +9344,35 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             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->root.splt, 5))
+         if (htab->root.target_os != is_vxworks
+             && !bfd_set_section_alignment (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->root.sgotplt,
+         if (!bfd_set_section_alignment (htab->root.sgotplt,
                                          MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
            return FALSE;
 
          /* On non-VxWorks targets, the first two entries in .got.plt
             are reserved.  */
-         if (!htab->is_vxworks)
+         if (htab->root.target_os != is_vxworks)
            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 && !bfd_link_pic (info))
+         if (htab->root.target_os == 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))
+         if (htab->root.target_os == is_vxworks
+             && bfd_link_pic (info))
            htab->plt_mips_entry_size
              = 4 * ARRAY_SIZE (mips_vxworks_shared_plt_entry);
-         else if (htab->is_vxworks)
+         else if (htab->root.target_os == is_vxworks)
            htab->plt_mips_entry_size
              = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
          else if (newabi_p)
@@ -9150,7 +9415,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         standard entry actually has to be used as the stub ends with a J
         instruction.  */
       if (newabi_p
-         || htab->is_vxworks
+         || htab->root.target_os == is_vxworks
          || hmips->call_stub
          || hmips->call_fp_stub)
        {
@@ -9192,12 +9457,12 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        hmips->use_plt_entry = TRUE;
 
       /* Make room for the R_MIPS_JUMP_SLOT relocation.  */
-      htab->root.srelplt->size += (htab->is_vxworks
+      htab->root.srelplt->size += (htab->root.target_os == is_vxworks
                                   ? MIPS_ELF_RELA_SIZE (dynobj)
                                   : MIPS_ELF_REL_SIZE (dynobj));
 
       /* Make room for the .rela.plt.unloaded relocations.  */
-      if (htab->is_vxworks && !bfd_link_pic (info))
+      if (htab->root.target_os == is_vxworks && !bfd_link_pic (info))
        htab->srelplt2->size += 3 * sizeof (Elf32_External_Rela);
 
       /* All relocations against this symbol that could have been made
@@ -9262,7 +9527,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
     }
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
     {
-      if (htab->is_vxworks)
+      if (htab->root.target_os == is_vxworks)
        srel->size += sizeof (Elf32_External_Rela);
       else
        mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
@@ -9295,7 +9560,7 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
   sect = bfd_get_section_by_name (output_bfd, ".reginfo");
   if (sect != NULL)
     {
-      bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo));
+      bfd_set_section_size (sect, sizeof (Elf32_External_RegInfo));
       sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
     }
 
@@ -9303,8 +9568,7 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
   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));
+      bfd_set_section_size (sect, sizeof (Elf_External_ABIFlags_v0));
       sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
     }
 
@@ -9346,7 +9610,7 @@ 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_low_gotno == 0);
-  if (htab->is_vxworks)
+  if (htab->root.target_os == is_vxworks)
     htab->reserved_gotno = 3;
   else
     htab->reserved_gotno = 2;
@@ -9378,7 +9642,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
        }
     }
 
-  if (htab->is_vxworks)
+  if (htab->root.target_os == is_vxworks)
     /* There's no need to allocate page entries for VxWorks; R_MIPS*_GOT16
        relocations against local symbols evaluate to "G", and the EABI does
        not include R_MIPS_GOT_PAGE.  */
@@ -9403,7 +9667,8 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
   /* VxWorks does not support multiple GOTs.  It initializes $gp to
      __GOTT_BASE__[__GOTT_INDEX__], the value of which is set by the
      dynamic loader.  */
-  if (!htab->is_vxworks && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
+  if (htab->root.target_os != is_vxworks
+      && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
     {
       if (!mips_elf_multi_got (output_bfd, info, s, page_gotno))
        return FALSE;
@@ -9429,7 +9694,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 && bfd_link_pic (info))
+      if (htab->root.target_os == is_vxworks && bfd_link_pic (info))
        g->relocs += g->global_gotno + g->local_gotno - htab->reserved_gotno;
 
       /* Allocate room for the TLS relocations.  */
@@ -9611,7 +9876,7 @@ mips_elf_set_plt_sym_value (struct mips_elf_link_hash_entry *h, void *data)
       /* 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)
+      if (htab->root.target_os == is_vxworks)
        val += 8;
 
       h->root.root.u.def.section = htab->root.splt;
@@ -9676,9 +9941,9 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
          BFD_ASSERT (htab->root.sgotplt->size == 0);
          BFD_ASSERT (htab->root.splt->size == 0);
 
-         if (htab->is_vxworks && bfd_link_pic (info))
+         if (htab->root.target_os == is_vxworks && bfd_link_pic (info))
            size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
-         else if (htab->is_vxworks)
+         else if (htab->root.target_os == 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);
@@ -9737,7 +10002,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
 
       /* It's OK to base decisions on the section name, because none
         of the dynobj section names depend upon the input files.  */
-      name = bfd_get_section_name (dynobj, s);
+      name = bfd_section_name (s);
 
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
@@ -9755,8 +10020,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
                 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);
+             outname = bfd_section_name (s->output_section);
              target = bfd_get_section_by_name (output_bfd, outname + 4);
              if ((target != NULL
                   && (target->flags & SEC_READONLY) != 0
@@ -9795,7 +10059,8 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
             room for an extra nop to fill the delay slot.  This is
             for CPUs without load interlocking.  */
          if (! LOAD_INTERLOCKS_P (output_bfd)
-             && ! htab->is_vxworks && s->size > 0)
+             && htab->root.target_os != is_vxworks
+             && s->size > 0)
            s->size += 4;
        }
       else if (! CONST_STRNEQ (name, ".init")
@@ -9853,7 +10118,9 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
          && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
        return FALSE;
 
-      if (reltext && (SGI_COMPAT (output_bfd) || htab->is_vxworks))
+      if (reltext
+         && (SGI_COMPAT (output_bfd)
+             || htab->root.target_os == is_vxworks))
        info->flags |= DF_TEXTREL;
 
       if ((info->flags & DF_TEXTREL) != 0)
@@ -9872,7 +10139,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
        return FALSE;
 
       sreldyn = mips_elf_rel_dyn_section (info, FALSE);
-      if (htab->is_vxworks)
+      if (htab->root.target_os == is_vxworks)
        {
          /* VxWorks uses .rela.dyn instead of .rel.dyn.  It does not
             use any of the DT_MIPS_* tags.  */
@@ -9890,7 +10157,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;
@@ -9923,6 +10191,10 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0))
            return FALSE;
 
+         if (info->emit_gnu_hash
+             && ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_XHASH, 0))
+           return FALSE;
+
          if (IRIX_COMPAT (dynobj) == ict_irix5
              && ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_HIPAGENO, 0))
            return FALSE;
@@ -9947,7 +10219,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_PLTGOT, 0))
            return FALSE;
        }
-      if (htab->is_vxworks
+      if (htab->root.target_os == is_vxworks
          && !elf_vxworks_add_dynamic_entries (output_bfd, info))
        return FALSE;
     }
@@ -10261,10 +10533,10 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
       /* Figure out what value we are supposed to relocate.  */
       switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
-                                            input_section, info, rel,
-                                            addend, howto, local_syms,
-                                            local_sections, &value,
-                                            &name, &cross_mode_jump_p,
+                                            input_section, contents,
+                                            info, rel, addend, howto,
+                                            local_syms, local_sections,
+                                            &value, &name, &cross_mode_jump_p,
                                             use_saved_addend_p))
        {
        case bfd_reloc_continue:
@@ -10419,6 +10691,8 @@ mips_elf_create_la25_stub (void **slot, void *data)
   asection *s;
   bfd_byte *loc;
   bfd_vma offset, target, target_high, target_low;
+  bfd_vma branch_pc;
+  bfd_signed_vma pcrel_offset = 0;
 
   stub = (struct mips_elf_la25_stub *) *slot;
   hti = (struct mips_htab_traverse_info *) data;
@@ -10442,6 +10716,12 @@ mips_elf_create_la25_stub (void **slot, void *data)
   /* Work out where in the section this stub should go.  */
   offset = stub->offset;
 
+  /* We add 8 here to account for the LUI/ADDIU instructions
+     before the branch instruction.  This cannot be moved down to
+     where pcrel_offset is calculated as 's' is updated in
+     mips_elf_get_la25_target.  */
+  branch_pc = s->output_section->vma + s->output_offset + offset + 8;
+
   /* Work out the target address.  */
   target = mips_elf_get_la25_target (stub, &s);
   target += s->output_section->vma + s->output_offset;
@@ -10449,6 +10729,12 @@ mips_elf_create_la25_stub (void **slot, void *data)
   target_high = ((target + 0x8000) >> 16) & 0xffff;
   target_low = (target & 0xffff);
 
+  /* Calculate the PC of the compact branch instruction (for the case where
+     compact branches are used for either microMIPSR6 or MIPSR6 with
+     compact branches.  Add 4-bytes to account for BC using the PC of the
+     next instruction as the base.  */
+  pcrel_offset = target - (branch_pc + 4);
+
   if (stub->stub_section != htab->strampoline)
     {
       /* This is a simple LUI/ADDIU stub.  Zero out the beginning
@@ -10487,8 +10773,16 @@ mips_elf_create_la25_stub (void **slot, void *data)
       else
        {
          bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
-         bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
-         bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
+         if (MIPSR6_P (hti->output_bfd) && htab->compact_branches)
+           {
+             bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
+             bfd_put_32 (hti->output_bfd, LA25_BC (pcrel_offset), loc + 8);
+           }
+         else
+           {
+             bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
+             bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
+           }
          bfd_put_32 (hti->output_bfd, 0, loc + 12);
        }
     }
@@ -10567,7 +10861,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
   dynobj = elf_hash_table (info)->dynobj;
   hmips = (struct mips_elf_link_hash_entry *) h;
 
-  BFD_ASSERT (!htab->is_vxworks);
+  BFD_ASSERT (htab->root.target_os != is_vxworks);
 
   if (h->plt.plist != NULL
       && (h->plt.plist->mips_offset != MINUS_ONE
@@ -10645,14 +10939,16 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
          /* Fill in the PLT entry itself.  */
 
          if (MIPSR6_P (output_bfd))
-           plt_entry = mipsr6_exec_plt_entry;
+           plt_entry = htab->compact_branches ? mipsr6_exec_plt_entry_compact
+                                              : 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))
+         if (! LOAD_INTERLOCKS_P (output_bfd)
+             || (MIPSR6_P (output_bfd) && htab->compact_branches))
            {
              bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8);
              bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
@@ -10856,8 +11152,12 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
                          stub + idx);
              idx += 4;
            }
-         bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
-         idx += 4;
+
+         if (!(MIPSR6_P (output_bfd) && htab->compact_branches))
+           {
+             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.  */
@@ -10870,6 +11170,10 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
          else
            bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
                        stub + idx);
+         idx += 4;
+
+         if (MIPSR6_P (output_bfd) && htab->compact_branches)
+           bfd_put_32 (output_bfd, STUB_JALRC, stub + idx);
        }
 
       BFD_ASSERT (h->plt.plist->stub_offset <= htab->sstubs->size);
@@ -11243,11 +11547,17 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
   BFD_ASSERT (htab != NULL);
 
   if (ABI_64_P (output_bfd))
-    plt_entry = mips_n64_exec_plt0_entry;
+    plt_entry = (htab->compact_branches
+                ? mipsr6_n64_exec_plt0_entry_compact
+                : mips_n64_exec_plt0_entry);
   else if (ABI_N32_P (output_bfd))
-    plt_entry = mips_n32_exec_plt0_entry;
+    plt_entry = (htab->compact_branches
+                ? mipsr6_n32_exec_plt0_entry_compact
+                : mips_n32_exec_plt0_entry);
   else if (!htab->plt_header_is_comp)
-    plt_entry = mips_o32_exec_plt0_entry;
+    plt_entry = (htab->compact_branches
+                ? mipsr6_o32_exec_plt0_entry_compact
+                : mips_o32_exec_plt0_entry);
   else if (htab->insn32)
     plt_entry = micromips_insn32_o32_exec_plt0_entry;
   else
@@ -11487,7 +11797,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              break;
 
            case DT_RELAENT:
-             BFD_ASSERT (htab->is_vxworks);
+             BFD_ASSERT (htab->root.target_os == is_vxworks);
              dyn.d_un.d_val = MIPS_ELF_RELA_SIZE (dynobj);
              break;
 
@@ -11626,7 +11936,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 
            case DT_PLTREL:
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
-             if (htab->is_vxworks)
+             if (htab->root.target_os == is_vxworks)
                dyn.d_un.d_val = DT_RELA;
              else
                dyn.d_un.d_val = DT_REL;
@@ -11662,9 +11972,15 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                swap_out_p = FALSE;
              break;
 
+           case DT_MIPS_XHASH:
+             name = ".MIPS.xhash";
+             s = bfd_get_linker_section (dynobj, name);
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+             break;
+
            default:
              swap_out_p = FALSE;
-             if (htab->is_vxworks
+             if (htab->root.target_os == is_vxworks
                  && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
                swap_out_p = TRUE;
              break;
@@ -11689,7 +12005,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
   if (sgot != NULL && sgot->size > 0
       && !bfd_is_abs_section (sgot->output_section))
     {
-      if (htab->is_vxworks)
+      if (htab->root.target_os == is_vxworks)
        {
          /* The first entry of the global offset table points to the
             ".dynamic" section.  The second is initialized by the
@@ -11798,6 +12114,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;
@@ -11835,7 +12152,8 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                                             s->contents));
 
            /* Clean up a dummy stub function entry in .text.  */
-           if (htab->sstubs != NULL)
+           if (htab->sstubs != NULL
+               && htab->sstubs->contents != NULL)
              {
                file_ptr dummy_offset;
 
@@ -11851,7 +12169,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
        increasing order of r_symndx.  The VxWorks EABI doesn't require
        this, and because the code below handles REL rather than RELA
        relocations, using it for VxWorks would be outright harmful.  */
-    if (!htab->is_vxworks)
+    if (htab->root.target_os != is_vxworks)
       {
        s = mips_elf_rel_dyn_section (info, FALSE);
        if (s != NULL
@@ -11873,7 +12191,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 
   if (htab->root.splt && htab->root.splt->size > 0)
     {
-      if (htab->is_vxworks)
+      if (htab->root.target_os == is_vxworks)
        {
          if (bfd_link_pic (info))
            mips_vxworks_finish_shared_plt (output_bfd, info);
@@ -11901,6 +12219,12 @@ mips_set_isa_flags (bfd *abfd)
   switch (bfd_get_mach (abfd))
     {
     default:
+      if (ABI_N32_P (abfd) || ABI_64_P (abfd))
+        val = E_MIPS_ARCH_3;
+      else
+        val = E_MIPS_ARCH_1;
+      break;
+
     case bfd_mach_mips3000:
       val = E_MIPS_ARCH_1;
       break;
@@ -11982,8 +12306,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_64R2 | 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:
@@ -12058,8 +12390,7 @@ _bfd_mips_elf_sort_relocs_p (asection *sec)
    number.  This is used by both the 32-bit and the 64-bit ABI.  */
 
 void
-_bfd_mips_elf_final_write_processing (bfd *abfd,
-                                     bfd_boolean linker ATTRIBUTE_UNUSED)
+_bfd_mips_final_write_processing (bfd *abfd)
 {
   unsigned int i;
   Elf_Internal_Shdr **hdrpp;
@@ -12089,7 +12420,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
 
        case SHT_MIPS_GPTAB:
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
-         name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+         name = bfd_section_name ((*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL
                      && CONST_STRNEQ (name, ".gptab."));
          sec = bfd_get_section_by_name (abfd, name + sizeof ".gptab" - 1);
@@ -12099,7 +12430,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
 
        case SHT_MIPS_CONTENT:
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
-         name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+         name = bfd_section_name ((*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL
                      && CONST_STRNEQ (name, ".MIPS.content"));
          sec = bfd_get_section_by_name (abfd,
@@ -12119,7 +12450,7 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
 
        case SHT_MIPS_EVENTS:
          BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
-         name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+         name = bfd_section_name ((*hdrpp)->bfd_section);
          BFD_ASSERT (name != NULL);
          if (CONST_STRNEQ (name, ".MIPS.events"))
            sec = bfd_get_section_by_name (abfd,
@@ -12135,9 +12466,20 @@ _bfd_mips_elf_final_write_processing (bfd *abfd,
          (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
          break;
 
+       case SHT_MIPS_XHASH:
+         sec = bfd_get_section_by_name (abfd, ".dynsym");
+         if (sec != NULL)
+           (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
        }
     }
 }
+
+bfd_boolean
+_bfd_mips_elf_final_write_processing (bfd *abfd)
+{
+  _bfd_mips_final_write_processing (abfd);
+  return _bfd_elf_final_write_processing (abfd);
+}
 \f
 /* When creating an IRIX5 executable, we need REGINFO and RTPROC
    segments.  */
@@ -12187,7 +12529,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
 {
   asection *s;
   struct elf_segment_map *m, **pm;
-  bfd_size_type amt;
+  size_t amt;
 
   /* If there is a .reginfo section, we need a PT_MIPS_REGINFO
      segment.  */
@@ -12390,7 +12732,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
                && s->vma + s->size <= high)
              ++c;
 
-         amt = sizeof *n + (bfd_size_type) (c - 1) * sizeof (asection *);
+         amt = sizeof *n - sizeof (asection *) + c * sizeof (asection *);
          n = bfd_zalloc (abfd, amt);
          if (n == NULL)
            return FALSE;
@@ -12494,8 +12836,7 @@ _bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info,
 
       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)))
+           && MIPS_ELF_ABIFLAGS_SECTION_NAME_P (bfd_section_name (o)))
          {
            if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
              return FALSE;
@@ -12561,6 +12902,27 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
   if (indmips->has_nonpic_branches)
     dirmips->has_nonpic_branches = TRUE;
 }
+
+/* Take care of the special `__gnu_absolute_zero' symbol and ignore attempts
+   to hide it.  It has to remain global (it will also be protected) so as to
+   be assigned a global GOT entry, which will then remain unchanged at load
+   time.  */
+
+void
+_bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
+                          struct elf_link_hash_entry *entry,
+                          bfd_boolean force_local)
+{
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+  if (htab->use_absolute_zero
+      && strcmp (entry->root.root.string, "__gnu_absolute_zero") == 0)
+    return;
+
+  _bfd_elf_link_hash_hide_symbol (info, entry, force_local);
+}
 \f
 #define PDR_SIZE 32
 
@@ -12696,28 +13058,18 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asymbol **symbols,
                                     filename_ptr, functionname_ptr,
                                     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 (filename_ptr != NULL && *filename_ptr != NULL)
-           filename_ptr = NULL;
-
-         _bfd_elf_find_function (abfd, symbols, section, offset,
-                                 filename_ptr, functionname_ptr);
-       }
+      == 1)
+    return TRUE;
 
+  if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+                                    filename_ptr, functionname_ptr,
+                                    line_ptr))
+    {
+      if (!*functionname_ptr)
+       _bfd_elf_find_function (abfd, symbols, section, offset,
+                               *filename_ptr ? NULL : filename_ptr,
+                               functionname_ptr);
       return TRUE;
     }
 
@@ -12831,7 +13183,7 @@ _bfd_mips_elf_set_section_contents (bfd *abfd, sec_ptr section,
 
       if (elf_section_data (section) == NULL)
        {
-         bfd_size_type amt = sizeof (struct bfd_elf_section_data);
+         size_t amt = sizeof (struct bfd_elf_section_data);
          section->used_by_bfd = bfd_zalloc (abfd, amt);
          if (elf_section_data (section) == NULL)
            return FALSE;
@@ -13004,13 +13356,11 @@ _bfd_elf_mips_get_relocated_section_contents
            }
        }
     }
-  if (reloc_vector != NULL)
-    free (reloc_vector);
+  free (reloc_vector);
   return data;
 
-error_return:
-  if (reloc_vector != NULL)
-    free (reloc_vector);
+ error_return:
+  free (reloc_vector);
   return NULL;
 }
 \f
@@ -13887,21 +14237,17 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
        }
     }
 
-  if (internal_relocs != NULL
-      && elf_section_data (sec)->relocs != internal_relocs)
+  if (elf_section_data (sec)->relocs != internal_relocs)
     free (internal_relocs);
 
   return TRUE;
 
  error_return:
-  if (isymbuf != NULL
-      && symtab_hdr->contents != (unsigned char *) isymbuf)
+  if (symtab_hdr->contents != (unsigned char *) isymbuf)
     free (isymbuf);
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
+  if (elf_section_data (sec)->this_hdr.contents != contents)
     free (contents);
-  if (internal_relocs != NULL
-      && elf_section_data (sec)->relocs != internal_relocs)
+  if (elf_section_data (sec)->relocs != internal_relocs)
     free (internal_relocs);
 
   return FALSE;
@@ -13913,7 +14259,7 @@ struct bfd_link_hash_table *
 _bfd_mips_elf_link_hash_table_create (bfd *abfd)
 {
   struct mips_elf_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct mips_elf_link_hash_table);
+  size_t amt = sizeof (struct mips_elf_link_hash_table);
 
   ret = bfd_zmalloc (amt);
   if (ret == NULL)
@@ -13947,7 +14293,6 @@ _bfd_mips_vxworks_link_hash_table_create (bfd *abfd)
 
       htab = (struct mips_elf_link_hash_table *) ret;
       htab->use_plts_and_copy_relocs = TRUE;
-      htab->is_vxworks = TRUE;
     }
   return ret;
 }
@@ -13963,15 +14308,28 @@ _bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
 
 /* 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.  */
+   branch relocation checks for invalid transitions between ISA modes.
+   Also record whether we have been configured for a GNU target.  */
 
 void
 _bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
-                           bfd_boolean ignore_branch_isa)
+                           bfd_boolean ignore_branch_isa,
+                           bfd_boolean gnu_target)
 {
   mips_elf_hash_table (info)->insn32 = insn32;
   mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
+  mips_elf_hash_table (info)->gnu_target = gnu_target;
+}
+
+/* A function that the linker calls to enable use of compact branches in
+   linker generated code for MIPSR6.  */
+
+void
+_bfd_mips_elf_compact_branches (struct bfd_link_info *info, bfd_boolean on)
+{
+  mips_elf_hash_table (info)->compact_branches = on;
 }
+
 \f
 /* Structure for saying that BFD machine EXTENSION extends BASE.  */
 
@@ -13991,7 +14349,9 @@ static const struct mips_mach_extension mips_mach_extensions[] =
   { 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_loongson_3a, 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 },
@@ -14103,7 +14463,6 @@ bfd_mips_isa_ext_mach (unsigned int isa_ext)
     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_LOONGSON_3A: return bfd_mach_mips_loongson_3a;
     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;
@@ -14132,7 +14491,6 @@ bfd_mips_isa_ext (bfd *abfd)
     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_loongson_3a: return AFL_EXT_LOONGSON_3A;
     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;
@@ -14248,7 +14606,7 @@ infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags)
       && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT
       && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A
       && abiflags->isa_level >= 32
-      && abiflags->isa_ext != AFL_EXT_LOONGSON_3A)
+      && abiflags->ases != AFL_ASE_LOONGSON_EXT)
     abiflags->flags1 |= AFL_FLAGS1_ODDSPREG;
 }
 
@@ -14313,7 +14671,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        elf_gp (abfd) = (h->u.def.value
                         + h->u.def.section->output_section->vma
                         + h->u.def.section->output_offset);
-      else if (htab->is_vxworks
+      else if (htab->root.target_os == is_vxworks
               && (h = bfd_link_hash_lookup (info->hash,
                                             "_GLOBAL_OFFSET_TABLE_",
                                             FALSE, FALSE, TRUE))
@@ -14624,7 +14982,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                                                                   ".rtproc",
                                                                   flags);
                  if (rtproc_sec == NULL
-                     || ! bfd_set_section_alignment (abfd, rtproc_sec, 4))
+                     || !bfd_set_section_alignment (rtproc_sec, 4))
                    return FALSE;
                }
 
@@ -15367,6 +15725,7 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
   /* 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.  */
+  /* FIXME: This excludes any input shared library from consideration.  */
   for (sec = ibfd->sections; sec != NULL; sec = sec->next)
     {
       /* Ignore synthetic sections and empty .text, .data and .bss sections
@@ -15597,6 +15956,8 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag)
       return "DT_MIPS_PLTGOT";
     case DT_MIPS_RWPLT:
       return "DT_MIPS_RWPLT";
+    case DT_MIPS_XHASH:
+      return "DT_MIPS_XHASH";
     }
 }
 
@@ -15673,6 +16034,14 @@ print_mips_ases (FILE *file, unsigned int mask)
     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)
@@ -15699,9 +16068,6 @@ print_mips_isa_ext (FILE *file, unsigned int isa_ext)
     case AFL_EXT_OCTEONP:
       fputs ("Cavium Networks OcteonP", file);
       break;
-    case AFL_EXT_LOONGSON_3A:
-      fputs ("Loongson 3A", file);
-      break;
     case AFL_EXT_OCTEON:
       fputs ("Cavium Networks Octeon", file);
       break;
@@ -15925,6 +16291,7 @@ const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
   { 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 },
+  { STRING_COMMA_LEN (".MIPS.xhash"),  0, SHT_MIPS_XHASH,   SHF_ALLOC },
   { NULL,                    0,  0, 0,              0 }
 };
 
@@ -15933,21 +16300,21 @@ const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
    definiton of the symbol.  */
 void
 _bfd_mips_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
-                                     const Elf_Internal_Sym *isym,
+                                     unsigned int st_other,
                                      bfd_boolean definition,
                                      bfd_boolean dynamic ATTRIBUTE_UNUSED)
 {
-  if ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) != 0)
+  if ((st_other & ~ELF_ST_VISIBILITY (-1)) != 0)
     {
       unsigned char other;
 
-      other = (definition ? isym->st_other : h->other);
+      other = (definition ? st_other : h->other);
       other &= ~ELF_ST_VISIBILITY (-1);
       h->other = other | ELF_ST_VISIBILITY (h->other);
     }
 
   if (!definition
-      && ELF_MIPS_IS_OPTIONAL (isym->st_other))
+      && ELF_MIPS_IS_OPTIONAL (st_other))
     h->other |= STO_OPTIONAL;
 }
 
@@ -16238,30 +16605,45 @@ enum
   MIPS_LIBC_ABI_MIPS_PLT,
   MIPS_LIBC_ABI_UNIQUE,
   MIPS_LIBC_ABI_MIPS_O32_FP64,
+  MIPS_LIBC_ABI_ABSOLUTE,
+  MIPS_LIBC_ABI_XHASH,
   MIPS_LIBC_ABI_MAX
 };
 
-void
-_bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
+bfd_boolean
+_bfd_mips_init_file_header (bfd *abfd, struct bfd_link_info *link_info)
 {
-  struct mips_elf_link_hash_table *htab;
+  struct mips_elf_link_hash_table *htab = NULL;
   Elf_Internal_Ehdr *i_ehdrp;
 
+  if (!_bfd_elf_init_file_header (abfd, link_info))
+    return FALSE;
+
   i_ehdrp = elf_elfheader (abfd);
   if (link_info)
     {
       htab = mips_elf_hash_table (link_info);
       BFD_ASSERT (htab != NULL);
-
-      if (htab->use_plts_and_copy_relocs && !htab->is_vxworks)
-       i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
     }
 
+  if (htab != NULL
+      && htab->use_plts_and_copy_relocs
+      && htab->root.target_os != is_vxworks)
+    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);
+  /* Mark that we need support for absolute symbols in the dynamic loader.  */
+  if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
+
+  /* Mark that we need support for .MIPS.xhash in the dynamic linker,
+     if it is the only hash section that will be created.  */
+  if (link_info && link_info->emit_gnu_hash && !link_info->emit_hash)
+    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_XHASH;
+  return TRUE;
 }
 
 int
@@ -16279,3 +16661,17 @@ _bfd_mips_elf_cant_unwind_opcode
 {
   return COMPACT_EH_CANT_UNWIND_OPCODE;
 }
+
+/* Record a position XLAT_LOC in the xlat translation table, associated with
+   the hash entry H.  The entry in the translation table will later be
+   populated with the real symbol dynindx.  */
+
+void
+_bfd_mips_elf_record_xhash_symbol (struct elf_link_hash_entry *h,
+                                  bfd_vma xlat_loc)
+{
+  struct mips_elf_link_hash_entry *hmips;
+
+  hmips = (struct mips_elf_link_hash_entry *) h;
+  hmips->mipsxhash_loc = xlat_loc;
+}