Skip gdb.mi/mi-threads-interrupt.exp if nointerrupts.
[deliverable/binutils-gdb.git] / bfd / elf32-avr.c
index bd57ab79a0e80e6ae89feee1f6bb1e631cdc20c9..830da288f3cd3e6a070b5ced908ca05d6b11e4b0 100644 (file)
@@ -1,5 +1,5 @@
 /* AVR-specific support for 32-bit ELF
-   Copyright (C) 1999-2015 Free Software Foundation, Inc.
+   Copyright (C) 1999-2017 Free Software Foundation, Inc.
    Contributed by Denis Chertykov <denisc@overta.ru>
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -89,7 +89,7 @@ struct elf32_avr_link_hash_table
 
   /* Assorted information used by elf32_avr_size_stubs.  */
   unsigned int        bfd_count;
-  int                 top_index;
+  unsigned int        top_index;
   asection **         input_list;
   Elf_Internal_Sym ** all_local_syms;
 
@@ -955,6 +955,7 @@ avr_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
   r_type = ELF32_R_TYPE (dst->r_info);
   if (r_type >= (unsigned int) R_AVR_max)
     {
+      /* xgettext:c-format */
       _bfd_error_handler (_("%B: invalid AVR reloc number: %d"), abfd, r_type);
       r_type = 0;
     }
@@ -1474,7 +1475,7 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
        RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
                                         rel, 1, relend, howto, 0, contents);
 
