MIPS/BFD: Also handle `jalr $0, $25' with R_MIPS_JALR
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index c2c129039caaec7b91e16ac711cde0e3d89774eb..7a1d5f848bbbd15748b3a6de17d31b97a04188cd 100644 (file)
@@ -1,5 +1,5 @@
 /* MIPS-specific support for ELF
-   Copyright (C) 1993-2016 Free Software Foundation, Inc.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
 
    Most of the information added by Ian Lance Taylor, Cygnus Support,
    <ian@cygnus.com>.
@@ -310,14 +310,17 @@ struct mips_elf_hash_sort_data
   struct elf_link_hash_entry *low;
   /* The least dynamic symbol table index corresponding to a non-TLS
      symbol with a GOT entry.  */
-  long min_got_dynindx;
+  bfd_size_type min_got_dynindx;
   /* The greatest dynamic symbol table index corresponding to a symbol
      with a GOT entry that is not referenced (e.g., a dynamic symbol
      with dynamic relocations pointing to it from non-primary GOTs).  */
-  long max_unref_got_dynindx;
-  /* The greatest dynamic symbol table index not corresponding to a
+  bfd_size_type max_unref_got_dynindx;
+  /* The greatest dynamic symbol table index corresponding to a local
+     symbol.  */
+  bfd_size_type max_local_dynindx;
+  /* The greatest dynamic symbol table index corresponding to an external
      symbol without a GOT entry.  */
-  long max_non_got_dynindx;
+  bfd_size_type max_non_got_dynindx;
 };
 
 /* We make up to two PLT entries if needed, one for standard MIPS code
@@ -443,6 +446,9 @@ struct mips_elf_link_hash_table
   /* True if we can only use 32-bit microMIPS instructions.  */
   bfd_boolean insn32;
 
+  /* True if we suppress checks for invalid branches between ISA modes.  */
+  bfd_boolean ignore_branch_isa;
+
   /* True if we're generating code for VxWorks.  */
   bfd_boolean is_vxworks;
 
@@ -451,14 +457,8 @@ struct mips_elf_link_hash_table
 
   /* Shortcuts to some dynamic sections, or NULL if they are not
      being used.  */
-  asection *srelbss;
-  asection *sdynbss;
-  asection *srelplt;
   asection *srelplt2;
-  asection *sgotplt;
-  asection *splt;
   asection *sstubs;
-  asection *sgot;
 
   /* The master GOT information.  */
   struct mips_got_info *got_info;
@@ -913,7 +913,7 @@ static bfd *reldyn_sorting_bfd;
     : 0x8f998010))                             /* lw t9,0x8010(gp) */
 #define STUB_MOVE 0x03e07825                   /* or t7,ra,zero */
 #define STUB_LUI(VAL) (0x3c180000 + (VAL))     /* lui t8,VAL */
-#define STUB_JALR 0x0320f809                   /* jalr t9,ra */
+#define STUB_JALR 0x0320f809                   /* jalr ra,t9 */
 #define STUB_ORI(VAL) (0x37180000 + (VAL))     /* ori t8,t8,VAL */
 #define STUB_LI16U(VAL) (0x34180000 + (VAL))   /* ori t8,zero,VAL unsigned */
 #define STUB_LI16S(abfd, VAL)                                          \
@@ -1578,12 +1578,13 @@ mips_elf_create_stub_symbol (struct bfd_link_info *info,
                             const char *prefix, asection *s, bfd_vma value,
                             bfd_vma size)
 {
+  bfd_boolean micromips_p = ELF_ST_IS_MICROMIPS (h->root.other);
   struct bfd_link_hash_entry *bh;
   struct elf_link_hash_entry *elfh;
   char *name;
   bfd_boolean res;
 
-  if (ELF_ST_IS_MICROMIPS (h->root.other))
+  if (micromips_p)
     value |= 1;
 
   /* Create a new symbol.  */
@@ -1601,6 +1602,8 @@ mips_elf_create_stub_symbol (struct bfd_link_info *info,
   elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
   elfh->size = size;
   elfh->forced_local = 1;
+  if (micromips_p)
+    elfh->other = ELF_ST_SET_MICROMIPS (elfh->other);
   return TRUE;
 }
 
@@ -1805,6 +1808,7 @@ mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
           || h->root.root.type == bfd_link_hash_defweak)
          && h->root.def_regular
          && !bfd_is_abs_section (h->root.root.u.def.section)
+         && !bfd_is_und_section (h->root.root.u.def.section)
          && (!ELF_ST_IS_MIPS16 (h->root.other)
              || (h->fn_stub && h->need_fn_stub))
          && (PIC_OBJECT_P (h->root.root.u.def.section->owner)
@@ -1961,6 +1965,8 @@ mips_elf_add_la25_stub (struct bfd_link_info *info,
   /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
      of the section and if we would need no more than 2 nops.  */
   value = mips_elf_get_la25_target (stub, &s);
+  if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+    value &= ~1;
   use_trampoline_p = (value != 0 || s->alignment_power > 4);
 
   h->la25_stub = stub;
@@ -2090,7 +2096,11 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
 
    All we need to do here is shuffle the bits appropriately.
    As above, the two 16-bit halves must be swapped on a
-   little-endian system.  */
+   little-endian system.
+
+   Finally R_MIPS16_PC16_S1 corresponds to R_MIPS_PC16, however the
+   relocatable field is shifted by 1 rather than 2 and the same bit
+   shuffling is done as with the relocations above.  */
 
 static inline bfd_boolean
 mips16_reloc_p (int r_type)
@@ -2110,6 +2120,7 @@ mips16_reloc_p (int r_type)
     case R_MIPS16_TLS_GOTTPREL:
     case R_MIPS16_TLS_TPREL_HI16:
     case R_MIPS16_TLS_TPREL_LO16:
+    case R_MIPS16_PC16_S1:
       return TRUE;
 
     default:
@@ -2215,6 +2226,19 @@ jal_reloc_p (int r_type)
          || r_type == R_MICROMIPS_26_S1);
 }
 
+static inline bfd_boolean
+b_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_PC26_S2
+         || r_type == R_MIPS_PC21_S2
+         || r_type == R_MIPS_PC16
+         || r_type == R_MIPS_GNU_REL16_S2
+         || r_type == R_MIPS16_PC16_S1
+         || r_type == R_MICROMIPS_PC16_S1
+         || r_type == R_MICROMIPS_PC10_S1
+         || r_type == R_MICROMIPS_PC7_S1);
+}
+
 static inline bfd_boolean
 aligned_pcrel_reloc_p (int r_type)
 {
@@ -2222,6 +2246,23 @@ aligned_pcrel_reloc_p (int r_type)
          || r_type == R_MIPS_PC19_S2);
 }
 
+static inline bfd_boolean
+branch_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_26
+         || r_type == R_MIPS_PC26_S2
+         || r_type == R_MIPS_PC21_S2
+         || r_type == R_MIPS_PC16
+         || r_type == R_MIPS_GNU_REL16_S2);
+}
+
+static inline bfd_boolean
+mips16_branch_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS16_26
+         || r_type == R_MIPS16_PC16_S1);
+}
+
 static inline bfd_boolean
 micromips_branch_reloc_p (int r_type)
 {
@@ -3315,7 +3356,7 @@ mips_elf_initialize_tls_slots (bfd *abfd, struct bfd_link_info *info,
   if (htab == NULL)
     return;
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
 
   indx = 0;
   if (h != NULL)
@@ -3442,8 +3483,8 @@ mips_elf_gotplt_index (struct bfd_link_info *info,
   BFD_ASSERT (h->plt.plist->gotplt_index != MINUS_ONE);
 
   /* Calculate the address of the associated .got.plt entry.  */
-  got_address = (htab->sgotplt->output_section->vma
-                + htab->sgotplt->output_offset
+  got_address = (htab->root.sgotplt->output_section->vma
+                + htab->root.sgotplt->output_offset
                 + (h->plt.plist->gotplt_index
                    * MIPS_ELF_GOT_SIZE (info->output_bfd)));
 
@@ -3507,7 +3548,7 @@ mips_elf_primary_global_got_index (bfd *obfd, struct bfd_link_info *info,
   g = mips_elf_bfd_got (obfd, FALSE);
   got_index = ((h->dynindx - global_got_dynindx + g->local_gotno)
               * MIPS_ELF_GOT_SIZE (obfd));
-  BFD_ASSERT (got_index < htab->sgot->size);
+  BFD_ASSERT (got_index < htab->root.sgot->size);
 
   return got_index;
 }
@@ -3541,7 +3582,7 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
   BFD_ASSERT (entry);
 
   gotidx = entry->gotidx;
-  BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
+  BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
 
   if (lookup.tls_type)
     {
@@ -3629,7 +3670,7 @@ mips_elf_got_offset_from_index (struct bfd_link_info *info, bfd *output_bfd,
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   gp = _bfd_get_gp_value (output_bfd)
     + mips_elf_adjust_gp (output_bfd, htab->got_info, input_bfd);
 
@@ -3692,7 +3733,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       BFD_ASSERT (entry);
 
       gotidx = entry->gotidx;
-      BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
+      BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
 
       return entry;
     }
@@ -3711,7 +3752,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
   if (g->assigned_low_gotno > g->assigned_high_gotno)
     {
       /* We didn't allocate enough space in the GOT.  */
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("not enough GOT space for local GOT entries"));
       bfd_set_error (bfd_error_bad_value);
       return NULL;
@@ -3732,7 +3773,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
   *entry = lookup;
   *loc = entry;
 
-  MIPS_ELF_PUT_WORD (abfd, value, htab->sgot->contents + entry->gotidx);
+  MIPS_ELF_PUT_WORD (abfd, value, htab->root.sgot->contents + entry->gotidx);
 
   /* These GOT entries need a dynamic relocation on VxWorks.  */
   if (htab->is_vxworks)
@@ -3743,8 +3784,8 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       bfd_vma got_address;
 
       s = mips_elf_rel_dyn_section (info, FALSE);
-      got_address = (htab->sgot->output_section->vma
-                    + htab->sgot->output_offset
+      got_address = (htab->root.sgot->output_section->vma
+                    + htab->root.sgot->output_offset
                     + entry->gotidx);
 
       rloc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
@@ -3794,12 +3835,12 @@ mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
   struct mips_elf_hash_sort_data hsd;
   struct mips_got_info *g;
 
-  if (elf_hash_table (info)->dynsymcount == 0)
-    return TRUE;
-
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
+  if (htab->root.dynsymcount == 0)
+    return TRUE;
+
   g = htab->got_info;
   if (g == NULL)
     return TRUE;
@@ -3807,20 +3848,19 @@ mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
   hsd.low = NULL;
   hsd.max_unref_got_dynindx
     = hsd.min_got_dynindx
-    = (elf_hash_table (info)->dynsymcount - g->reloc_only_gotno);
-  hsd.max_non_got_dynindx = count_section_dynsyms (abfd, info) + 1;
-  mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
-                               elf_hash_table (info)),
-                              mips_elf_sort_hash_table_f,
-                              &hsd);
+    = (htab->root.dynsymcount - g->reloc_only_gotno);
+  /* Add 1 to local symbol indices to account for the mandatory NULL entry
+     at the head of the table; see `_bfd_elf_link_renumber_dynsyms'.  */
+  hsd.max_local_dynindx = count_section_dynsyms (abfd, info) + 1;
+  hsd.max_non_got_dynindx = htab->root.local_dynsymcount + 1;
+  mips_elf_link_hash_traverse (htab, mips_elf_sort_hash_table_f, &hsd);
 
   /* There should have been enough room in the symbol table to
      accommodate both the GOT and non-GOT symbols.  */
