MIPS/BFD: Also handle `jalr $0, $25' with R_MIPS_JALR
[deliverable/binutils-gdb.git] / bfd / elfxx-mips.c
index 7c7cd3898a891364650c658c79f7b3df5ca35d19..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;
 
@@ -3829,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;
@@ -3842,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.  */
@@ -3881,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:
@@ -6270,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:
@@ -6416,31 +6430,33 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
          value <<= 2;
        }
 
-      if (bfd_link_pic (info) || !ok)
+      if (ok && !bfd_link_pic (info))
        {
-         info->callbacks->einfo
-           (_("%X%H: Unsupported branch between ISA modes\n"),
-            input_bfd, input_section, relocation->r_offset);
-         return TRUE;
-       }
+         addr = (input_section->output_section->vma
+                 + input_section->output_offset
+                 + relocation->r_offset
+                 + 4);
+         dest = addr + (((value & 0x3ffff) ^ 0x20000) - 0x20000);
 
-      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;
+           }
 
-      if ((addr >> 28) << 28 != (dest >> 28) << 28)
+         /* 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: Cannot convert branch between ISA modes "
-              "to JALX: relocation out of range\n"),
+           (_("%X%H: Unsupported branch between ISA modes\n"),
             input_bfd, input_section, relocation->r_offset);
          return TRUE;
        }
-
-      /* Make this the JALX opcode.  */
-      x = ((dest >> 2) & 0x3ffffff) | jalx_opcode << 26;
     }
 
   /* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in
@@ -6449,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;
@@ -6472,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 */
@@ -8873,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
@@ -14095,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.  */
This page took 0.032447 seconds and 4 git commands to generate.