-      if (info->relocatable)
+      if (bfd_link_relocatable (info))
        continue;
 
       r = avr_final_link_relocate (howto, input_bfd, input_section,
@@ -1487,14 +1488,13 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
          switch (r)
            {
            case bfd_reloc_overflow:
-             r = info->callbacks->reloc_overflow
-               (info, (h ? &h->root : NULL),
-                name, howto->name, (bfd_vma) 0,
-                input_bfd, input_section, rel->r_offset);
+             (*info->callbacks->reloc_overflow)
+               (info, (h ? &h->root : NULL), name, howto->name,
+                (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
              break;
 
            case bfd_reloc_undefined:
-             r = info->callbacks->undefined_symbol
+             (*info->callbacks->undefined_symbol)
                (info, name, input_bfd, input_section, rel->r_offset, TRUE);
              break;
 
@@ -1516,11 +1516,8 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
            }
 
          if (msg)
-           r = info->callbacks->warning
-             (info, msg, name, input_bfd, input_section, rel->r_offset);
-
-         if (! r)
-           return FALSE;
+           (*info->callbacks->warning) (info, msg, name, input_bfd,
+                                        input_section, rel->r_offset);
        }
     }
 
@@ -1745,22 +1742,22 @@ elf32_avr_adjust_diff_reloc_value (bfd *abfd,
   reloc_contents = isec_contents + irel->r_offset;
 
   /* Read value written in object file. */
bfd_vma x = 0;
 bfd_signed_vma x = 0;
   switch (ELF32_R_TYPE (irel->r_info))
   {
   case R_AVR_DIFF8:
     {
-      x = *reloc_contents;
+      x = bfd_get_signed_8 (abfd, reloc_contents);
       break;
     }
   case R_AVR_DIFF16:
     {
-      x = bfd_get_16 (abfd, reloc_contents);
+      x = bfd_get_signed_16 (abfd, reloc_contents);
       break;
     }
   case R_AVR_DIFF32:
     {
-      x = bfd_get_32 (abfd, reloc_contents);
+      x = bfd_get_signed_32 (abfd, reloc_contents);
       break;
     }
   default:
@@ -1774,30 +1771,44 @@ elf32_avr_adjust_diff_reloc_value (bfd *abfd,
      symval (<start_of_section>) + reloc addend. Compute the start and end
      addresses and check if the shrinked insn falls between sym1 and sym2. */
 
-  bfd_vma end_address = symval + irel->r_addend;
-  bfd_vma start_address = end_address - x;
+  bfd_vma sym2_address = symval + irel->r_addend;
+  bfd_vma sym1_address = sym2_address - x;
+
+  /* Don't assume sym2 is bigger than sym1 - the difference
+     could be negative. Compute start and end addresses, and
+     use those to see if they span shrinked_insn_address. */
+
+  bfd_vma start_address = sym1_address < sym2_address
+    ? sym1_address : sym2_address;
+  bfd_vma end_address = sym1_address > sym2_address
+    ? sym1_address : sym2_address;
 
-  /* Reduce the diff value by count bytes and write it back into section
-    contents. */
 
   if (shrinked_insn_address >= start_address
-      && shrinked_insn_address <= end_address)
+      && shrinked_insn_address < end_address)
   {
+    /* Reduce the diff value by count bytes and write it back into section
+       contents. */
+    bfd_signed_vma new_diff = x < 0 ? x + count : x - count;
+
+    if (sym2_address > shrinked_insn_address)
+      irel->r_addend -= count;
+
     switch (ELF32_R_TYPE (irel->r_info))
     {
     case R_AVR_DIFF8:
       {
-        *reloc_contents = (x - count);
+        bfd_put_signed_8 (abfd, new_diff, reloc_contents);
         break;
       }
     case R_AVR_DIFF16:
       {
-        bfd_put_16 (abfd, (x - count) & 0xFFFF, reloc_contents);
+        bfd_put_signed_16 (abfd, new_diff & 0xFFFF, reloc_contents);
         break;
       }
     case R_AVR_DIFF32:
       {
-        bfd_put_32 (abfd, (x - count) & 0xFFFFFFFF, reloc_contents);
+        bfd_put_signed_32 (abfd, new_diff & 0xFFFFFFFF, reloc_contents);
         break;
       }
     default:
@@ -1809,16 +1820,91 @@ elf32_avr_adjust_diff_reloc_value (bfd *abfd,
   }
 }
 
+static void
+elf32_avr_adjust_reloc_if_spans_insn (bfd *abfd,
+                                      asection *isec,
+                                      Elf_Internal_Rela *irel,  bfd_vma symval,
+                                      bfd_vma shrinked_insn_address,
+                                      bfd_vma shrink_boundary,
+                                      int count)
+{
+
+  if (elf32_avr_is_diff_reloc (irel))
+    {
+      elf32_avr_adjust_diff_reloc_value (abfd, isec, irel,
+                                         symval,
+                                         shrinked_insn_address,
+                                         count);
+    }
+  else
+    {
+      bfd_vma reloc_value = symval + irel->r_addend;
+      bfd_boolean addend_within_shrink_boundary =
+        (reloc_value <= shrink_boundary);
+
+      bfd_boolean reloc_spans_insn =
+        (symval <= shrinked_insn_address
+         && reloc_value > shrinked_insn_address
+         && addend_within_shrink_boundary);
+
+      if (! reloc_spans_insn)
+        return;
+
+      irel->r_addend -= count;
+
+      if (debug_relax)
+        printf ("Relocation's addend needed to be fixed \n");
+    }
+}
+
+static bfd_boolean
+avr_should_move_sym (symvalue symval,
+                     bfd_vma start,
+                     bfd_vma end,
+                     bfd_boolean did_pad)
+{
+  bfd_boolean sym_within_boundary =
+          did_pad ? symval < end : symval <= end;
+  return (symval > start && sym_within_boundary);
+}
+
+static bfd_boolean
+avr_should_reduce_sym_size (symvalue symval,
+                            symvalue symend,
+                            bfd_vma start,
+                            bfd_vma end,
+                            bfd_boolean did_pad)
+{
+  bfd_boolean sym_end_within_boundary =
+          did_pad ? symend < end : symend <= end;
+  return (symval <= start && symend > start && sym_end_within_boundary);
+}
+
+static bfd_boolean
+avr_should_increase_sym_size (symvalue symval,
+                              symvalue symend,
+                              bfd_vma start,
+                              bfd_vma end,
+                              bfd_boolean did_pad)
+{
+  return avr_should_move_sym (symval, start, end, did_pad)
+          && symend >= end && did_pad;
+}
+
 /* Delete some bytes from a section while changing the size of an instruction.
    The parameter "addr" denotes the section-relative offset pointing just
    behind the shrinked instruction. "addr+count" point at the first
-   byte just behind the original unshrinked instruction.  */
+   byte just behind the original unshrinked instruction. If delete_shrinks_insn
+   is FALSE, we are deleting redundant padding bytes from relax_info prop
+   record handling. In that case, addr is section-relative offset of start
+   of padding, and count is the number of padding bytes to delete. */
 
 static bfd_boolean
 elf32_avr_relax_delete_bytes (bfd *abfd,
                               asection *sec,
                               bfd_vma addr,
-                              int count)
+                              int count,
+                              bfd_boolean delete_shrinks_insn)
 {
   Elf_Internal_Shdr *symtab_hdr;
   unsigned int sec_shndx;
@@ -1832,6 +1918,8 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
   unsigned int symcount;
   struct avr_relax_info *relax_info;
   struct avr_property_record *prop_record = NULL;
+  bfd_boolean did_shrink = FALSE;
+  bfd_boolean did_pad = FALSE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
@@ -1867,10 +1955,16 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
 
   /* Actually delete the bytes.  */
   if (toaddr - addr - count > 0)
-    memmove (contents + addr, contents + addr + count,
-             (size_t) (toaddr - addr - count));
+    {
+      memmove (contents + addr, contents + addr + count,
+               (size_t) (toaddr - addr - count));
+      did_shrink = TRUE;
+    }
   if (prop_record == NULL)
-    sec->size -= count;
+    {
+      sec->size -= count;
+      did_shrink = TRUE;
+    }
   else
     {
       /* Use the property record to fill in the bytes we've opened up.  */
@@ -1889,13 +1983,18 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
           prop_record->data.align.preceding_deleted += count;
           break;
         };
+      /* If toaddr == (addr + count), then we didn't delete anything, yet
+         we fill count bytes backwards from toaddr. This is still ok - we
+         end up overwriting the bytes we would have deleted. We just need
+         to remember we didn't delete anything i.e. don't set did_shrink,
+         so that we don't corrupt reloc offsets or symbol values.*/
       memset (contents + toaddr - count, fill, count);
-
-      /* Adjust the TOADDR to avoid moving symbols located at the address
-         of the property record, which has not moved.  */
-      toaddr -= count;
+      did_pad = TRUE;
     }
 
+  if (!did_shrink)
+    return TRUE;
+
   /* Adjust all the reloc addresses.  */
   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
     {
@@ -1943,7 +2042,9 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
         continue;
 
        shrinked_insn_address = (sec->output_section->vma
-                                + sec->output_offset + addr - count);
+                                + sec->output_offset + addr);
+       if (delete_shrinks_insn)
+         shrinked_insn_address -= count;
 
        irel = elf_section_data (isec)->relocs;
        /* PR 12161: Read in the relocs for this section if necessary.  */
@@ -1980,6 +2081,12 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
                   a symbol or section associated with it.  */
                if (sym_sec == sec)
                  {
+                   /* If there is an alignment boundary, we only need to
+                      adjust addends that end up below the boundary. */
+                   bfd_vma shrink_boundary = (toaddr
+                                              + sec->output_section->vma
+                                              + sec->output_offset);
+
                    symval += sym_sec->output_section->vma
                              + sym_sec->output_offset;
 
@@ -1993,22 +2100,11 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
                              (unsigned int) (symval + irel->r_addend),
                              (unsigned int) shrinked_insn_address);
 
-                   if (symval <= shrinked_insn_address
-                       && (symval + irel->r_addend) > shrinked_insn_address)
-                     {
-                       if (elf32_avr_is_diff_reloc (irel))
-                         {
-                           elf32_avr_adjust_diff_reloc_value (abfd, isec, irel,
+                   elf32_avr_adjust_reloc_if_spans_insn (abfd, isec, irel,
                                                          symval,
                                                          shrinked_insn_address,
-                                                        count);
-                         }
-
-                       irel->r_addend -= count;
-
-                       if (debug_relax)
-                         printf ("Relocation's addend needed to be fixed \n");
-                     }
+                                                         shrink_boundary,
+                                                         count);
                  }
               /* else...Reference symbol is absolute.  No adjustment needed.  */
             }
@@ -2030,12 +2126,10 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
        {
          if (isym->st_shndx == sec_shndx)
             {
-             if (isym->st_value > addr
-                  && isym->st_value <= toaddr)
-                isym->st_value -= count;
-
-              if (isym->st_value <= addr
-                  && isym->st_value + isym->st_size > addr)
+              symvalue symval = isym->st_value;
+              symvalue symend = symval + isym->st_size;
+              if (avr_should_reduce_sym_size (symval, symend,
+                                      addr, toaddr, did_pad))
                 {
                   /* If this assert fires then we have a symbol that ends
                      part way through an instruction.  Does that make
@@ -2043,6 +2137,12 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
                   BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
                   isym->st_size -= count;
                 }
+              else if (avr_should_increase_sym_size (symval, symend,
+                                      addr, toaddr, did_pad))
+                isym->st_size += count;
+
+              if (avr_should_move_sym (symval, addr, toaddr, did_pad))
+                isym->st_value -= count;
             }
        }
     }
@@ -2059,20 +2159,24 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
            || sym_hash->root.type == bfd_link_hash_defweak)
           && sym_hash->root.u.def.section == sec)
         {
-          if (sym_hash->root.u.def.value > addr
-              && sym_hash->root.u.def.value <= toaddr)
-            sym_hash->root.u.def.value -= count;
+          symvalue symval = sym_hash->root.u.def.value;
+          symvalue symend = symval + sym_hash->size;
 
-          if (sym_hash->root.u.def.value <= addr
-              && (sym_hash->root.u.def.value + sym_hash->size > addr))
+          if (avr_should_reduce_sym_size (symval, symend,
+                                  addr, toaddr, did_pad))
             {
               /* If this assert fires then we have a symbol that ends
                  part way through an instruction.  Does that make
                  sense?  */
-              BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
-                          >= addr + count);
+              BFD_ASSERT (symend >= addr + count);
               sym_hash->size -= count;
             }
+          else if (avr_should_increase_sym_size (symval, symend,
+                                  addr, toaddr, did_pad))
+              sym_hash->size += count;
+
+          if (avr_should_move_sym (symval, addr, toaddr, did_pad))
+            sym_hash->root.u.def.value -= count;
         }
     }
 