+  BFD_ASSERT (hsd.max_local_dynindx <= htab->root.local_dynsymcount + 1);
   BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
-  BFD_ASSERT ((unsigned long) hsd.max_unref_got_dynindx
-             == elf_hash_table (info)->dynsymcount);
-  BFD_ASSERT (elf_hash_table (info)->dynsymcount - hsd.min_got_dynindx
-             == g->global_gotno);
+  BFD_ASSERT (hsd.max_unref_got_dynindx == htab->root.dynsymcount);
+  BFD_ASSERT (htab->root.dynsymcount - hsd.min_got_dynindx == g->global_gotno);
 
   /* Now we know which dynamic symbol has the lowest dynamic symbol
      table index in the GOT.  */
@@ -3846,7 +3886,10 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
   switch (h->global_got_area)
     {
     case GGA_NONE:
-      h->root.dynindx = hsd->max_non_got_dynindx++;
+      if (h->root.forced_local)
+       h->root.dynindx = hsd->max_local_dynindx++;
+      else
+       h->root.dynindx = hsd->max_non_got_dynindx++;
       break;
 
     case GGA_NORMAL:
@@ -5096,7 +5139,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   BFD_ASSERT (htab != NULL);
 
   /* This function may be called more than once.  */
-  if (htab->sgot)
+  if (htab->root.sgot)
     return TRUE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
@@ -5108,7 +5151,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 4))
     return FALSE;
-  htab->sgot = s;
+  htab->root.sgot = s;
 
   /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the
      linker script because we don't want to define the symbol if we
@@ -5142,7 +5185,7 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
                                          | SEC_LINKER_CREATED);
   if (s == NULL)
     return FALSE;
-  htab->sgotplt = s;
+  htab->root.sgotplt = s;
 
   return TRUE;
 }
@@ -5247,6 +5290,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   /* TRUE if the symbol referred to by this relocation is a local
      symbol.  */
   bfd_boolean local_p, was_local_p;
+  /* TRUE if the symbol referred to by this relocation is a section
+     symbol.  */
+  bfd_boolean section_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is "_gp_disp".  */
   bfd_boolean gp_disp_p = FALSE;
   /* TRUE if the symbol referred to by this relocation is
@@ -5297,17 +5343,18 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   /* Figure out the value of the symbol.  */
   if (local_p)
     {
+      bfd_boolean micromips_p = MICROMIPS_P (abfd);
       Elf_Internal_Sym *sym;
 
       sym = local_syms + r_symndx;
       sec = local_sections[r_symndx];
 
+      section_p = ELF_ST_TYPE (sym->st_info) == STT_SECTION;
+
       symbol = sec->output_section->vma + sec->output_offset;
-      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION
-         || (sec->flags & SEC_MERGE))
+      if (!section_p || (sec->flags & SEC_MERGE))
        symbol += sym->st_value;
-      if ((sec->flags & SEC_MERGE)
-         && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+      if ((sec->flags & SEC_MERGE) && section_p)
        {
          addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
          addend -= symbol;
@@ -5325,8 +5372,26 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       if (*namep == NULL || **namep == '\0')
        *namep = bfd_section_name (input_bfd, sec);
 
-      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
-      target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other);
+      /* For relocations against a section symbol and ones against no
+         symbol (absolute relocations) infer the ISA mode from the addend.  */
+      if (section_p || r_symndx == STN_UNDEF)
+       {
+         target_is_16_bit_code_p = (addend & 1) && !micromips_p;
+         target_is_micromips_code_p = (addend & 1) && micromips_p;
+       }
+      /* For relocations against an absolute symbol infer the ISA mode
+         from the value of the symbol plus addend.  */
+      else if (bfd_is_abs_section (sec))
+       {
+         target_is_16_bit_code_p = ((symbol + addend) & 1) && !micromips_p;
+         target_is_micromips_code_p = ((symbol + addend) & 1) && micromips_p;
+       }
+      /* Otherwise just use the regular symbol annotation available.  */
+      else
+       {
+         target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
+         target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other);
+       }
     }
   else
     {
@@ -5410,17 +5475,14 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
             http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf  */
          symbol = 0;
        }
