* elf-hppa.h (elf_hppa_reloc_final_type): Handle R_PARISC_GPREL64,
[deliverable/binutils-gdb.git] / bfd / elf-m10300.c
index db8114e53dbd25fd81336163d6005c77867fbb65..37c4f3b5756eb80d849f31fb7ea7bdb20343eb2a 100644 (file)
@@ -661,6 +661,7 @@ mn10300_elf_check_relocs (bfd *abfd,
 {
   bfd_boolean sym_diff_reloc_seen;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Sym * isymbuf = NULL;
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
@@ -669,6 +670,7 @@ mn10300_elf_check_relocs (bfd *abfd,
   asection * sgot;
   asection * srelgot;
   asection * sreloc;
+  bfd_boolean result = FALSE;
 
   sgot    = NULL;
   srelgot = NULL;
@@ -678,6 +680,7 @@ mn10300_elf_check_relocs (bfd *abfd,
     return TRUE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   sym_hashes = elf_sym_hashes (abfd);
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -689,6 +692,7 @@ mn10300_elf_check_relocs (bfd *abfd,
     {
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+      unsigned int r_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -701,10 +705,12 @@ mn10300_elf_check_relocs (bfd *abfd,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
+      r_type = ELF32_R_TYPE (rel->r_info);
+
       /* Some relocs require a global offset table.  */
       if (dynobj == NULL)
        {
-         switch (ELF32_R_TYPE (rel->r_info))
+         switch (r_type)
            {
            case R_MN10300_GOT32:
            case R_MN10300_GOT24:
@@ -716,7 +722,7 @@ mn10300_elf_check_relocs (bfd *abfd,
            case R_MN10300_GOTPC16:
              elf_hash_table (info)->dynobj = dynobj = abfd;
              if (! _bfd_mn10300_elf_create_got_section (dynobj, info))
-               return FALSE;
+               goto fail;
              break;
 
            default:
@@ -724,13 +730,13 @@ mn10300_elf_check_relocs (bfd *abfd,
            }
        }
 
-      switch (ELF32_R_TYPE (rel->r_info))
+      switch (r_type)
        {
        /* This relocation describes the C++ object vtable hierarchy.
           Reconstruct it for later use during GC.  */
        case R_MN10300_GNU_VTINHERIT:
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-           return FALSE;
+           goto fail;
          break;
 
        /* This relocation describes which C++ vtable entries are actually
@@ -739,8 +745,9 @@ mn10300_elf_check_relocs (bfd *abfd,
          BFD_ASSERT (h != NULL);
          if (h != NULL
              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-           return FALSE;
+           goto fail;
          break;
+
        case R_MN10300_GOT32:
        case R_MN10300_GOT24:
        case R_MN10300_GOT16:
@@ -768,7 +775,7 @@ mn10300_elf_check_relocs (bfd *abfd,
                                                          | SEC_READONLY));
                  if (srelgot == NULL
                      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
-                   return FALSE;
+                   goto fail;
                }
            }
 
@@ -784,7 +791,7 @@ mn10300_elf_check_relocs (bfd *abfd,
              if (h->dynindx == -1)
                {
                  if (! bfd_elf_link_record_dynamic_symbol (info, h))
-                   return FALSE;
+                   goto fail;
                }
 
              srelgot->size += sizeof (Elf32_External_Rela);
@@ -802,7 +809,8 @@ mn10300_elf_check_relocs (bfd *abfd,
                  local_got_offsets = bfd_alloc (abfd, size);
 
                  if (local_got_offsets == NULL)
-                   return FALSE;
+                   goto fail;
+
                  elf_local_got_offsets (abfd) = local_got_offsets;
 
                  for (i = 0; i < symtab_hdr->sh_info; i++)
@@ -878,10 +886,8 @@ mn10300_elf_check_relocs (bfd *abfd,
                 symbol involved in the relocation.  */
              if (h == NULL)
                {
-                 Elf_Internal_Sym * isymbuf;
                  Elf_Internal_Sym * isym;
 
-                 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
                  if (isymbuf == NULL)
                    isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
                                                    symtab_hdr->sh_info, 0,
@@ -918,7 +924,7 @@ mn10300_elf_check_relocs (bfd *abfd,
                               elf_elfheader (abfd)->e_shstrndx,
                               elf_section_data (sec)->rel_hdr.sh_name));
                      if (name == NULL)
-                       return FALSE;
+                       goto fail;
 
                      BFD_ASSERT (CONST_STRNEQ (name, ".rela")
                                  && streq (bfd_get_section_name (abfd, sec), name + 5));
@@ -935,7 +941,7 @@ mn10300_elf_check_relocs (bfd *abfd,
                          sreloc = bfd_make_section_with_flags (dynobj, name, flags);
                          if (sreloc == NULL
                              || ! bfd_set_section_alignment (dynobj, sreloc, 2))
-                           return FALSE;
+                           goto fail;
                        }
                    }
 
@@ -950,7 +956,12 @@ mn10300_elf_check_relocs (bfd *abfd,
        sym_diff_reloc_seen = FALSE;
     }
 
-  return TRUE;
+  result = TRUE;
+ fail:
+  if (isymbuf != NULL)
+    free (isymbuf);
+
+  return result;
 }
 
 /* Return the section that should be marked against GC for a given
@@ -1039,6 +1050,17 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
        case R_MN10300_16:
        case R_MN10300_8:
          value -= sym_diff_value;
+         /* If we are computing a 32-bit value for the location lists
+            and the result is 0 then we add one to the value.  A zero
+            value can result because of linker relaxation deleteing
+            prologue instructions and using a value of 1 (for the begin
+            and end offsets in the location list entry) results in a
+            nul entry which does not prevent the following entries from
+            being parsed.  */
+         if (r_type == R_MN10300_32
+             && value == 0
+             && strcmp (input_section->name, ".debug_loc") == 0)
+           value = 1;
          sym_diff_section = NULL;
          is_sym_diff_reloc = TRUE;
          break;
@@ -1190,7 +1212,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xff || (long) value < -0x100)
+      if ((long) value > 0x7f || (long) value < -0x80)
        return bfd_reloc_overflow;
 
       bfd_put_8 (input_bfd, value, hit_data);
@@ -1202,7 +1224,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1242,7 +1264,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1274,7 +1296,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
                                        ".got")->output_section->vma;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1323,7 +1345,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1411,7 +1433,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
        }
       else if (r_type == R_MN10300_GOT16)
        {
-         if ((long) value > 0xffff || (long) value < -0x10000)
+         if ((long) value > 0x7fff || (long) value < -0x8000)
            return bfd_reloc_overflow;
 
          bfd_put_16 (input_bfd, value, hit_data);
@@ -1847,24 +1869,33 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
   irel = elf_section_data (sec)->relocs;
   irelend = irel + sec->reloc_count;
 
-  /* If there is an align reloc at the end of the section ignore it.
-     GAS creates these relocs for reasons of its own, and they just
-     serve to keep the section artifically inflated.  */
-  if (ELF32_R_TYPE ((irelend - 1)->r_info) == (int) R_MN10300_ALIGN)
-    --irelend;
+  if (sec->reloc_count > 0)
+    {
+      /* If there is an align reloc at the end of the section ignore it.
+        GAS creates these relocs for reasons of its own, and they just
+        serve to keep the section artifically inflated.  */
+      if (ELF32_R_TYPE ((irelend - 1)->r_info) == (int) R_MN10300_ALIGN)
+       --irelend;
       
-  /* The deletion must stop at the next ALIGN reloc for an aligment
-     power larger than the number of bytes we are deleting.  */
-  for (; irel < irelend; irel++)
-    if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
-       && irel->r_offset > addr
-       && irel->r_offset < toaddr
-       && count < (1 << irel->r_addend))
-      {
-       irelalign = irel;
-       toaddr = irel->r_offset;
-       break;
-      }
+      /* The deletion must stop at the next ALIGN reloc for an aligment
+        power larger than, or not a multiple of, the number of bytes we
+        are deleting.  */
+      for (; irel < irelend; irel++)
+       {
+         int alignment = 1 << irel->r_addend;
+
+         if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
+             && irel->r_offset > addr
+             && irel->r_offset < toaddr
+             && (count < alignment
+                 || alignment % count != 0))
+           {
+             irelalign = irel;
+             toaddr = irel->r_offset;
+             break;
+           }
+       }
+    }
 
   /* Actually delete the bytes.  */
   memmove (contents + addr, contents + addr + count,
@@ -1895,11 +1926,17 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
     {
       /* Get the new reloc address.  */
       if ((irel->r_offset > addr
-          && irel->r_offset < toaddr))
+          && irel->r_offset < toaddr)
+         || (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN
+             && irel->r_offset == toaddr))
        irel->r_offset -= count;
     }
 
-  /* Adjust the local symbols defined in this section.  */
+  /* Adjust the local symbols in the section, reducing their value
+     by the number of bytes deleted.  Note - symbols within the deleted
+     region are moved to the address of the start of the region, which
+     actually means that they will address the byte beyond the end of
+     the region once the deletion has been completed.  */
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
   for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
@@ -1907,7 +1944,12 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
       if (isym->st_shndx == sec_shndx
          && isym->st_value > addr
          && isym->st_value < toaddr)
-       isym->st_value -= count;
+       {
+         if (isym->st_value < addr + count)
+           isym->st_value = addr;
+         else
+           isym->st_value -= count;
+       }
       /* Adjust the function symbol's size as well.  */
       else if (isym->st_shndx == sec_shndx
               && ELF_ST_TYPE (isym->st_info) == STT_FUNC
@@ -1930,7 +1972,12 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
          && sym_hash->root.u.def.section == sec
          && sym_hash->root.u.def.value > addr
          && sym_hash->root.u.def.value < toaddr)
-       sym_hash->root.u.def.value -= count;
+       {
+         if (sym_hash->root.u.def.value < addr + count)
+           sym_hash->root.u.def.value = addr;
+         else
+           sym_hash->root.u.def.value -= count;
+       }
       /* Adjust the function symbol's size as well.  */
       else if (sym_hash->root.type == bfd_link_hash_defined
               && sym_hash->root.u.def.section == sec
@@ -1940,6 +1987,26 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
        sym_hash->size -= count;
     }
 
+  /* See if we can move the ALIGN reloc forward.
+     We have adjusted r_offset for it already.  */
+  if (irelalign != NULL)
+    {
+      bfd_vma alignto, alignaddr;
+
+      if ((int) irelalign->r_addend > 0)
+       {
+         /* This is the old address.  */
+         alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend);
+         /* This is where the align points to now.  */
+         alignaddr = BFD_ALIGN (irelalign->r_offset,
+                                1 << irelalign->r_addend);
+         if (alignaddr < alignto)
+           /* Tail recursion.  */
+           return mn10300_elf_relax_delete_bytes (abfd, sec, alignaddr,
+                                                  (int) (alignto - alignaddr));
+       }
+    }
+
   return TRUE;
 }
 
@@ -2038,6 +2105,7 @@ mn10300_elf_relax_section (bfd *abfd,
   Elf_Internal_Sym *isymbuf = NULL;
   struct elf32_mn10300_link_hash_table *hash_table;
   asection *section = sec;
+  bfd_vma align_gap_adjustment;
 
   /* Assume nothing changes.  */
   *again = FALSE;
@@ -2651,11 +2719,40 @@ mn10300_elf_relax_section (bfd *abfd,
   if (internal_relocs == NULL)
     goto error_return;
 
+  /* Scan for worst case alignment gap changes.  Note that this logic
+     is not ideal; what we should do is run this scan for every
+     opcode/address range and adjust accordingly, but that's
+     expensive.  Worst case is that for an alignment of N bytes, we
+     move by 2*N-N-1 bytes, assuming we have aligns of 1, 2, 4, 8, etc
+     all before it.  Plus, this still doesn't cover cross-section
+     jumps with section alignment.  */
+  irelend = internal_relocs + sec->reloc_count;
+  align_gap_adjustment = 0;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN)
+       {
+         bfd_vma adj = 1 << irel->r_addend;
+         bfd_vma aend = irel->r_offset;
+
+         aend = BFD_ALIGN (aend, 1 << irel->r_addend);
+         adj = 2 * adj - adj - 1;
+
+         /* Record the biggest adjustmnet.  Skip any alignment at the
+            end of our section.  */
+         if (align_gap_adjustment < adj
+             && aend < sec->output_section->vma + sec->output_offset + sec->size)
+           align_gap_adjustment = adj;
+       }
+    }
+
   /* Walk through them looking for relaxing opportunities.  */
   irelend = internal_relocs + sec->reloc_count;
   for (irel = internal_relocs; irel < irelend; irel++)
     {
       bfd_vma symval;
+      bfd_signed_vma jump_offset;
+      asection *sym_sec = NULL;
       struct elf32_mn10300_link_hash_entry *h = NULL;
 
       /* If this isn't something that can be relaxed, then ignore
@@ -2695,7 +2792,6 @@ mn10300_elf_relax_section (bfd *abfd,
       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          Elf_Internal_Sym *isym;
-         asection *sym_sec = NULL;
          const char *sym_name;
          char *new_name;
 
@@ -2718,12 +2814,11 @@ mn10300_elf_relax_section (bfd *abfd,
              && ELF_ST_TYPE (isym->st_info) == STT_SECTION
              && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
            {
-             bfd_vma saved_addend;
-
-             saved_addend = irel->r_addend;
-             symval = _bfd_elf_rela_local_sym (abfd, isym, & sym_sec, irel);
-             symval += irel->r_addend;
-             irel->r_addend = saved_addend;
+             symval = isym->st_value + irel->r_addend;
+             symval = _bfd_merged_section_offset (abfd, & sym_sec,
+                                                  elf_section_data (sym_sec)->sec_info,
+                                                  symval);
+             symval += sym_sec->output_section->vma + sym_sec->output_offset - irel->r_addend;
            }
          else
            symval = (isym->st_value
@@ -2763,6 +2858,8 @@ mn10300_elf_relax_section (bfd *abfd,
          if (h->root.root.u.def.section->output_section == NULL)
            continue;
 
+         sym_sec = h->root.root.u.def.section->output_section;
+
          symval = (h->root.root.u.def.value
                    + h->root.root.u.def.section->output_section->vma
                    + h->root.root.u.def.section->output_offset);
@@ -2865,8 +2962,16 @@ mn10300_elf_relax_section (bfd *abfd,
 
          /* See if the value will fit in 16 bits, note the high value is
             0x7fff + 2 as the target will be two bytes closer if we are
-            able to relax.  */
-         if ((long) value < 0x8001 && (long) value > -0x8000)
+            able to relax, if it's in the same section.  */
+         if (sec->output_section == sym_sec->output_section)
+           jump_offset = 0x8001;
+         else
+           jump_offset = 0x7fff;
+
+         /* Account for jumps across alignment boundaries using
+            align_gap_adjustment.  */
+         if ((bfd_signed_vma) value < jump_offset - (bfd_signed_vma) align_gap_adjustment
+             && ((bfd_signed_vma) value > -0x8000 + (bfd_signed_vma) align_gap_adjustment))
            {
              unsigned char code;
 
This page took 0.037075 seconds and 4 git commands to generate.