@@ -2375,7 +2479,7 @@ elf32_avr_relax_section (bfd *abfd,
       || !strcmp (sec->name,".jumptables"))
     shrinkable = FALSE;
 
-  if (link_info->relocatable)
+  if (bfd_link_relocatable (link_info))
     (*link_info->callbacks->einfo)
       (_("%P%F: --relax and -r may not be used together\n"));
 
@@ -2413,7 +2517,7 @@ elf32_avr_relax_section (bfd *abfd,
   /* We don't have to do anything for a relocatable link, if
      this section does not have relocs, or if this is not a
      code section.  */
-  if (link_info->relocatable
+  if (bfd_link_relocatable (link_info)
       || (sec->flags & SEC_RELOC) == 0
       || sec->reloc_count == 0
       || (sec->flags & SEC_CODE) == 0)
@@ -2626,7 +2730,8 @@ elf32_avr_relax_section (bfd *abfd,
                   {
                     /* Delete two bytes of data.  */
                     if (!elf32_avr_relax_delete_bytes (abfd, sec,
-                                                       irel->r_offset + 2, 2))
+                                                       irel->r_offset + 2, 2,
+                                                       TRUE))
                       goto error_return;
 
                     /* That will change things, so, we should relax again.
@@ -2635,6 +2740,7 @@ elf32_avr_relax_section (bfd *abfd,
                   }
               }
           }
+         /* Fall through.  */
 
         default:
           {
@@ -2950,7 +3056,8 @@ elf32_avr_relax_section (bfd *abfd,
 
                            /* Delete two bytes of data.  */
                            if (!elf32_avr_relax_delete_bytes (abfd, sec,
-                                                              irel->r_offset + insn_size, 2))
+                                                              irel->r_offset + insn_size, 2,
+                                                              TRUE))
                              goto error_return;
 
                            /* That will change things, so, we should relax
@@ -3018,7 +3125,7 @@ elf32_avr_relax_section (bfd *abfd,
                         record->offset -= count;
                         elf32_avr_relax_delete_bytes (abfd, sec,
                                                       addr - count,
-                                                      count);
+                                                      count, FALSE);
                         *again = TRUE;
                       }
                   }
@@ -3208,8 +3315,8 @@ avr_add_stub (const char *stub_name,
 
   if (hsh == NULL)
     {
-      (*_bfd_error_handler) (_("%B: cannot create stub entry %s"),
-                             NULL, stub_name);
+      /* xgettext:c-format */
+      _bfd_error_handler (_("cannot create stub entry %s"), stub_name);
       return NULL;
     }
 
@@ -3365,7 +3472,7 @@ elf32_avr_setup_section_lists (bfd *output_bfd,
 {
   bfd *input_bfd;
   unsigned int bfd_count;
-  int top_id, top_index;
+  unsigned int top_id, top_index;
   asection *section;
   asection **input_list, **list;
   bfd_size_type amt;
@@ -3641,7 +3748,7 @@ elf32_avr_size_stubs (bfd *output_bfd,
                         }
                       else if (hh->root.type == bfd_link_hash_undefweak)
                         {
-                          if (! info->shared)
+                          if (! bfd_link_pic (info))
                             continue;
                         }
                       else if (hh->root.type == bfd_link_hash_undefined)
@@ -4068,11 +4175,13 @@ avr_elf32_load_records_from_section (bfd *abfd, asection *sec)
     }
 
   free (contents);
-  free (internal_relocs);
+  if (elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
   return r_list;
 
  load_failed:
-  free (internal_relocs);
+  if (elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
   free (contents);
   free (r_list);
   return NULL;
This page took 0.094591 seconds and 4 git commands to generate.