-      else if ((*info->callbacks->undefined_symbol)
-              (info, h->root.root.root.string, input_bfd,
-               input_section, relocation->r_offset,
-               (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
-                || ELF_ST_VISIBILITY (h->root.other)))
-       {
-         return bfd_reloc_undefined;
-       }
       else
        {
-         return bfd_reloc_notsupported;
+         (*info->callbacks->undefined_symbol)
+           (info, h->root.root.root.string, input_bfd,
+            input_section, relocation->r_offset,
+            (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
+            || ELF_ST_VISIBILITY (h->root.other));
+         return bfd_reloc_undefined;
        }
 
       target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
@@ -5523,15 +5585,20 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
   else if (h != NULL && h->la25_stub
           && mips_elf_relocation_needs_la25_stub (input_bfd, r_type,
                                                   target_is_16_bit_code_p))
-    symbol = (h->la25_stub->stub_section->output_section->vma
-             + h->la25_stub->stub_section->output_offset
-             + h->la25_stub->offset);
+    {
+       symbol = (h->la25_stub->stub_section->output_section->vma
+                 + h->la25_stub->stub_section->output_offset
+                 + h->la25_stub->offset);
+       if (ELF_ST_IS_MICROMIPS (h->root.other))
+         symbol |= 1;
+    }
   /* For direct MIPS16 and microMIPS calls make sure the compressed PLT
      entry is used if a standard PLT entry has also been made.  In this
      case the symbol will have been set by mips_elf_set_plt_sym_value
      to point to the standard PLT entry, so redirect to the compressed
      one.  */
-  else if ((r_type == R_MIPS16_26 || r_type == R_MICROMIPS_26_S1)
+  else if ((mips16_branch_reloc_p (r_type)
+           || micromips_branch_reloc_p (r_type))
           && !bfd_link_relocatable (info)
           && h != NULL
           && h->use_plt_entry
@@ -5540,7 +5607,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     {
       bfd_boolean micromips_p = MICROMIPS_P (abfd);
 
-      sec = htab->splt;
+      sec = htab->root.splt;
       symbol = (sec->output_section->vma
                + sec->output_offset
                + htab->plt_header_size
@@ -5553,10 +5620,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     }
 
   /* Make sure MIPS16 and microMIPS are not used together.  */
-  if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
+  if ((mips16_branch_reloc_p (r_type) && target_is_micromips_code_p)
       || (micromips_branch_reloc_p (r_type) && target_is_16_bit_code_p))
    {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("MIPS16 and microMIPS functions cannot call each other"));
       return bfd_reloc_notsupported;
    }
@@ -5569,10 +5636,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
      acceptable.  */
   *cross_mode_jump_p = (!bfd_link_relocatable (info)
                        && !(h && h->root.root.type == bfd_link_hash_undefweak)
-                       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
-                           || (r_type == R_MICROMIPS_26_S1
+                       && ((mips16_branch_reloc_p (r_type)
+                            && !target_is_16_bit_code_p)
+                           || (micromips_branch_reloc_p (r_type)
                                && !target_is_micromips_code_p)
-                           || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
+                           || ((branch_reloc_p (r_type)
+                                || r_type == R_MIPS_JALR)
                                && (target_is_16_bit_code_p
                                    || target_is_micromips_code_p))));
 
@@ -5654,7 +5723,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
              if (!TLS_RELOC_P (r_type)
                  && !elf_hash_table (info)->dynamic_sections_created)
                /* This is a static link.  We must initialize the GOT entry.  */
-               MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g);
+               MIPS_ELF_PUT_WORD (dynobj, symbol, htab->root.sgot->contents + g);
            }
        }
       else if (!htab->is_vxworks
@@ -5776,21 +5845,23 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
        /* Shift is 2, unusually, for microMIPS JALX.  */
        shift = (!*cross_mode_jump_p && r_type == R_MICROMIPS_26_S1) ? 1 : 2;
 
-       if (was_local_p)
-         value = addend | ((p + 4) & (0xfc000000 << shift));
-       else if (howto->partial_inplace)
+       if (howto->partial_inplace && !section_p)
          value = _bfd_mips_elf_sign_extend (addend, 26 + shift);
        else
          value = addend;
        value += symbol;
 
-       /* Make sure the target of JALX is word-aligned.  Bit 0 must be
-          the correct ISA mode selector and bit 1 must be 0.  */
-       if (*cross_mode_jump_p && (value & 3) != (r_type == R_MIPS_26))
+       /* Make sure the target of a jump is suitably aligned.  Bit 0 must
+          be the correct ISA mode selector except for weak undefined
+          symbols.  */
+       if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+           && (*cross_mode_jump_p
+               ? (value & 3) != (r_type == R_MIPS_26)
+               : (value & ((1 << shift) - 1)) != (r_type != R_MIPS_26)))
          return bfd_reloc_outofrange;
 
        value >>= shift;
-       if (!was_local_p && h->root.root.type != bfd_link_hash_undefweak)
+       if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
          overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift));
        value &= howto->dst_mask;
       }
@@ -5855,7 +5926,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
            value = mips_elf_high (addend + gp - p - 1);
          else
            value = mips_elf_high (addend + gp - p);
-         overflowed_p = mips_elf_overflow_p (value, 16);
        }
       break;
 
@@ -5977,7 +6047,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       if (howto->partial_inplace)
        addend = _bfd_mips_elf_sign_extend (addend, 18);
 
-      if ((symbol + addend) & 3)
+      /* No need to exclude weak undefined symbols here as they resolve
+         to 0 and never set `*cross_mode_jump_p', so this alignment check
+         will never trigger for them.  */
+      if (*cross_mode_jump_p
+         ? ((symbol + addend) & 3) != 1
+         : ((symbol + addend) & 3) != 0)
        return bfd_reloc_outofrange;
 
       value = symbol + addend - p;
@@ -5987,6 +6062,23 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       value &= howto->dst_mask;
       break;
 
+    case R_MIPS16_PC16_S1:
+      if (howto->partial_inplace)
+       addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend) & 3) != 0
+             : ((symbol + addend) & 1) == 0))
+       return bfd_reloc_outofrange;
+
+      value = symbol + addend - p;
+      if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+       overflowed_p = mips_elf_overflow_p (value, 17);
+      value >>= howto->rightshift;
+      value &= howto->dst_mask;
+      break;
+
     case R_MIPS_PC21_S2:
       if (howto->partial_inplace)
        addend = _bfd_mips_elf_sign_extend (addend, 23);
@@ -6060,6 +6152,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MICROMIPS_PC7_S1:
       if (howto->partial_inplace)
        addend = _bfd_mips_elf_sign_extend (addend, 8);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend + 2) & 3) != 0
+             : ((symbol + addend + 2) & 1) == 0))
+       return bfd_reloc_outofrange;
+
       value = symbol + addend - p;
       if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
        overflowed_p = mips_elf_overflow_p (value, 8);
@@ -6070,6 +6169,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MICROMIPS_PC10_S1:
       if (howto->partial_inplace)
        addend = _bfd_mips_elf_sign_extend (addend, 11);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend + 2) & 3) != 0
+             : ((symbol + addend + 2) & 1) == 0))
+       return bfd_reloc_outofrange;
+
       value = symbol + addend - p;
       if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
        overflowed_p = mips_elf_overflow_p (value, 11);
@@ -6080,6 +6186,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MICROMIPS_PC16_S1:
       if (howto->partial_inplace)
        addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+      if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+         && (*cross_mode_jump_p
+             ? ((symbol + addend) & 3) != 0
+             : ((symbol + addend) & 1) == 0))
+       return bfd_reloc_outofrange;
+
       value = symbol + addend - p;
       if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
        overflowed_p = mips_elf_overflow_p (value, 17);
@@ -6165,7 +6278,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
         when the symbol does not resolve locally.  */
       if (h != NULL && !SYMBOL_CALLS_LOCAL (info, &h->root))
        return bfd_reloc_continue;
+      /* We can't optimize cross-mode jumps either.  */
+      if (*cross_mode_jump_p)
+       return bfd_reloc_continue;
       value = symbol + addend;
+      /* Neither we can non-instruction-aligned targets.  */
+      if (r_type == R_MIPS_JALR ? (value & 3) != 0 : (value & 1) == 0)
+       return bfd_reloc_continue;
       break;
 
     case R_MIPS_PJUMP:
@@ -6238,7 +6357,21 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
   /* Set the field.  */
   x |= (value & howto->dst_mask);
 
-  /* If required, turn JAL into JALX.  */
+  /* Detect incorrect JALX usage.  If required, turn JAL or BAL into JALX.  */
+  if (!cross_mode_jump_p && jal_reloc_p (r_type))
+    {
+      bfd_vma opcode = x >> 26;
+
+      if (r_type == R_MIPS16_26 ? opcode == 0x7
+         : r_type == R_MICROMIPS_26_S1 ? opcode == 0x3c
+         : opcode == 0x1d)
+       {
+         info->callbacks->einfo
+           (_("%X%H: Unsupported JALX to the same ISA mode\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
+       }
+    }
   if (cross_mode_jump_p && jal_reloc_p (r_type))
     {
       bfd_boolean ok;
@@ -6266,18 +6399,65 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
          convert J or JALS to JALX.  */
       if (!ok)
        {
-         (*_bfd_error_handler)
-           (_("%B: %A+0x%lx: Unsupported jump between ISA modes; consider recompiling with interlinking enabled."),
-            input_bfd,
-            input_section,
-            (unsigned long) relocation->r_offset);
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         info->callbacks->einfo
+           (_("%X%H: Unsupported jump between ISA modes; "
+              "consider recompiling with interlinking enabled\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
        }
 
       /* Make this the JALX opcode.  */
       x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
     }
+  else if (cross_mode_jump_p && b_reloc_p (r_type))
+    {
+      bfd_boolean ok = FALSE;
+      bfd_vma opcode = x >> 16;
+      bfd_vma jalx_opcode = 0;
+      bfd_vma addr;
+      bfd_vma dest;
+
+      if (r_type == R_MICROMIPS_PC16_S1)
+       {
+         ok = opcode == 0x4060;
+         jalx_opcode = 0x3c;
+         value <<= 1;
+       }
+      else if (r_type == R_MIPS_PC16 || r_type == R_MIPS_GNU_REL16_S2)
+       {
+         ok = opcode == 0x411;
+         jalx_opcode = 0x1d;
+         value <<= 2;
+       }
+
+      if (ok && !bfd_link_pic (info))
+       {
+         addr = (input_section->output_section->vma
+                 + input_section->output_offset
+                 + relocation->r_offset
+                 + 4);
+         dest = addr + (((value & 0x3ffff) ^ 0x20000) - 0x20000);
+
+         if ((addr >> 28) << 28 != (dest >> 28) << 28)
+           {
+             info->callbacks->einfo
+               (_("%X%H: Cannot convert branch between ISA modes "
+                  "to JALX: relocation out of range\n"),
+                input_bfd, input_section, relocation->r_offset);
+             return TRUE;
+           }
+
+         /* Make this the JALX opcode.  */
+         x = ((dest >> 2) & 0x3ffffff) | jalx_opcode << 26;
+       }
+      else if (!mips_elf_hash_table (info)->ignore_branch_isa)
+       {
+         info->callbacks->einfo
+           (_("%X%H: Unsupported branch between ISA modes\n"),
+            input_bfd, input_section, relocation->r_offset);
+         return TRUE;
+       }
+    }
 
   /* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in
      range.  */
@@ -6285,13 +6465,13 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
       && !cross_mode_jump_p
       && ((JAL_TO_BAL_P (input_bfd)
           && r_type == R_MIPS_26
-          && (x >> 26) == 0x3)         /* jal addr */
+          && (x >> 26) == 0x3)                 /* jal addr */
          || (JALR_TO_BAL_P (input_bfd)
              && r_type == R_MIPS_JALR
-             && x == 0x0320f809)       /* jalr t9 */
+             && x == 0x0320f809)               /* jalr t9 */
          || (JR_TO_B_P (input_bfd)
              && r_type == R_MIPS_JALR
-             && x == 0x03200008)))     /* jr t9 */
+             && (x & ~1) == 0x03200008)))      /* jr t9 / jalr zero, t9 */
     {
       bfd_vma addr;
       bfd_vma dest;
@@ -6308,7 +6488,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
       off = dest - addr;
       if (off <= 0x1ffff && off >= -0x20000)
        {
-         if (x == 0x03200008)  /* jr t9 */
+         if ((x & ~1) == 0x03200008)           /* jr t9 / jalr zero, t9 */
            x = 0x10000000 | (((bfd_vma) off >> 2) & 0xffff);   /* b addr */
          else
            x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff);   /* bal addr */
@@ -6946,7 +7126,8 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr)
                                        &intopt);
          if (intopt.size < sizeof (Elf_External_Options))
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: Warning: bad `%s' option size %u smaller than its header"),
                abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
              break;
@@ -7179,7 +7360,8 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
                                        &intopt);
          if (intopt.size < sizeof (Elf_External_Options))
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: Warning: bad `%s' option size %u smaller than its header"),
                abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
              break;
@@ -7725,22 +7907,6 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (!_bfd_elf_create_dynamic_sections (abfd, info))
     return FALSE;
 
-  /* Cache the sections created above.  */
-  htab->splt = bfd_get_linker_section (abfd, ".plt");
-  htab->sdynbss = bfd_get_linker_section (abfd, ".dynbss");
-  if (htab->is_vxworks)
-    {
-      htab->srelbss = bfd_get_linker_section (abfd, ".rela.bss");
-      htab->srelplt = bfd_get_linker_section (abfd, ".rela.plt");
-    }
-  else
-    htab->srelplt = bfd_get_linker_section (abfd, ".rel.plt");
-  if (!htab->sdynbss
-      || (htab->is_vxworks && !htab->srelbss && !bfd_link_pic (info))
-      || !htab->srelplt
-      || !htab->splt)
-    abort ();
-
   /* Do the usual VxWorks handling.  */
   if (htab->is_vxworks
       && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
@@ -7949,7 +8115,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
       if (r_symndx == 0)
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: Warning: cannot determine the target function for"
               " stub section `%s'"),
             abfd, name);
@@ -8074,7 +8241,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
       if (r_symndx == 0)
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: Warning: cannot determine the target function for"
               " stub section `%s'"),
             abfd, name);
@@ -8205,7 +8373,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        h = NULL;
       else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: Malformed reloc detected for section %s"),
             abfd, name);
          bfd_set_error (bfd_error_bad_value);
@@ -8280,7 +8449,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            return FALSE;
          if (htab->is_vxworks && !bfd_link_pic (info))
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: GOT reloc at 0x%lx not expected in executables"),
                 abfd, (unsigned long) rel->r_offset);
              bfd_set_error (bfd_error_bad_value);
@@ -8341,6 +8511,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MIPS_PC21_S2:
        case R_MIPS_PC26_S2:
        case R_MIPS16_26:
+       case R_MIPS16_PC16_S1:
        case R_MICROMIPS_26_S1:
        case R_MICROMIPS_PC7_S1:
        case R_MICROMIPS_PC10_S1:
@@ -8416,7 +8587,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_MICROMIPS_CALL16:
          if (h == NULL)
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
                 abfd, (unsigned long) rel->r_offset);
              bfd_set_error (bfd_error_bad_value);
@@ -8634,7 +8806,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          a PLT entry is not created because the symbol is satisfied
          locally.  */
       if (h != NULL
-         && jal_reloc_p (r_type)
+         && (branch_reloc_p (r_type)
+             || mips16_branch_reloc_p (r_type)
+             || micromips_branch_reloc_p (r_type))
          && !SYMBOL_CALLS_LOCAL (info, h))
        {
          if (h->plt.plist == NULL)
@@ -8642,7 +8816,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (h->plt.plist == NULL)
            return FALSE;
 
-         if (r_type == R_MIPS_26)
+         if (branch_reloc_p (r_type))
            h->plt.plist->need_mips = TRUE;
          else
            h->plt.plist->need_comp = TRUE;
@@ -8699,7 +8873,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_MIPS_26:
            case R_MICROMIPS_26_S1:
              howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: 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");
@@ -8714,167 +8889,6 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 \f
-bfd_boolean
-_bfd_mips_relax_section (bfd *abfd, asection *sec,
-                        struct bfd_link_info *link_info,
-                        bfd_boolean *again)
-{
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irel, *irelend;
-  Elf_Internal_Shdr *symtab_hdr;
-  bfd_byte *contents = NULL;
-  size_t extsymoff;
-  bfd_boolean changed_contents = FALSE;
-  bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
-  Elf_Internal_Sym *isymbuf = NULL;
-
-  /* We are not currently changing any sizes, so only one pass.  */
-  *again = FALSE;
-
-  if (bfd_link_relocatable (link_info))
-    return TRUE;
-
-  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
-                                              link_info->keep_memory);
-  if (internal_relocs == NULL)
-    return TRUE;
-
-  irelend = internal_relocs + sec->reloc_count
-    * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel;
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
-
-  for (irel = internal_relocs; irel < irelend; irel++)
-    {
-      bfd_vma symval;
-      bfd_signed_vma sym_offset;
-      unsigned int r_type;
-      unsigned long r_symndx;
-      asection *sym_sec;
-      unsigned long instruction;
-
-      /* Turn jalr into bgezal, and jr into beq, if they're marked
-        with a JALR relocation, that indicate where they jump to.
-        This saves some pipeline bubbles.  */
-      r_type = ELF_R_TYPE (abfd, irel->r_info);
-      if (r_type != R_MIPS_JALR)
-       continue;
-
-      r_symndx = ELF_R_SYM (abfd, irel->r_info);
-      /* Compute the address of the jump target.  */
-      if (r_symndx >= extsymoff)
-       {
-         struct mips_elf_link_hash_entry *h
-           = ((struct mips_elf_link_hash_entry *)
-              elf_sym_hashes (abfd) [r_symndx - extsymoff]);
-
-         while (h->root.root.type == bfd_link_hash_indirect
-                || h->root.root.type == bfd_link_hash_warning)
-           h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
-         /* If a symbol is undefined, or if it may be overridden,
-            skip it.  */
-         if (! ((h->root.root.type == bfd_link_hash_defined
-                 || h->root.root.type == bfd_link_hash_defweak)
-                && h->root.root.u.def.section)
-             || (bfd_link_pic (link_info) && ! link_info->symbolic
-                 && !h->root.forced_local))
-           continue;
-
-         sym_sec = h->root.root.u.def.section;
-         if (sym_sec->output_section)
-           symval = (h->root.root.u.def.value
-                     + sym_sec->output_section->vma
-                     + sym_sec->output_offset);
-         else
-           symval = h->root.root.u.def.value;
-       }
-      else
-       {
-         Elf_Internal_Sym *isym;
-
-         /* Read this BFD's symbols if we haven't done so already.  */
-         if (isymbuf == NULL && symtab_hdr->sh_info != 0)
-           {
-             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
-             if (isymbuf == NULL)
-               isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
-                                               symtab_hdr->sh_info, 0,
-                                               NULL, NULL, NULL);
-             if (isymbuf == NULL)
-               goto relax_return;
-           }
-
-         isym = isymbuf + r_symndx;
-         if (isym->st_shndx == SHN_UNDEF)
-           continue;
-         else if (isym->st_shndx == SHN_ABS)
-           sym_sec = bfd_abs_section_ptr;
-         else if (isym->st_shndx == SHN_COMMON)
-           sym_sec = bfd_com_section_ptr;
-         else
-           sym_sec
-             = bfd_section_from_elf_index (abfd, isym->st_shndx);
-         symval = isym->st_value
-           + sym_sec->output_section->vma
-           + sym_sec->output_offset;
-       }
-
-      /* Compute branch offset, from delay slot of the jump to the
-        branch target.  */
-      sym_offset = (symval + irel->r_addend)
-       - (sec_start + irel->r_offset + 4);
-
-      /* Branch offset must be properly aligned.  */
-      if ((sym_offset & 3) != 0)
-       continue;
-
-      sym_offset >>= 2;
-
-      /* Check that it's in range.  */
-      if (sym_offset < -0x8000 || sym_offset >= 0x8000)
-       continue;
-
-      /* Get the section contents if we haven't done so already.  */
-      if (!mips_elf_get_section_contents (abfd, sec, &contents))
-       goto relax_return;
-
-      instruction = bfd_get_32 (abfd, contents + irel->r_offset);
-
-      /* If it was jalr <reg>, turn it into bgezal $zero, <target>.  */
-      if ((instruction & 0xfc1fffff) == 0x0000f809)
-       instruction = 0x04110000;
-      /* If it was jr <reg>, turn it into b <target>.  */
-      else if ((instruction & 0xfc1fffff) == 0x00000008)
-       instruction = 0x10000000;
-      else
-       continue;
-
-      instruction |= (sym_offset & 0xffff);
-      bfd_put_32 (abfd, instruction, contents + irel->r_offset);
-      changed_contents = TRUE;
-    }
-
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    {
-      if (!changed_contents && !link_info->keep_memory)
-        free (contents);
-      else
-        {
-          /* Cache the section contents for elf_link_input_bfd.  */
-          elf_section_data (sec)->this_hdr.contents = contents;
-        }
-    }
-  return TRUE;
-
- relax_return:
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    free (contents);
-  return FALSE;
-}
-\f
 /* Allocate space for global sym dynamic relocs.  */
 
 static bfd_boolean
@@ -8970,6 +8984,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   bfd *dynobj;
   struct mips_elf_link_hash_entry *hmips;
   struct mips_elf_link_hash_table *htab;
+  asection *s, *srel;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
@@ -9036,7 +9051,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
          for PLT offset calculations.  */
       if (htab->plt_mips_offset + htab->plt_comp_offset == 0)
        {
-         BFD_ASSERT (htab->sgotplt->size == 0);
+         BFD_ASSERT (htab->root.sgotplt->size == 0);
          BFD_ASSERT (htab->plt_got_index == 0);
 
          /* If we're using the PLT additions to the psABI, each PLT
@@ -9044,12 +9059,12 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             Encourage better cache usage by aligning.  We do this
             lazily to avoid pessimizing traditional objects.  */
          if (!htab->is_vxworks
-             && !bfd_set_section_alignment (dynobj, htab->splt, 5))
+             && !bfd_set_section_alignment (dynobj, htab->root.splt, 5))
            return FALSE;
 
          /* Make sure that .got.plt is word-aligned.  We do this lazily
             for the same reason as above.  */
-         if (!bfd_set_section_alignment (dynobj, htab->sgotplt,
+         if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt,
                                          MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
            return FALSE;
 
@@ -9154,9 +9169,9 @@ _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->srelplt->size += (htab->is_vxworks
-                             ? MIPS_ELF_RELA_SIZE (dynobj)
-                             : MIPS_ELF_REL_SIZE (dynobj));
+      htab->root.srelplt->size += (htab->is_vxworks
+                                  ? MIPS_ELF_RELA_SIZE (dynobj)
+                                  : MIPS_ELF_REL_SIZE (dynobj));
 
       /* Make room for the .rela.plt.unloaded relocations.  */
       if (htab->is_vxworks && !bfd_link_pic (info))
@@ -9195,9 +9210,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      some that we can't convert.  */
   if (!htab->use_plts_and_copy_relocs || bfd_link_pic (info))
     {
-      (*_bfd_error_handler) (_("non-dynamic relocations refer to "
-                              "dynamic symbol %s"),
-                            h->root.root.string);
+      _bfd_error_handler (_("non-dynamic relocations refer to "
+                           "dynamic symbol %s"),
+                         h->root.root.string);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
@@ -9212,10 +9227,20 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      both the dynamic object and the regular object will refer to the
      same memory location for the variable.  */
 
+  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+    {
+      s = htab->root.sdynrelro;
+      srel = htab->root.sreldynrelro;
+    }
+  else
+    {
+      s = htab->root.sdynbss;
+      srel = htab->root.srelbss;
+    }
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
     {
       if (htab->is_vxworks)
-       htab->srelbss->size += sizeof (Elf32_External_Rela);
+       srel->size += sizeof (Elf32_External_Rela);
       else
        mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
       h->needs_copy = 1;
@@ -9225,7 +9250,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      dynamic will now refer to the local copy instead.  */
   hmips->possibly_dynamic_relocs = 0;
 
-  return _bfd_elf_adjust_dynamic_copy (info, h, htab->sdynbss);
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 \f
 /* This function is called after all the input files have been read,
@@ -9281,7 +9306,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  s = htab->sgot;
+  s = htab->root.sgot;
   if (s == NULL)
     return TRUE;
 
@@ -9559,7 +9584,7 @@ mips_elf_set_plt_sym_value (struct mips_elf_link_hash_entry *h, void *data)
       if (htab->is_vxworks)
        val += 8;
 
-      h->root.root.u.def.section = htab->splt;
+      h->root.root.u.def.section = htab->root.splt;
       h->root.root.u.def.value = val;
       h->root.other = other;
     }
@@ -9608,7 +9633,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
 
          Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we
          haven't already in _bfd_elf_create_dynamic_sections.  */
-      if (htab->splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
+      if (htab->root.splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
        {
          bfd_boolean micromips_p = (MICROMIPS_P (output_bfd)
                                     && !htab->plt_mips_offset);
@@ -9618,8 +9643,8 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
          bfd_vma size;
 
          BFD_ASSERT (htab->use_plts_and_copy_relocs);
-         BFD_ASSERT (htab->sgotplt->size == 0);
-         BFD_ASSERT (htab->splt->size == 0);
+         BFD_ASSERT (htab->root.sgotplt->size == 0);
+         BFD_ASSERT (htab->root.splt->size == 0);
 
          if (htab->is_vxworks && bfd_link_pic (info))
            size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
@@ -9638,17 +9663,17 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
 
          htab->plt_header_is_comp = micromips_p;
          htab->plt_header_size = size;
-         htab->splt->size = (size
-                             + htab->plt_mips_offset
-                             + htab->plt_comp_offset);
-         htab->sgotplt->size = (htab->plt_got_index
-                                * MIPS_ELF_GOT_SIZE (dynobj));
+         htab->root.splt->size = (size
+                                  + htab->plt_mips_offset
+                                  + htab->plt_comp_offset);
+         htab->root.sgotplt->size = (htab->plt_got_index
+                                     * MIPS_ELF_GOT_SIZE (dynobj));
 
          mips_elf_link_hash_traverse (htab, mips_elf_set_plt_sym_value, info);
 
          if (htab->root.hplt == NULL)
            {
-             h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt,
+             h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.splt,
                                               "_PROCEDURE_LINKAGE_TABLE_");
              htab->root.hplt = h;
              if (h == NULL)
@@ -9734,7 +9759,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
       else if (SGI_COMPAT (output_bfd)
               && CONST_STRNEQ (name, ".compact_rel"))
        s->size += mips_elf_hash_table (info)->compact_rel_size;
-      else if (s == htab->splt)
+      else if (s == htab->root.splt)
        {
          /* If the last PLT entry has a branch delay slot, allocate
             room for an extra nop to fill the delay slot.  This is
@@ -9744,10 +9769,11 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
            s->size += 4;
        }
       else if (! CONST_STRNEQ (name, ".init")
-              && s != htab->sgot
-              && s != htab->sgotplt
+              && s != htab->root.sgot
+              && s != htab->root.sgotplt
               && s != htab->sstubs
-              && s != htab->sdynbss)
+              && s != htab->root.sdynbss
+              && s != htab->root.sdynrelro)
        {
          /* It's not one of our sections, so don't allocate space.  */
          continue;
@@ -9877,7 +9903,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
              && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
            return FALSE;
        }
-      if (htab->splt->size > 0)
+      if (htab->root.splt->size > 0)
        {
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
            return FALSE;
@@ -10104,7 +10130,8 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                        name = bfd_elf_sym_name (input_bfd, symtab_hdr,
                                                 local_syms + r_symndx,
                                                 sec);
-                     (*_bfd_error_handler)
+                     _bfd_error_handler
+                       /* xgettext:c-format */
                        (_("%B: Can't find matching LO16 reloc against `%s' for %s at 0x%lx in section `%A'"),
                         input_bfd, input_section, name, howto->name,
                         rel->r_offset);
@@ -10250,10 +10277,9 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  htab->small_data_overflow_reported = TRUE;
                  (*info->callbacks->einfo) ("%P: %s\n", msg);
                }
-             if (! ((*info->callbacks->reloc_overflow)
-                    (info, NULL, name, howto->name, (bfd_vma) 0,
-                     input_bfd, input_section, rel->r_offset)))
-               return FALSE;
+             (*info->callbacks->reloc_overflow)
+               (info, NULL, name, howto->name, (bfd_vma) 0,
+                input_bfd, input_section, rel->r_offset);
            }
          break;
 
@@ -10263,7 +10289,17 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case bfd_reloc_outofrange:
          msg = NULL;
          if (jal_reloc_p (howto->type))
-           msg = _("JALX to a non-word-aligned address");
+           msg = (cross_mode_jump_p
+                  ? _("Cannot convert a jump to JALX "
+                      "for a non-word-aligned address")
+                  : (howto->type == R_MIPS16_26
+                     ? _("Jump to a non-word-aligned address")
+                     : _("Jump to a non-instruction-aligned address")));
+         else if (b_reloc_p (howto->type))
+           msg = (cross_mode_jump_p
+                  ? _("Cannot convert a branch to JALX "
+                      "for a non-word-aligned address")
+                  : _("Branch to a non-instruction-aligned address"));
          else if (aligned_pcrel_reloc_p (howto->type))
            msg = _("PC-relative load from unaligned address");
          if (msg)
@@ -10519,25 +10555,25 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 
       BFD_ASSERT (htab->use_plts_and_copy_relocs);
       BFD_ASSERT (h->dynindx != -1);
-      BFD_ASSERT (htab->splt != NULL);
+      BFD_ASSERT (htab->root.splt != NULL);
       BFD_ASSERT (got_index != MINUS_ONE);
       BFD_ASSERT (!h->def_regular);
 
       /* Calculate the address of the PLT header.  */
       isa_bit = htab->plt_header_is_comp;
-      header_address = (htab->splt->output_section->vma
-                       + htab->splt->output_offset + isa_bit);
+      header_address = (htab->root.splt->output_section->vma
+                       + htab->root.splt->output_offset + isa_bit);
 
       /* Calculate the address of the .got.plt entry.  */
-      got_address = (htab->sgotplt->output_section->vma
-                    + htab->sgotplt->output_offset
+      got_address = (htab->root.sgotplt->output_section->vma
+                    + htab->root.sgotplt->output_offset
                     + got_index * MIPS_ELF_GOT_SIZE (dynobj));
 
       got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
       got_address_low = got_address & 0xffff;
 
       /* Initially point the .got.plt entry at the PLT header.  */
-      loc = (htab->sgotplt->contents + got_index * MIPS_ELF_GOT_SIZE (dynobj));
+      loc = (htab->root.sgotplt->contents + got_index * MIPS_ELF_GOT_SIZE (dynobj));
       if (ABI_64_P (output_bfd))
        bfd_put_64 (output_bfd, header_address, loc);
       else
@@ -10552,10 +10588,10 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 
          plt_offset = htab->plt_header_size + h->plt.plist->mips_offset;
 
-         BFD_ASSERT (plt_offset <= htab->splt->size);
+         BFD_ASSERT (plt_offset <= htab->root.splt->size);
 
          /* Find out where the .plt entry should go.  */
-         loc = htab->splt->contents + plt_offset;
+         loc = htab->root.splt->contents + plt_offset;
 
          /* Pick the load opcode.  */
          load = MIPS_ELF_LOAD_WORD (output_bfd);
@@ -10591,10 +10627,10 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
          plt_offset = (htab->plt_header_size + htab->plt_mips_offset
                        + h->plt.plist->comp_offset);
 
-         BFD_ASSERT (plt_offset <= htab->splt->size);
+         BFD_ASSERT (plt_offset <= htab->root.splt->size);
 
          /* Find out where the .plt entry should go.  */
-         loc = htab->splt->contents + plt_offset;
+         loc = htab->root.splt->contents + plt_offset;
 
          /* Fill in the PLT entry itself.  */
          if (!MICROMIPS_P (output_bfd))
@@ -10630,19 +10666,20 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 
              BFD_ASSERT (got_address % 4 == 0);
 
-             loc_address = (htab->splt->output_section->vma
-                            + htab->splt->output_offset + plt_offset);
+             loc_address = (htab->root.splt->output_section->vma
+                            + htab->root.splt->output_offset + plt_offset);
              gotpc_offset = got_address - ((loc_address | 3) ^ 3);
 
              /* ADDIUPC has a span of +/-16MB, check we're in range.  */
              if (gotpc_offset + 0x1000000 >= 0x2000000)
                {
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
+                   /* xgettext:c-format */
                    (_("%B: `%A' offset of %ld from `%A' "
                       "beyond the range of ADDIUPC"),
                     output_bfd,
-                    htab->sgotplt->output_section,
-                    htab->splt->output_section,
+                    htab->root.sgotplt->output_section,
+                    htab->root.splt->output_section,
                     (long) gotpc_offset);
                  bfd_set_error (bfd_error_no_error);
                  return FALSE;
@@ -10658,7 +10695,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
        }
 
       /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry.  */
-      mips_elf_output_dynamic_relocation (output_bfd, htab->srelplt,
+      mips_elf_output_dynamic_relocation (output_bfd, htab->root.srelplt,
                                          got_index - 2, h->dynindx,
                                          R_MIPS_JUMP_SLOT, got_address);
 
@@ -10822,7 +10859,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
   BFD_ASSERT (h->dynindx != -1
              || h->forced_local);
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   g = htab->got_info;
   BFD_ASSERT (g != NULL);
 
@@ -10858,7 +10895,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
                                                           &e)))
            {
              offset = p->gotidx;
-             BFD_ASSERT (offset > 0 && offset < htab->sgot->size);
+             BFD_ASSERT (offset > 0 && offset < htab->root.sgot->size);
              if (bfd_link_pic (info)
                  || (elf_hash_table (info)->dynamic_sections_created
                      && p->d.h != NULL
@@ -11005,18 +11042,18 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
       gotplt_index = h->plt.plist->gotplt_index;
 
       BFD_ASSERT (h->dynindx != -1);
-      BFD_ASSERT (htab->splt != NULL);
+      BFD_ASSERT (htab->root.splt != NULL);
       BFD_ASSERT (gotplt_index != MINUS_ONE);
-      BFD_ASSERT (plt_offset <= htab->splt->size);
+      BFD_ASSERT (plt_offset <= htab->root.splt->size);
 
       /* Calculate the address of the .plt entry.  */
-      plt_address = (htab->splt->output_section->vma
-                    + htab->splt->output_offset
+      plt_address = (htab->root.splt->output_section->vma
+                    + htab->root.splt->output_offset
                     + plt_offset);
 
       /* Calculate the address of the .got.plt entry.  */
-      got_address = (htab->sgotplt->output_section->vma
-                    + htab->sgotplt->output_offset
+      got_address = (htab->root.sgotplt->output_section->vma
+                    + htab->root.sgotplt->output_offset
                     + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd));
 
       /* Calculate the offset of the .got.plt entry from
@@ -11029,11 +11066,11 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
 
       /* Fill in the initial value of the .got.plt entry.  */
       bfd_put_32 (output_bfd, plt_address,
-                 (htab->sgotplt->contents
+                 (htab->root.sgotplt->contents
                   + gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd)));
 
       /* Find out where the .plt entry should go.  */
-      loc = htab->splt->contents + plt_offset;
+      loc = htab->root.splt->contents + plt_offset;
 
       if (bfd_link_pic (info))
        {
@@ -11082,7 +11119,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
        }
 
       /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry.  */
-      loc = (htab->srelplt->contents
+      loc = (htab->root.srelplt->contents
             + gotplt_index * sizeof (Elf32_External_Rela));
       rel.r_offset = got_address;
       rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_JUMP_SLOT);
@@ -11095,7 +11132,7 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
 
   BFD_ASSERT (h->dynindx != -1 || h->forced_local);
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   g = htab->got_info;
   BFD_ASSERT (g != NULL);
 
@@ -11126,6 +11163,8 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
   if (h->needs_copy)
     {
       Elf_Internal_Rela rel;
+      asection *srel;
+      bfd_byte *loc;
 
       BFD_ASSERT (h->dynindx != -1);
 
@@ -11134,11 +11173,13 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
                      + h->root.u.def.value);
       rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_COPY);
       rel.r_addend = 0;
-      bfd_elf32_swap_reloca_out (output_bfd, &rel,
-                                htab->srelbss->contents
-                                + (htab->srelbss->reloc_count
-                                   * sizeof (Elf32_External_Rela)));
-      ++htab->srelbss->reloc_count;
+      if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+       srel = htab->root.sreldynrelro;
+      else
+       srel = htab->root.srelbss;
+      loc = srel->contents + srel->reloc_count * sizeof (Elf32_External_Rela);
+      bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
+      ++srel->reloc_count;
     }
 
   /* If this is a mips16/microMIPS symbol, force the value to be even.  */
@@ -11173,8 +11214,8 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
     plt_entry = micromips_o32_exec_plt0_entry;
 
   /* Calculate the value of .got.plt.  */
-  gotplt_value = (htab->sgotplt->output_section->vma
-                 + htab->sgotplt->output_offset);
+  gotplt_value = (htab->root.sgotplt->output_section->vma
+                 + htab->root.sgotplt->output_offset);
   gotplt_value_high = ((gotplt_value + 0x8000) >> 16) & 0xffff;
   gotplt_value_low = gotplt_value & 0xffff;
 
@@ -11184,7 +11225,7 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
              || ~(gotplt_value | 0x7fffffff) == 0);
 
   /* Install the PLT header.  */
-  loc = htab->splt->contents;
+  loc = htab->root.splt->contents;
   if (plt_entry == micromips_o32_exec_plt0_entry)
     {
       bfd_vma gotpc_offset;
@@ -11193,18 +11234,19 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
 
       BFD_ASSERT (gotplt_value % 4 == 0);
 
-      loc_address = (htab->splt->output_section->vma
-                    + htab->splt->output_offset);
+      loc_address = (htab->root.splt->output_section->vma
+                    + htab->root.splt->output_offset);
       gotpc_offset = gotplt_value - ((loc_address | 3) ^ 3);
 
       /* ADDIUPC has a span of +/-16MB, check we're in range.  */
       if (gotpc_offset + 0x1000000 >= 0x2000000)
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: `%A' offset of %ld from `%A' beyond the range of ADDIUPC"),
             output_bfd,
-            htab->sgotplt->output_section,
-            htab->splt->output_section,
+            htab->root.sgotplt->output_section,
+            htab->root.splt->output_section,
             (long) gotpc_offset);
          bfd_set_error (bfd_error_no_error);
          return FALSE;
@@ -11269,10 +11311,11 @@ mips_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
   got_value_low = got_value & 0xffff;
 
   /* Calculate the address of the PLT header.  */
-  plt_address = htab->splt->output_section->vma + htab->splt->output_offset;
+  plt_address = (htab->root.splt->output_section->vma
+                + htab->root.splt->output_offset);
 
   /* Install the PLT header.  */
-  loc = htab->splt->contents;
+  loc = htab->root.splt->contents;
   bfd_put_32 (output_bfd, plt_entry[0] | got_value_high, loc);
   bfd_put_32 (output_bfd, plt_entry[1] | got_value_low, loc + 4);
   bfd_put_32 (output_bfd, plt_entry[2], loc + 8);
@@ -11333,7 +11376,7 @@ mips_vxworks_finish_shared_plt (bfd *output_bfd, struct bfd_link_info *info)
   /* We just need to copy the entry byte-by-byte.  */
   for (i = 0; i < ARRAY_SIZE (mips_vxworks_shared_plt0_entry); i++)
     bfd_put_32 (output_bfd, mips_vxworks_shared_plt0_entry[i],
-               htab->splt->contents + i * 4);
+               htab->root.splt->contents + i * 4);
 }
 
 /* Finish up the dynamic sections.  */
@@ -11355,7 +11398,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 
   sdyn = bfd_get_linker_section (dynobj, ".dynamic");
 
-  sgot = htab->sgot;
+  sgot = htab->root.sgot;
   gg = htab->got_info;
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -11403,12 +11446,12 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              break;
 
            case DT_PLTGOT:
-             s = htab->sgot;
+             s = htab->root.sgot;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_MIPS_PLTGOT:
-             s = htab->sgotplt;
+             s = htab->root.sgotplt;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
@@ -11463,7 +11506,8 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
                }
              /* In case if we don't have global got symbols we default
                 to setting DT_MIPS_GOTSYM to the same value as
-                DT_MIPS_SYMTABNO, so we just fall through.  */
+                DT_MIPS_SYMTABNO.  */
+             /* Fall through.  */
 
            case DT_MIPS_SYMTABNO:
              name = ".dynsym";
@@ -11528,13 +11572,6 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
              dyn.d_un.d_ptr = s->vma;
              break;
 
-           case DT_RELASZ:
-             BFD_ASSERT (htab->is_vxworks);
-             /* The count does not include the JUMP_SLOT relocations.  */
-             if (htab->srelplt)
-               dyn.d_un.d_val -= htab->srelplt->size;
-             break;
-
            case DT_PLTREL:
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
              if (htab->is_vxworks)
@@ -11545,13 +11582,13 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 
            case DT_PLTRELSZ:
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
-             dyn.d_un.d_val = htab->srelplt->size;
+             dyn.d_un.d_val = htab->root.srelplt->size;
              break;
 
            case DT_JMPREL:
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
-             dyn.d_un.d_ptr = (htab->srelplt->output_section->vma
-                               + htab->srelplt->output_offset);
+             dyn.d_un.d_ptr = (htab->root.srelplt->output_section->vma
+                               + htab->root.srelplt->output_offset);
              break;
 
            case DT_TEXTREL:
@@ -11782,7 +11819,7 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
       }
   }
 
-  if (htab->splt && htab->splt->size > 0)
+  if (htab->root.splt && htab->root.splt->size > 0)
     {
       if (htab->is_vxworks)
        {
@@ -12929,25 +12966,22 @@ _bfd_elf_mips_get_relocated_section_contents
              switch (r)
                {
                case bfd_reloc_undefined:
-                 if (!((*link_info->callbacks->undefined_symbol)
-                       (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
-                        input_bfd, input_section, (*parent)->address, TRUE)))
-                   goto error_return;
+                 (*link_info->callbacks->undefined_symbol)
+                   (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                    input_bfd, input_section, (*parent)->address, TRUE);
                  break;
                case bfd_reloc_dangerous:
                  BFD_ASSERT (error_message != NULL);
-                 if (!((*link_info->callbacks->reloc_dangerous)
-                       (link_info, error_message, input_bfd, input_section,
-                        (*parent)->address)))
-                   goto error_return;
+                 (*link_info->callbacks->reloc_dangerous)
+                   (link_info, error_message,
+                    input_bfd, input_section, (*parent)->address);
                  break;
                case bfd_reloc_overflow:
-                 if (!((*link_info->callbacks->reloc_overflow)
-                       (link_info, NULL,
-                        bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
-                        (*parent)->howto->name, (*parent)->addend,
-                        input_bfd, input_section, (*parent)->address)))
-                   goto error_return;
+                 (*link_info->callbacks->reloc_overflow)
+                   (link_info, NULL,
+                    bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                    (*parent)->howto->name, (*parent)->addend,
+                    input_bfd, input_section, (*parent)->address);
                  break;
                case bfd_reloc_outofrange:
                default:
@@ -13916,12 +13950,15 @@ _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.  */
+   32-bit microMIPS instructions, and between making or ignoring
+   branch relocation checks for invalid transitions between ISA modes.  */
 
 void
-_bfd_mips_elf_insn32 (struct bfd_link_info *info, bfd_boolean on)
+_bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
+                           bfd_boolean ignore_branch_isa)
 {
-  mips_elf_hash_table (info)->insn32 = on;
+  mips_elf_hash_table (info)->insn32 = insn32;
+  mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
 }
 \f
 /* Structure for saying that BFD machine EXTENSION extends BASE.  */
@@ -14115,7 +14152,8 @@ update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags)
     case E_MIPS_ARCH_64R2: new_isa = LEVEL_REV (64, 2); break;
     case E_MIPS_ARCH_64R6: new_isa = LEVEL_REV (64, 6); break;
     default:
-      (*_bfd_error_handler)
+      _bfd_error_handler
+       /* xgettext:c-format */
        (_("%B: Unknown architecture %s"),
         abfd, bfd_printable_name (abfd));
     }
@@ -14644,7 +14682,8 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            gptab_bss_sec = o;
          else
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%s: illegal section name `%s'"),
                 bfd_get_filename (abfd), o->name);
              bfd_set_error (bfd_error_nonrepresentable_section);
@@ -14883,8 +14922,9 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
    if there are conflicting settings.  */
 
 static bfd_boolean
-mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
+mips_elf_merge_obj_e_flags (bfd *ibfd, struct bfd_link_info *info)
 {
+  bfd *obfd = info->output_bfd;
   struct mips_elf_obj_tdata *out_tdata = mips_elf_tdata (obfd);
   flagword old_flags;
   flagword new_flags;
@@ -14921,7 +14961,7 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
   if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
       != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("%B: warning: linking abicalls files with non-abicalls files"),
         ibfd);
       ok = TRUE;
@@ -14938,7 +14978,7 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
   /* Compare the ISAs.  */
   if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("%B: linking 32-bit code with 64-bit code"),
         ibfd);
       ok = FALSE;
@@ -14969,7 +15009,8 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
       else
        {
          /* The ISAs aren't compatible.  */
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: linking %s module with previous %s modules"),
             ibfd,
             bfd_printable_name (ibfd),
@@ -14992,7 +15033,8 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
          || (elf_elfheader (ibfd)->e_ident[EI_CLASS]
              != elf_elfheader (obfd)->e_ident[EI_CLASS]))
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: ABI mismatch: linking %s module with previous %s modules"),
             ibfd,
             elf_mips_abi_name (ibfd),
@@ -15016,7 +15058,8 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
 
       if (m16_mis || micro_mis)
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: ASE mismatch: linking %s module with previous %s modules"),
             ibfd,
             m16_mis ? "MIPS16" : "microMIPS",
@@ -15033,6 +15076,7 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
   /* Compare NaN encodings.  */
   if ((new_flags & EF_MIPS_NAN2008) != (old_flags & EF_MIPS_NAN2008))
     {
+      /* xgettext:c-format */
       _bfd_error_handler (_("%B: linking %s module with previous %s modules"),
                          ibfd,
                          (new_flags & EF_MIPS_NAN2008
@@ -15047,6 +15091,7 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
   /* Compare FP64 state.  */
   if ((new_flags & EF_MIPS_FP64) != (old_flags & EF_MIPS_FP64))
     {
+      /* xgettext:c-format */
       _bfd_error_handler (_("%B: linking %s module with previous %s modules"),
                          ibfd,
                          (new_flags & EF_MIPS_FP64
@@ -15061,7 +15106,8 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
   /* Warn about any other mismatches */
   if (new_flags != old_flags)
     {
-      (*_bfd_error_handler)
+      /* xgettext:c-format */
+      _bfd_error_handler
        (_("%B: uses different e_flags (0x%lx) fields than previous modules "
           "(0x%lx)"),
         ibfd, (unsigned long) new_flags,
@@ -15075,8 +15121,9 @@ mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
 /* Merge object attributes from IBFD into OBFD.  Raise an error if
    there are conflicting attributes.  */
 static bfd_boolean
-mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+mips_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
+  bfd *obfd = info->output_bfd;
   obj_attribute *in_attr;
   obj_attribute *out_attr;
   bfd *abi_fp_bfd;
@@ -15146,17 +15193,20 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
          in_string = _bfd_mips_fp_abi_string (in_fp);
          /* First warn about cases involving unrecognised ABIs.  */
          if (!out_string && !in_string)
+           /* xgettext:c-format */
            _bfd_error_handler
              (_("Warning: %B uses unknown floating point ABI %d "
                 "(set by %B), %B uses unknown floating point ABI %d"),
               obfd, abi_fp_bfd, ibfd, out_fp, in_fp);
          else if (!out_string)
            _bfd_error_handler
+             /* xgettext:c-format */
              (_("Warning: %B uses unknown floating point ABI %d "
                 "(set by %B), %B uses %s"),
               obfd, abi_fp_bfd, ibfd, out_fp, in_string);
          else if (!in_string)
            _bfd_error_handler
+             /* xgettext:c-format */
              (_("Warning: %B uses %s (set by %B), "
                 "%B uses unknown floating point ABI %d"),
               obfd, abi_fp_bfd, ibfd, out_string, in_fp);
@@ -15170,6 +15220,7 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
              else if (out_fp == Val_GNU_MIPS_ABI_FP_SOFT)
                in_string = "-mhard-float";
              _bfd_error_handler
+               /* xgettext:c-format */
                (_("Warning: %B uses %s (set by %B), %B uses %s"),
                 obfd, abi_fp_bfd, ibfd, out_string, in_string);
            }
@@ -15188,6 +15239,7 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
          {
          case Val_GNU_MIPS_ABI_MSA_128:
            _bfd_error_handler
+             /* xgettext:c-format */
              (_("Warning: %B uses %s (set by %B), "
                 "%B uses unknown MSA ABI %d"),
               obfd, abi_msa_bfd, ibfd,
@@ -15199,6 +15251,7 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
              {
              case Val_GNU_MIPS_ABI_MSA_128:
                _bfd_error_handler
+                 /* xgettext:c-format */
                  (_("Warning: %B uses unknown MSA ABI %d "
                     "(set by %B), %B uses %s"),
                     obfd, abi_msa_bfd, ibfd,
@@ -15207,6 +15260,7 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
 
              default:
                _bfd_error_handler
+                 /* xgettext:c-format */
                  (_("Warning: %B uses unknown MSA ABI %d "
                     "(set by %B), %B uses unknown MSA ABI %d"),
                   obfd, abi_msa_bfd, ibfd,
@@ -15218,7 +15272,7 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  return _bfd_elf_merge_object_attributes (ibfd, obfd);
+  return _bfd_elf_merge_object_attributes (ibfd, info);
 }
 
 /* Merge object ABI flags from IBFD into OBFD.  Raise an error if
@@ -15257,8 +15311,9 @@ mips_elf_merge_obj_abiflags (bfd *ibfd, bfd *obfd)
    object file when linking.  */
 
 bfd_boolean
-_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
+  bfd *obfd = info->output_bfd;
   struct mips_elf_obj_tdata *out_tdata;
   struct mips_elf_obj_tdata *in_tdata;
   bfd_boolean null_input_bfd = TRUE;
@@ -15266,9 +15321,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   bfd_boolean ok;
 
   /* Check if we have the same endianness.  */
-  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+  if (! _bfd_generic_verify_endian_match (ibfd, info))
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("%B: endianness incompatible with that of the selected emulation"),
         ibfd);
       return FALSE;
@@ -15282,7 +15337,7 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 
   if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("%B: ABI is incompatible with that of the selected emulation"),
         ibfd);
       return FALSE;
@@ -15334,27 +15389,27 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 
       if (LEVEL_REV (in_abiflags.isa_level, in_abiflags.isa_rev)
          < LEVEL_REV (abiflags.isa_level, abiflags.isa_rev))
-       (*_bfd_error_handler)
+       _bfd_error_handler
          (_("%B: warning: Inconsistent ISA between e_flags and "
             ".MIPS.abiflags"), ibfd);
       if (abiflags.fp_abi != Val_GNU_MIPS_ABI_FP_ANY
          && in_abiflags.fp_abi != abiflags.fp_abi)
-       (*_bfd_error_handler)
+       _bfd_error_handler
          (_("%B: warning: Inconsistent FP ABI between .gnu.attributes and "
             ".MIPS.abiflags"), ibfd);
       if ((in_abiflags.ases & abiflags.ases) != abiflags.ases)
-       (*_bfd_error_handler)
+       _bfd_error_handler
          (_("%B: warning: Inconsistent ASEs between e_flags and "
             ".MIPS.abiflags"), ibfd);
       /* The isa_ext is allowed to be an extension of what can be inferred
         from e_flags.  */
       if (!mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags.isa_ext),
                                bfd_mips_isa_ext_mach (in_abiflags.isa_ext)))
-       (*_bfd_error_handler)
+       _bfd_error_handler
          (_("%B: warning: Inconsistent ISA extensions between e_flags and "
             ".MIPS.abiflags"), ibfd);
       if (in_abiflags.flags2 != 0)
-       (*_bfd_error_handler)
+       _bfd_error_handler
          (_("%B: warning: Unexpected flag in the flags2 field of "
             ".MIPS.abiflags (0x%lx)"), ibfd,
           (unsigned long) in_abiflags.flags2);
@@ -15395,9 +15450,9 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
       ok = TRUE;
     }
   else
-    ok = mips_elf_merge_obj_e_flags (ibfd, obfd);
+    ok = mips_elf_merge_obj_e_flags (ibfd, info);
 
-  ok = mips_elf_merge_obj_attributes (ibfd, obfd) && ok;
+  ok = mips_elf_merge_obj_attributes (ibfd, info) && ok;
 
   ok = mips_elf_merge_obj_abiflags (ibfd, obfd) && ok;
 
@@ -16134,6 +16189,16 @@ _bfd_mips_elf_get_synthetic_symtab (bfd *abfd,
   return n;
 }
 
+/* Return the ABI flags associated with ABFD if available.  */
+
+Elf_Internal_ABIFlags_v0 *
+bfd_mips_elf_get_abiflags (bfd *abfd)
+{
+  struct mips_elf_obj_tdata *tdata = mips_elf_tdata (abfd);
+
+  return tdata->abiflags_valid ? &tdata->abiflags : NULL;
+}
+
 void
 _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
 {
@@ -16155,9 +16220,6 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
   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] = 3;
-
-  if (elf_stack_flags (abfd) && !(elf_stack_flags (abfd) & PF_X))
-    i_ehdrp->e_ident[EI_ABIVERSION] = 5;
 }
 
 int
This page took 0.057047 seconds and 4 git commands to generate.