Remove unused local variable
[deliverable/binutils-gdb.git] / bfd / elf32-avr.c
index 9169a8b88c38ceb042c853cc25881ad34ce56786..54d67bf04031ada4602f3ab496efeedf63ada62d 100644 (file)
@@ -1,13 +1,12 @@
 /* AVR-specific support for 32-bit ELF
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 1999-2014 Free Software Foundation, Inc.
    Contributed by Denis Chertykov <denisc@overta.ru>
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -33,12 +32,16 @@ static bfd_boolean debug_relax = FALSE;
 /* Enable debugging printout at stdout with this variable.  */
 static bfd_boolean debug_stubs = FALSE;
 
+static bfd_reloc_status_type
+bfd_elf_avr_diff_reloc (bfd *, arelent *, asymbol *, void *,
+                       asection *, bfd *, char **);
+
 /* Hash table initialization and handling.  Code is taken from the hppa port
    and adapted to the needs of AVR.  */
 
 /* We use two hash tables to hold information for linking avr objects.
 
-   The first is the elf32_avr_link_hash_tablse which is derived from the
+   The first is the elf32_avr_link_hash_table which is derived from the
    stanard ELF linker hash table.  We use this as a place to attach the other
    hash table and some static information.
 
@@ -104,8 +107,8 @@ struct elf32_avr_link_hash_table
 /* Various hash macros and functions.  */
 #define avr_link_hash_table(p) \
   /* PR 3874: Check that we have an AVR style hash table before using it.  */\
-  ((p)->hash->table.newfunc != elf32_avr_link_hash_newfunc ? NULL : \
-   ((struct elf32_avr_link_hash_table *) ((p)->hash)))
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == AVR_ELF_DATA ? ((struct elf32_avr_link_hash_table *) ((p)->hash)) : NULL)
 
 #define avr_stub_hash_entry(ent) \
   ((struct elf32_avr_stub_hash_entry *)(ent))
@@ -473,7 +476,7 @@ static reloc_howto_type elf_avr_howto_table[] =
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
   /* A low 8 bit absolute relocation of 24 bit program memory address.
-     For LDI command.  Will be changed when linker stubs are needed. */
+     For LDI command.  Will be changed when linker stubs are needed.  */
   HOWTO (R_AVR_LO8_LDI_GS,      /* type */
          1,                     /* rightshift */
          1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -488,7 +491,7 @@ static reloc_howto_type elf_avr_howto_table[] =
          0xffff,                /* dst_mask */
          FALSE),                /* pcrel_offset */
   /* A low 8 bit absolute relocation of 24 bit program memory address.
-     For LDI command.  Will be changed when linker stubs are needed. */
+     For LDI command.  Will be changed when linker stubs are needed.  */
   HOWTO (R_AVR_HI8_LDI_GS,      /* type */
          9,                     /* rightshift */
          1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -501,7 +504,143 @@ static reloc_howto_type elf_avr_howto_table[] =
          FALSE,                 /* partial_inplace */
          0xffff,                /* src_mask */
          0xffff,                /* dst_mask */
-         FALSE)                 /* pcrel_offset */
+         FALSE),                /* pcrel_offset */
+  /* 8 bit offset.  */
+  HOWTO (R_AVR_8,              /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_8",             /* name */
+        FALSE,                 /* partial_inplace */
+        0x000000ff,            /* src_mask */
+        0x000000ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* lo8-part to use in  .byte lo8(sym).  */
+  HOWTO (R_AVR_8_LO8,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_8_LO8",         /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffff,              /* src_mask */
+        0xffffff,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* hi8-part to use in  .byte hi8(sym).  */
+  HOWTO (R_AVR_8_HI8,          /* type */
+        8,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_8_HI8",         /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffff,              /* src_mask */
+        0xffffff,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* hlo8-part to use in  .byte hlo8(sym).  */
+  HOWTO (R_AVR_8_HLO8,         /* type */
+        16,                    /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_8_HLO8",        /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffff,              /* src_mask */
+        0xffffff,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_AVR_DIFF8,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_avr_diff_reloc, /* special_function */
+        "R_AVR_DIFF8",         /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xff,                  /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_AVR_DIFF16,         /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_avr_diff_reloc,/* special_function */
+        "R_AVR_DIFF16",        /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_AVR_DIFF32,         /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_avr_diff_reloc,/* special_function */
+        "R_AVR_DIFF32",        /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* 7 bit immediate for LDS/STS in Tiny core.  */
+  HOWTO (R_AVR_LDS_STS_16,  /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        7,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_LDS_STS_16",    /* name */
+        FALSE,                 /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_AVR_PORT6,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        6,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_PORT6",         /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffff,              /* src_mask */
+        0xffffff,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_AVR_PORT5,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        5,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_PORT5",         /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffff,              /* src_mask */
+        0xffffff,              /* dst_mask */
+        FALSE)                 /* pcrel_offset */
 };
 
 /* Map BFD reloc types to AVR ELF reloc types.  */
@@ -539,7 +678,17 @@ static const struct avr_reloc_map avr_reloc_map[] =
   { BFD_RELOC_AVR_CALL,             R_AVR_CALL },
   { BFD_RELOC_AVR_LDI,              R_AVR_LDI  },
   { BFD_RELOC_AVR_6,                R_AVR_6    },
-  { BFD_RELOC_AVR_6_ADIW,           R_AVR_6_ADIW }
+  { BFD_RELOC_AVR_6_ADIW,           R_AVR_6_ADIW },
+  { BFD_RELOC_8,                    R_AVR_8 },
+  { BFD_RELOC_AVR_8_LO,             R_AVR_8_LO8 },
+  { BFD_RELOC_AVR_8_HI,             R_AVR_8_HI8 },
+  { BFD_RELOC_AVR_8_HLO,            R_AVR_8_HLO8 },
+  { BFD_RELOC_AVR_DIFF8,            R_AVR_DIFF8 },
+  { BFD_RELOC_AVR_DIFF16,           R_AVR_DIFF16 },
+  { BFD_RELOC_AVR_DIFF32,           R_AVR_DIFF32 },
+  { BFD_RELOC_AVR_LDS_STS_16,       R_AVR_LDS_STS_16},
+  { BFD_RELOC_AVR_PORT6,            R_AVR_PORT6},
+  { BFD_RELOC_AVR_PORT5,            R_AVR_PORT5}
 };
 
 /* Meant to be filled one day with the wrap around address for the
@@ -601,6 +750,24 @@ elf32_avr_link_hash_newfunc (struct bfd_hash_entry * entry,
   return _bfd_elf_link_hash_newfunc (entry, table, string);
 }
 
+/* Free the derived linker hash table.  */
+
+static void
+elf32_avr_link_hash_table_free (bfd *obfd)
+{
+  struct elf32_avr_link_hash_table *htab
+    = (struct elf32_avr_link_hash_table *) obfd->link.hash;
+
+  /* Free the address mapping table.  */
+  if (htab->amt_stub_offsets != NULL)
+    free (htab->amt_stub_offsets);
+  if (htab->amt_destination_addr != NULL)
+    free (htab->amt_destination_addr);
+
+  bfd_hash_table_free (&htab->bstab);
+  _bfd_elf_link_hash_table_free (obfd);
+}
+
 /* Create the derived linker hash table.  The AVR ELF port uses the derived
    hash table to keep information specific to the AVR ELF linker (without
    using static variables).  */
@@ -611,13 +778,14 @@ elf32_avr_link_hash_table_create (bfd *abfd)
   struct elf32_avr_link_hash_table *htab;
   bfd_size_type amt = sizeof (*htab);
 
-  htab = bfd_malloc (amt);
+  htab = bfd_zmalloc (amt);
   if (htab == NULL)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (&htab->etab, abfd,
                                       elf32_avr_link_hash_newfunc,
-                                      sizeof (struct elf_link_hash_entry)))
+                                      sizeof (struct elf_link_hash_entry),
+                                     AVR_ELF_DATA))
     {
       free (htab);
       return NULL;
@@ -626,38 +794,15 @@ elf32_avr_link_hash_table_create (bfd *abfd)
   /* Init the stub hash table too.  */
   if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc,
                             sizeof (struct elf32_avr_stub_hash_entry)))
-    return NULL;
-
-  htab->stub_bfd = NULL;
-  htab->stub_sec = NULL;
-
-  /* Initialize the address mapping table.  */
-  htab->amt_stub_offsets = NULL;
-  htab->amt_destination_addr = NULL;
-  htab->amt_entry_cnt = 0;
-  htab->amt_max_entry_cnt = 0;
+    {
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+  htab->etab.root.hash_table_free = elf32_avr_link_hash_table_free;
 
   return &htab->etab.root;
 }
 
-/* Free the derived linker hash table.  */
-
-static void
-elf32_avr_link_hash_table_free (struct bfd_link_hash_table *btab)
-{
-  struct elf32_avr_link_hash_table *htab
-    = (struct elf32_avr_link_hash_table *) btab;
-
-  /* Free the address mapping table.  */
-  if (htab->amt_stub_offsets != NULL)
-    free (htab->amt_stub_offsets);
-  if (htab->amt_destination_addr != NULL)
-    free (htab->amt_destination_addr);
-
-  bfd_hash_table_free (&htab->bstab);
-  _bfd_generic_link_hash_table_free (btab);
-}
-
 /* Calculates the effective distance of a pc relative jump/call.  */
 
 static int
@@ -718,51 +863,6 @@ avr_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
   cache_ptr->howto = &elf_avr_howto_table[r_type];
 }
 
-/* Look through the relocs for a section during the first phase.
-   Since we don't do .gots or .plts, we just need to consider the
-   virtual table relocs for gc.  */
-
-static bfd_boolean
-elf32_avr_check_relocs (bfd *abfd,
-                       struct bfd_link_info *info,
-                       asection *sec,
-                       const Elf_Internal_Rela *relocs)
-{
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
-  const Elf_Internal_Rela *rel;
-  const Elf_Internal_Rela *rel_end;
-
-  if (info->relocatable)
-    return TRUE;
-
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
-  if (!elf_bad_symtab (abfd))
-    sym_hashes_end -= symtab_hdr->sh_info;
-
-  rel_end = relocs + sec->reloc_count;
-  for (rel = relocs; rel < rel_end; rel++)
-    {
-      struct elf_link_hash_entry *h;
-      unsigned long r_symndx;
-
-      r_symndx = ELF32_R_SYM (rel->r_info);
-      if (r_symndx < symtab_hdr->sh_info)
-        h = NULL;
-      else
-       {
-         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
-       }
-    }
-
-  return TRUE;
-}
-
 static bfd_boolean
 avr_stub_is_required_for_16_bit_reloc (bfd_vma relocation)
 {
@@ -778,19 +878,35 @@ static bfd_vma
 avr_get_stub_addr (bfd_vma srel,
                    struct elf32_avr_link_hash_table *htab)
 {
-  unsigned int index;
+  unsigned int sindex;
   bfd_vma stub_sec_addr =
               (htab->stub_sec->output_section->vma +
               htab->stub_sec->output_offset);
 
-  for (index = 0; index < htab->amt_max_entry_cnt; index ++)
-    if (htab->amt_destination_addr[index] == srel)
-      return htab->amt_stub_offsets[index] + stub_sec_addr;
+  for (sindex = 0; sindex < htab->amt_max_entry_cnt; sindex ++)
+    if (htab->amt_destination_addr[sindex] == srel)
+      return htab->amt_stub_offsets[sindex] + stub_sec_addr;
 
   /* Return an address that could not be reached by 16 bit relocs.  */
   return 0x020000;
 }
 
+/* Perform a diff relocation. Nothing to do, as the difference value is already
+   written into the section's contents. */
+
+static bfd_reloc_status_type
+bfd_elf_avr_diff_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+                     arelent *reloc_entry ATTRIBUTE_UNUSED,
+              asymbol *symbol ATTRIBUTE_UNUSED,
+              void *data ATTRIBUTE_UNUSED,
+              asection *input_section ATTRIBUTE_UNUSED,
+              bfd *output_bfd ATTRIBUTE_UNUSED,
+              char **error_message ATTRIBUTE_UNUSED)
+{
+  return bfd_reloc_ok;
+}
+
+
 /* Perform a single relocation.  By default we use the standard BFD
    routines, but a few relocs, we have to do them ourselves.  */
 
@@ -857,10 +973,11 @@ avr_final_link_relocate (reloc_howto_type *                 howto,
        {
           /* Relative distance is too large.  */
 
-         /* Always apply WRAPAROUND for avr2 and avr4.  */
+         /* Always apply WRAPAROUND for avr2, avr25, and avr4.  */
          switch (bfd_get_mach (input_bfd))
            {
            case bfd_mach_avr2:
+           case bfd_mach_avr25:
            case bfd_mach_avr4:
              break;
 
@@ -1142,6 +1259,44 @@ avr_final_link_relocate (reloc_howto_type *                 howto,
       bfd_put_16 (input_bfd, (bfd_vma) srel &0x00ffff, contents);
       break;
 
+    case R_AVR_DIFF8:
+    case R_AVR_DIFF16:
+    case R_AVR_DIFF32:
+      /* Nothing to do here, as contents already contains the diff value. */
+      r = bfd_reloc_ok;
+      break;
+
+   case R_AVR_LDS_STS_16:
+      contents += rel->r_offset;
+      srel = (bfd_signed_vma) relocation + rel->r_addend;
+      if ((srel & 0xFFFF) < 0x40 || (srel & 0xFFFF) > 0xbf)
+        return bfd_reloc_outofrange;
+      srel = srel & 0x7f;
+      x = bfd_get_16 (input_bfd, contents);
+      x |= (srel & 0x0f) | ((srel & 0x30) << 5) | ((srel & 0x40) << 2);
+      bfd_put_16 (input_bfd, x, contents);
+      break;
+
+    case R_AVR_PORT6:
+      contents += rel->r_offset;
+      srel = (bfd_signed_vma) relocation + rel->r_addend;
+      if ((srel & 0xffff) > 0x3f)
+        return bfd_reloc_outofrange;
+      x = bfd_get_16 (input_bfd, contents);
+      x = (x & 0xf9f0) | ((srel & 0x30) << 5) | (srel & 0x0f);
+      bfd_put_16 (input_bfd, x, contents);
+      break;
+
+    case R_AVR_PORT5:
+      contents += rel->r_offset;
+      srel = (bfd_signed_vma) relocation + rel->r_addend;
+      if ((srel & 0xffff) > 0x1f)
+        return bfd_reloc_outofrange;
+      x = bfd_get_16 (input_bfd, contents);
+      x = (x & 0xff07) | ((srel & 0x1f) << 3);
+      bfd_put_16 (input_bfd, x, contents);
+      break;
+
     default:
       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                    contents, rel->r_offset,
@@ -1169,6 +1324,9 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
   Elf_Internal_Rela *           relend;
   struct elf32_avr_link_hash_table * htab = avr_link_hash_table (info);
 
+  if (htab == NULL)
+    return FALSE;
+
   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
   relend     = relocs + input_section->reloc_count;
@@ -1187,7 +1345,7 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       r_type = ELF32_R_TYPE (rel->r_info);
       r_symndx = ELF32_R_SYM (rel->r_info);
-      howto  = elf_avr_howto_table + ELF32_R_TYPE (rel->r_info);
+      howto  = elf_avr_howto_table + r_type;
       h      = NULL;
       sym    = NULL;
       sec    = NULL;
@@ -1204,26 +1362,19 @@ elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
        }
       else
        {
-         bfd_boolean unresolved_reloc, warned;
+         bfd_boolean unresolved_reloc, warned, ignored;
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   h, sec, relocation,
-                                  unresolved_reloc, warned);
+                                  unresolved_reloc, warned, ignored);
 
          name = h->root.root.string;
        }
 
-      if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+      if (sec != NULL && discarded_section (sec))
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, 1, relend, howto, 0, contents);
 
       if (info->relocatable)
        continue;
@@ -1299,10 +1450,22 @@ bfd_elf_avr_final_write_processing (bfd *abfd,
       val = E_AVR_MACH_AVR1;
       break;
 
+    case bfd_mach_avr25:
+      val = E_AVR_MACH_AVR25;
+      break;
+
     case bfd_mach_avr3:
       val = E_AVR_MACH_AVR3;
       break;
 
+    case bfd_mach_avr31:
+      val = E_AVR_MACH_AVR31;
+      break;
+
+    case bfd_mach_avr35:
+      val = E_AVR_MACH_AVR35;
+      break;
+
     case bfd_mach_avr4:
       val = E_AVR_MACH_AVR4;
       break;
@@ -1311,9 +1474,45 @@ bfd_elf_avr_final_write_processing (bfd *abfd,
       val = E_AVR_MACH_AVR5;
       break;
 
+    case bfd_mach_avr51:
+      val = E_AVR_MACH_AVR51;
+      break;
+
     case bfd_mach_avr6:
       val = E_AVR_MACH_AVR6;
       break;
+
+    case bfd_mach_avrxmega1:
+      val = E_AVR_MACH_XMEGA1;
+      break;
+
+    case bfd_mach_avrxmega2:
+      val = E_AVR_MACH_XMEGA2;
+      break;
+
+    case bfd_mach_avrxmega3:
+      val = E_AVR_MACH_XMEGA3;
+      break;
+
+    case bfd_mach_avrxmega4:
+      val = E_AVR_MACH_XMEGA4;
+      break;
+
+    case bfd_mach_avrxmega5:
+      val = E_AVR_MACH_XMEGA5;
+      break;
+
+    case bfd_mach_avrxmega6:
+      val = E_AVR_MACH_XMEGA6;
+      break;
+
+    case bfd_mach_avrxmega7:
+      val = E_AVR_MACH_XMEGA7;
+      break;
+
+   case bfd_mach_avrtiny:
+      val = E_AVR_MACH_AVRTINY;
+      break;
     }
 
   elf_elfheader (abfd)->e_machine = EM_AVR;
@@ -1345,10 +1544,22 @@ elf32_avr_object_p (bfd *abfd)
          e_set = bfd_mach_avr1;
          break;
 
+       case E_AVR_MACH_AVR25:
+         e_set = bfd_mach_avr25;
+         break;
+
        case E_AVR_MACH_AVR3:
          e_set = bfd_mach_avr3;
          break;
 
+       case E_AVR_MACH_AVR31:
+         e_set = bfd_mach_avr31;
+         break;
+
+       case E_AVR_MACH_AVR35:
+         e_set = bfd_mach_avr35;
+         break;
+
        case E_AVR_MACH_AVR4:
          e_set = bfd_mach_avr4;
          break;
@@ -1357,15 +1568,149 @@ elf32_avr_object_p (bfd *abfd)
          e_set = bfd_mach_avr5;
          break;
 
+       case E_AVR_MACH_AVR51:
+         e_set = bfd_mach_avr51;
+         break;
+
        case E_AVR_MACH_AVR6:
          e_set = bfd_mach_avr6;
          break;
+
+       case E_AVR_MACH_XMEGA1:
+         e_set = bfd_mach_avrxmega1;
+         break;
+
+       case E_AVR_MACH_XMEGA2:
+         e_set = bfd_mach_avrxmega2;
+         break;
+
+       case E_AVR_MACH_XMEGA3:
+         e_set = bfd_mach_avrxmega3;
+         break;
+
+       case E_AVR_MACH_XMEGA4:
+         e_set = bfd_mach_avrxmega4;
+         break;
+
+       case E_AVR_MACH_XMEGA5:
+         e_set = bfd_mach_avrxmega5;
+         break;
+
+       case E_AVR_MACH_XMEGA6:
+         e_set = bfd_mach_avrxmega6;
+         break;
+
+       case E_AVR_MACH_XMEGA7:
+         e_set = bfd_mach_avrxmega7;
+         break;
+
+    case E_AVR_MACH_AVRTINY:
+      e_set = bfd_mach_avrtiny;
+      break;
        }
     }
   return bfd_default_set_arch_mach (abfd, bfd_arch_avr,
                                    e_set);
 }
 
+/* Returns whether the relocation type passed is a diff reloc. */
+
+static bfd_boolean
+elf32_avr_is_diff_reloc (Elf_Internal_Rela *irel)
+{
+  return (ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF8
+          ||ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF16
+          || ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF32);
+}
+
+/* Reduce the diff value written in the section by count if the shrinked
+   insn address happens to fall between the two symbols for which this
+   diff reloc was emitted.  */
+
+static void
+elf32_avr_adjust_diff_reloc_value (bfd *abfd,
+                                   struct bfd_section *isec,
+                                   Elf_Internal_Rela *irel,
+                                   bfd_vma symval,
+                                   bfd_vma shrinked_insn_address,
+                                   int count)
+{
+  unsigned char *reloc_contents = NULL;
+  unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
+  if (isec_contents == NULL)
+  {
+    if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
+      return;
+
+    elf_section_data (isec)->this_hdr.contents = isec_contents;
+  }
+
+  reloc_contents = isec_contents + irel->r_offset;
+
+  /* Read value written in object file. */
+ bfd_vma x = 0;
+  switch (ELF32_R_TYPE (irel->r_info))
+  {
+  case R_AVR_DIFF8:
+    {
+      x = *reloc_contents;
+      break;
+    }
+  case R_AVR_DIFF16:
+    {
+      x = bfd_get_16 (abfd, reloc_contents);
+      break;
+    }
+  case R_AVR_DIFF32:
+    {
+      x = bfd_get_32 (abfd, reloc_contents);
+      break;
+    }
+  default:
+    {
+      BFD_FAIL();
+    }
+  }
+
+  /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
+     into the object file at the reloc offset. sym2's logical value is
+     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;
+
+  /* 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)
+  {
+    switch (ELF32_R_TYPE (irel->r_info))
+    {
+    case R_AVR_DIFF8:
+      {
+        *reloc_contents = (x - count);
+        break;
+      }
+    case R_AVR_DIFF16:
+      {
+        bfd_put_16 (abfd, (x - count) & 0xFFFF, reloc_contents);
+        break;
+      }
+    case R_AVR_DIFF32:
+      {
+        bfd_put_32 (abfd, (x - count) & 0xFFFFFFFF, reloc_contents);
+        break;
+      }
+    default:
+      {
+        BFD_FAIL();
+      }
+    }
+
+  }
+}
 
 /* Delete some bytes from a section while changing the size of an instruction.
    The parameter "addr" denotes the section-relative offset pointing just
@@ -1382,10 +1727,8 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
   unsigned int sec_shndx;
   bfd_byte *contents;
   Elf_Internal_Rela *irel, *irelend;
-  Elf_Internal_Rela *irelalign;
   Elf_Internal_Sym *isym;
   Elf_Internal_Sym *isymbuf = NULL;
-  Elf_Internal_Sym *isymend;
   bfd_vma toaddr;
   struct elf_link_hash_entry **sym_hashes;
   struct elf_link_hash_entry **end_hashes;
@@ -1395,10 +1738,6 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
   contents = elf_section_data (sec)->this_hdr.contents;
 
-  /* The deletion must stop at the next ALIGN reloc for an aligment
-     power larger than the number of bytes we are deleting.  */
-
-  irelalign = NULL;
   toaddr = sec->size;
 
   irel = elf_section_data (sec)->relocs;
@@ -1414,12 +1753,9 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
     {
       bfd_vma old_reloc_address;
-      bfd_vma shrinked_insn_address;
 
       old_reloc_address = (sec->output_section->vma
                            + sec->output_offset + irel->r_offset);
-      shrinked_insn_address = (sec->output_section->vma
-                              + sec->output_offset + addr - count);
 
       /* Get the new reloc address.  */
       if ((irel->r_offset > addr
@@ -1456,11 +1792,18 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
        bfd_vma symval;
        bfd_vma shrinked_insn_address;
 
+       if (isec->reloc_count == 0)
+        continue;
+
        shrinked_insn_address = (sec->output_section->vma
                                 + sec->output_offset + addr - count);
 
-       irelend = elf_section_data (isec)->relocs + isec->reloc_count;
-       for (irel = elf_section_data (isec)->relocs;
+       irel = elf_section_data (isec)->relocs;
+       /* PR 12161: Read in the relocs for this section if necessary.  */
+       if (irel == NULL)
+         irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
+
+       for (irelend = irel + isec->reloc_count;
             irel < irelend;
             irel++)
          {
@@ -1481,7 +1824,6 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
            if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
              {
                /* A local symbol.  */
-               Elf_Internal_Sym *isym;
                asection *sym_sec;
 
                isym = isymbuf + ELF32_R_SYM (irel->r_info);
@@ -1507,6 +1849,14 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
                    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,
+                                                         symval,
+                                                         shrinked_insn_address,
+                                                        count);
+                         }
+
                        irel->r_addend -= count;
 
                        if (debug_relax)
@@ -1523,13 +1873,19 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
 
   /* Adjust the local symbols defined in this section.  */
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
-  isymend = isym + symtab_hdr->sh_info;
-  for (; isym < isymend; isym++)
+  /* Fix PR 9841, there may be no local symbols.  */
+  if (isym != NULL)
     {
-      if (isym->st_shndx == sec_shndx
-          && isym->st_value > addr
-          && isym->st_value < toaddr)
-        isym->st_value -= count;
+      Elf_Internal_Sym *isymend;
+
+      isymend = isym + symtab_hdr->sh_info;
+      for (; isym < isymend; isym++)
+       {
+         if (isym->st_shndx == sec_shndx
+             && isym->st_value > addr
+             && isym->st_value < toaddr)
+           isym->st_value -= count;
+       }
     }
 
   /* Now adjust the global symbols defined in this section.  */
@@ -1595,10 +1951,22 @@ elf32_avr_relax_section (bfd *abfd,
   Elf_Internal_Rela *irel, *irelend;
   bfd_byte *contents = NULL;
   Elf_Internal_Sym *isymbuf = NULL;
-  static asection *last_input_section = NULL;
-  static Elf_Internal_Rela *last_reloc = NULL;
   struct elf32_avr_link_hash_table *htab;
 
+  /* If 'shrinkable' is FALSE, do not shrink by deleting bytes while
+     relaxing. Such shrinking can cause issues for the sections such
+     as .vectors and .jumptables. Instead the unused bytes should be
+     filled with nop instructions. */
+  bfd_boolean shrinkable = TRUE;
+
+  if (!strcmp (sec->name,".vectors")
+      || !strcmp (sec->name,".jumptables"))
+    shrinkable = FALSE;
+
+  if (link_info->relocatable)
+    (*link_info->callbacks->einfo)
+      (_("%P%F: --relax and -r may not be used together\n"));
+
   htab = avr_link_hash_table (link_info);
   if (htab == NULL)
     return FALSE;
@@ -1652,11 +2020,6 @@ elf32_avr_relax_section (bfd *abfd,
   if (internal_relocs == NULL)
     goto error_return;
 
-  if (sec != last_input_section)
-    last_reloc = NULL;
-
-  last_input_section = sec;
-
   /* Walk through the relocs looking for relaxing opportunities.  */
   irelend = internal_relocs + sec->reloc_count;
   for (irel = internal_relocs; irel < irelend; irel++)
@@ -1664,8 +2027,8 @@ elf32_avr_relax_section (bfd *abfd,
       bfd_vma symval;
 
       if (   ELF32_R_TYPE (irel->r_info) != R_AVR_13_PCREL
-          && ELF32_R_TYPE (irel->r_info) != R_AVR_7_PCREL
-          && ELF32_R_TYPE (irel->r_info) != R_AVR_CALL)
+         && ELF32_R_TYPE (irel->r_info) != R_AVR_7_PCREL
+         && ELF32_R_TYPE (irel->r_info) != R_AVR_CALL)
         continue;
 
       /* Get the section contents if we haven't done so already.  */
@@ -1682,7 +2045,7 @@ elf32_avr_relax_section (bfd *abfd,
             }
         }
 
-     /* Read this BFD's local symbols if we haven't done so already.  */
+      /* Read this BFD's local symbols if we haven't done so already.  */
       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
         {
           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
@@ -1741,9 +2104,9 @@ elf32_avr_relax_section (bfd *abfd,
          the linker is run.  */
       switch (ELF32_R_TYPE (irel->r_info))
         {
-         /* Try to turn a 22-bit absolute call/jump into an 13-bit
-            pc-relative rcall/rjmp.  */
-         case R_AVR_CALL:
+         /* Try to turn a 22-bit absolute call/jump into an 13-bit
+            pc-relative rcall/rjmp.  */
+       case R_AVR_CALL:
           {
             bfd_vma value = symval + irel->r_addend;
             bfd_vma dot, gap;
@@ -1756,10 +2119,16 @@ elf32_avr_relax_section (bfd *abfd,
             /* Compute the distance from this insn to the branch target.  */
             gap = value - dot;
 
-            /* If the distance is within -4094..+4098 inclusive, then we can
-               relax this jump/call.  +4098 because the call/jump target
-               will be closer after the relaxation.  */
-            if ((int) gap >= -4094 && (int) gap <= 4098)
+            /* Check if the gap falls in the range that can be accommodated
+               in 13bits signed (It is 12bits when encoded, as we deal with
+               word addressing). */
+            if (!shrinkable && ((int) gap >= -4096 && (int) gap <= 4095))
+              distance_short_enough = 1;
+            /* If shrinkable, then we can check for a range of distance which
+               is two bytes farther on both the directions because the call
+               or jump target will be closer by two bytes after the
+               relaxation. */
+            else if (shrinkable && ((int) gap >= -4094 && (int) gap <= 4097))
               distance_short_enough = 1;
 
             /* Here we handle the wrap-around case.  E.g. for a 16k device
@@ -1768,27 +2137,27 @@ elf32_avr_relax_section (bfd *abfd,
                vaiable avr_pc_wrap_around with the appropriate value.
                I.e. 0x4000 for a 16k device.  */
             {
-               /* Shrinking the code size makes the gaps larger in the
-                  case of wrap-arounds.  So we use a heuristical safety
-                  margin to avoid that during relax the distance gets
-                  again too large for the short jumps.  Let's assume
-                  a typical code-size reduction due to relax for a
-                  16k device of 600 bytes.  So let's use twice the
-                  typical value as safety margin.  */
-               int rgap;
-               int safety_margin;
-
-               int assumed_shrink = 600;
-               if (avr_pc_wrap_around > 0x4000)
-                 assumed_shrink = 900;
-
-               safety_margin = 2 * assumed_shrink;
-
-               rgap = avr_relative_distance_considering_wrap_around (gap);
-
-               if (rgap >= (-4092 + safety_margin)
-                   && rgap <= (4094 - safety_margin))
-                distance_short_enough = 1;
+             /* Shrinking the code size makes the gaps larger in the
+                case of wrap-arounds.  So we use a heuristical safety
+                margin to avoid that during relax the distance gets
+                again too large for the short jumps.  Let's assume
+                a typical code-size reduction due to relax for a
+                16k device of 600 bytes.  So let's use twice the
+                typical value as safety margin.  */
+             int rgap;
+             int safety_margin;
+
+             int assumed_shrink = 600;
+             if (avr_pc_wrap_around > 0x4000)
+               assumed_shrink = 900;
+
+             safety_margin = 2 * assumed_shrink;
+
+             rgap = avr_relative_distance_considering_wrap_around (gap);
+
+             if (rgap >= (-4092 + safety_margin)
+                 && rgap <= (4094 - safety_margin))
+               distance_short_enough = 1;
             }
 
             if (distance_short_enough)
@@ -1833,11 +2202,9 @@ elf32_avr_relax_section (bfd *abfd,
                 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                              R_AVR_13_PCREL);
 
-                /* Check for the vector section. There we don't want to
-                   modify the ordering!  */
-
-                if (!strcmp (sec->name,".vectors")
-                    || !strcmp (sec->name,".jumptables"))
+                /* We should not modify the ordering if 'shrinkable' is
+                   FALSE. */
+                if (!shrinkable)
                   {
                     /* Let's insert a nop.  */
                     bfd_put_8 (abfd, 0x00, contents + irel->r_offset + 2);
@@ -1882,9 +2249,9 @@ elf32_avr_relax_section (bfd *abfd,
                 if (irel->r_offset + 3 < sec->size)
                   {
                     next_insn_msb =
-                        bfd_get_8 (abfd, contents + irel->r_offset + 3);
+                     bfd_get_8 (abfd, contents + irel->r_offset + 3);
                     next_insn_lsb =
-                        bfd_get_8 (abfd, contents + irel->r_offset + 2);
+                     bfd_get_8 (abfd, contents + irel->r_offset + 2);
                   }
 
                if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
@@ -1912,9 +2279,9 @@ elf32_avr_relax_section (bfd *abfd,
                 if (irel->r_offset + 5 < sec->size)
                   {
                     next_insn_msb =
-                        bfd_get_8 (abfd, contents + irel->r_offset + 5);
+                     bfd_get_8 (abfd, contents + irel->r_offset + 5);
                     next_insn_lsb =
-                        bfd_get_8 (abfd, contents + irel->r_offset + 4);
+                     bfd_get_8 (abfd, contents + irel->r_offset + 4);
                   }
 
                 if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
@@ -1949,20 +2316,20 @@ elf32_avr_relax_section (bfd *abfd,
                 if (irel->r_offset + insn_size + 1 < sec->size)
                   {
                     next_insn_msb =
-                        bfd_get_8 (abfd, contents + irel->r_offset
-                                         + insn_size + 1);
+                     bfd_get_8 (abfd, contents + irel->r_offset
+                                + insn_size + 1);
                     next_insn_lsb =
-                        bfd_get_8 (abfd, contents + irel->r_offset
-                                         + insn_size);
+                     bfd_get_8 (abfd, contents + irel->r_offset
+                                + insn_size);
                   }
 
                 if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb))
                   {
                     /* The next insn is a ret. We possibly could delete
-                       this ret. First we need to check for preceeding
+                       this ret. First we need to check for preceding
                        sbis/sbic/sbrs or cpse "skip" instructions.  */
 
-                    int there_is_preceeding_non_skip_insn = 1;
+                    int there_is_preceding_non_skip_insn = 1;
                     bfd_vma address_of_ret;
 
                     address_of_ret = dot + insn_size;
@@ -1974,51 +2341,52 @@ elf32_avr_relax_section (bfd *abfd,
                       printf ("found jmp / ret sequence at address 0x%x\n",
                               (int) dot);
 
-                    /* We have to make sure that there is a preceeding insn.  */
+                    /* We have to make sure that there is a preceding insn.  */
                     if (irel->r_offset >= 2)
                       {
-                        unsigned char preceeding_msb;
-                        unsigned char preceeding_lsb;
-                        preceeding_msb =
-                            bfd_get_8 (abfd, contents + irel->r_offset - 1);
-                        preceeding_lsb =
-                            bfd_get_8 (abfd, contents + irel->r_offset - 2);
+                        unsigned char preceding_msb;
+                        unsigned char preceding_lsb;
+
+                        preceding_msb =
+                         bfd_get_8 (abfd, contents + irel->r_offset - 1);
+                        preceding_lsb =
+                         bfd_get_8 (abfd, contents + irel->r_offset - 2);
 
                         /* sbic.  */
-                        if (0x99 == preceeding_msb)
-                          there_is_preceeding_non_skip_insn = 0;
+                        if (0x99 == preceding_msb)
+                          there_is_preceding_non_skip_insn = 0;
 
                         /* sbis.  */
-                        if (0x9b == preceeding_msb)
-                          there_is_preceeding_non_skip_insn = 0;
+                        if (0x9b == preceding_msb)
+                          there_is_preceding_non_skip_insn = 0;
 
                         /* sbrc */
-                        if ((0xfc == (preceeding_msb & 0xfe)
-                            && (0x00 == (preceeding_lsb & 0x08))))
-                          there_is_preceeding_non_skip_insn = 0;
+                        if ((0xfc == (preceding_msb & 0xfe)
+                            && (0x00 == (preceding_lsb & 0x08))))
+                          there_is_preceding_non_skip_insn = 0;
 
                         /* sbrs */
-                        if ((0xfe == (preceeding_msb & 0xfe)
-                            && (0x00 == (preceeding_lsb & 0x08))))
-                          there_is_preceeding_non_skip_insn = 0;
+                        if ((0xfe == (preceding_msb & 0xfe)
+                            && (0x00 == (preceding_lsb & 0x08))))
+                          there_is_preceding_non_skip_insn = 0;
 
                         /* cpse */
-                        if (0x10 == (preceeding_msb & 0xfc))
-                          there_is_preceeding_non_skip_insn = 0;
+                        if (0x10 == (preceding_msb & 0xfc))
+                          there_is_preceding_non_skip_insn = 0;
 
-                        if (there_is_preceeding_non_skip_insn == 0)
+                        if (there_is_preceding_non_skip_insn == 0)
                           if (debug_relax)
-                            printf ("preceeding skip insn prevents deletion of"
-                                    " ret insn at addr 0x%x in section %s\n",
+                            printf ("preceding skip insn prevents deletion of"
+                                    " ret insn at Addy 0x%x in section %s\n",
                                     (int) dot + 2, sec->name);
                       }
                     else
                       {
                         /* There is no previous instruction.  */
-                        there_is_preceeding_non_skip_insn = 0;
+                        there_is_preceding_non_skip_insn = 0;
                       }
 
-                    if (there_is_preceeding_non_skip_insn)
+                    if (there_is_preceding_non_skip_insn)
                       {
                         /* We now only have to make sure that there is no
                            local label defined at the address of the ret
@@ -2027,9 +2395,10 @@ elf32_avr_relax_section (bfd *abfd,
 
                         int deleting_ret_is_safe = 1;
                         unsigned int section_offset_of_ret_insn =
-                                          irel->r_offset + insn_size;
+                         irel->r_offset + insn_size;
                         Elf_Internal_Sym *isym, *isymend;
                         unsigned int sec_shndx;
+                       struct bfd_section *isec;
 
                         sec_shndx =
                          _bfd_elf_section_from_bfd_section (abfd, sec);
@@ -2037,148 +2406,148 @@ elf32_avr_relax_section (bfd *abfd,
                         /* Check for local symbols.  */
                         isym = (Elf_Internal_Sym *) symtab_hdr->contents;
                         isymend = isym + symtab_hdr->sh_info;
-                        for (; isym < isymend; isym++)
-                         {
-                           if (isym->st_value == section_offset_of_ret_insn
-                               && isym->st_shndx == sec_shndx)
-                             {
-                               deleting_ret_is_safe = 0;
-                               if (debug_relax)
-                                 printf ("local label prevents deletion of ret "
-                                         "insn at address 0x%x\n",
-                                         (int) dot + insn_size);
-                             }
-                         }
-
-                         /* Now check for global symbols.  */
-                         {
-                           int symcount;
-                           struct elf_link_hash_entry **sym_hashes;
-                           struct elf_link_hash_entry **end_hashes;
-
-                           symcount = (symtab_hdr->sh_size
-                                       / sizeof (Elf32_External_Sym)
-                                       - symtab_hdr->sh_info);
-                           sym_hashes = elf_sym_hashes (abfd);
-                           end_hashes = sym_hashes + symcount;
-                           for (; sym_hashes < end_hashes; sym_hashes++)
-                            {
-                              struct elf_link_hash_entry *sym_hash =
-                                                                 *sym_hashes;
-                              if ((sym_hash->root.type == bfd_link_hash_defined
-                                  || sym_hash->root.type ==
+                       /* PR 6019: There may not be any local symbols.  */
+                        for (; isym != NULL && isym < isymend; isym++)
+                         {
+                           if (isym->st_value == section_offset_of_ret_insn
+                               && isym->st_shndx == sec_shndx)
+                             {
+                               deleting_ret_is_safe = 0;
+                               if (debug_relax)
+                                 printf ("local label prevents deletion of ret "
+                                         "insn at address 0x%x\n",
+                                         (int) dot + insn_size);
+                             }
+                         }
+
+                       /* Now check for global symbols.  */
+                       {
+                         int symcount;
+                         struct elf_link_hash_entry **sym_hashes;
+                         struct elf_link_hash_entry **end_hashes;
+
+                         symcount = (symtab_hdr->sh_size
+                                     / sizeof (Elf32_External_Sym)
+                                     - symtab_hdr->sh_info);
+                         sym_hashes = elf_sym_hashes (abfd);
+                         end_hashes = sym_hashes + symcount;
+                         for (; sym_hashes < end_hashes; sym_hashes++)
+                           {
+                             struct elf_link_hash_entry *sym_hash =
+                               *sym_hashes;
+                             if ((sym_hash->root.type == bfd_link_hash_defined
+                                  || sym_hash->root.type ==
                                   bfd_link_hash_defweak)
-                                  && sym_hash->root.u.def.section == sec
-                                  && sym_hash->root.u.def.value == section_offset_of_ret_insn)
-                                {
-                                  deleting_ret_is_safe = 0;
-                                  if (debug_relax)
-                                    printf ("global label prevents deletion of "
-                                            "ret insn at address 0x%x\n",
-                                            (int) dot + insn_size);
-                                }
-                            }
-                         }
-                         /* Now we check for relocations pointing to ret.  */
-                         {
-                           Elf_Internal_Rela *irel;
-                           Elf_Internal_Rela *relend;
-                           Elf_Internal_Shdr *symtab_hdr;
-
-                           symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-                           relend = elf_section_data (sec)->relocs
-                                    + sec->reloc_count;
-
-                           for (irel = elf_section_data (sec)->relocs;
-                                irel < relend; irel++)
-                             {
-                               bfd_vma reloc_target = 0;
-                               bfd_vma symval;
-                               Elf_Internal_Sym *isymbuf = NULL;
-
-                               /* Read this BFD's local 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)
-                                     break;
-                                  }
-
-                               /* Get the value of the symbol referred to
-                                  by the reloc.  */
-                               if (ELF32_R_SYM (irel->r_info)
-                                   < symtab_hdr->sh_info)
-                                 {
-                                   /* A local symbol.  */
-                                   Elf_Internal_Sym *isym;
-                                   asection *sym_sec;
-
-                                   isym = isymbuf
-                                          + ELF32_R_SYM (irel->r_info);
-                                   sym_sec = bfd_section_from_elf_index
-                                    (abfd, isym->st_shndx);
-                                   symval = isym->st_value;
-
-                                   /* If the reloc is absolute, it will not
-                                      have a symbol or section associated
-                                      with it.  */
-
-                                   if (sym_sec)
-                                     {
-                                       symval +=
-                                           sym_sec->output_section->vma
-                                           + sym_sec->output_offset;
-                                       reloc_target = symval + irel->r_addend;
-                                     }
-                                   else
-                                     {
-                                       reloc_target = symval + irel->r_addend;
-                                       /* Reference symbol is absolute.  */
-                                     }
-                                 }
-                              /* else ... reference symbol is extern.  */
-
-                               if (address_of_ret == reloc_target)
-                                 {
-                                   deleting_ret_is_safe = 0;
-                                   if (debug_relax)
-                                     printf ("ret from "
-                                             "rjmp/jmp ret sequence at address"
-                                             " 0x%x could not be deleted. ret"
-                                             " is target of a relocation.\n",
-                                             (int) address_of_ret);
-                                 }
-                             }
-                         }
-
-                         if (deleting_ret_is_safe)
-                           {
-                             if (debug_relax)
-                               printf ("unreachable ret instruction "
-                                       "at address 0x%x deleted.\n",
-                                       (int) dot + insn_size);
-
-                             /* Delete two bytes of data.  */
-                             if (!elf32_avr_relax_delete_bytes (abfd, sec,
-                                        irel->r_offset + insn_size, 2))
-                               goto error_return;
-
-                             /* That will change things, so, we should relax
-                                again. Note that this is not required, and it
-                                may be slow.  */
-                             *again = TRUE;
-                             break;
-                           }
+                                 && sym_hash->root.u.def.section == sec
+                                 && sym_hash->root.u.def.value == section_offset_of_ret_insn)
+                               {
+                                 deleting_ret_is_safe = 0;
+                                 if (debug_relax)
+                                   printf ("global label prevents deletion of "
+                                           "ret insn at address 0x%x\n",
+                                           (int) dot + insn_size);
+                               }
+                           }
+                       }
+
+                       /* Now we check for relocations pointing to ret.  */
+                       for (isec = abfd->sections; isec && deleting_ret_is_safe; isec = isec->next)
+                         {
+                           Elf_Internal_Rela *rel;
+                           Elf_Internal_Rela *relend;
+
+                           rel = elf_section_data (isec)->relocs;
+                           if (rel == NULL)
+                             rel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
+
+                           relend = rel + isec->reloc_count;
+
+                           for (; rel && rel < relend; rel++)
+                             {
+                               bfd_vma reloc_target = 0;
+
+                               /* Read this BFD's local 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)
+                                     break;
+                                 }
+
+                               /* Get the value of the symbol referred to
+                                  by the reloc.  */
+                               if (ELF32_R_SYM (rel->r_info)
+                                   < symtab_hdr->sh_info)
+                                 {
+                                   /* A local symbol.  */
+                                   asection *sym_sec;
+
+                                   isym = isymbuf
+                                     + ELF32_R_SYM (rel->r_info);
+                                   sym_sec = bfd_section_from_elf_index
+                                     (abfd, isym->st_shndx);
+                                   symval = isym->st_value;
+
+                                   /* If the reloc is absolute, it will not
+                                      have a symbol or section associated
+                                      with it.  */
+
+                                   if (sym_sec)
+                                     {
+                                       symval +=
+                                         sym_sec->output_section->vma
+                                         + sym_sec->output_offset;
+                                       reloc_target = symval + rel->r_addend;
+                                     }
+                                   else
+                                     {
+                                       reloc_target = symval + rel->r_addend;
+                                       /* Reference symbol is absolute.  */
+                                     }
+                                 }
+                               /* else ... reference symbol is extern.  */
+
+                               if (address_of_ret == reloc_target)
+                                 {
+                                   deleting_ret_is_safe = 0;
+                                   if (debug_relax)
+                                     printf ("ret from "
+                                             "rjmp/jmp ret sequence at address"
+                                             " 0x%x could not be deleted. ret"
+                                             " is target of a relocation.\n",
+                                             (int) address_of_ret);
+                                   break;
+                                 }
+                             }
+                         }
+
+                       if (deleting_ret_is_safe)
+                         {
+                           if (debug_relax)
+                             printf ("unreachable ret instruction "
+                                     "at address 0x%x deleted.\n",
+                                     (int) dot + insn_size);
+
+                           /* Delete two bytes of data.  */
+                           if (!elf32_avr_relax_delete_bytes (abfd, sec,
+                                                              irel->r_offset + insn_size, 2))
+                             goto error_return;
+
+                           /* That will change things, so, we should relax
+                              again. Note that this is not required, and it
+                              may be slow.  */
+                           *again = TRUE;
+                           break;
+                         }
                       }
-
                   }
               }
             break;
@@ -2456,12 +2825,10 @@ avr_build_one_stub (struct bfd_hash_entry *bh, void *in_arg)
 
 static bfd_boolean
 avr_mark_stub_not_to_be_necessary (struct bfd_hash_entry *bh,
-                                   void *in_arg)
+                                   void *in_arg ATTRIBUTE_UNUSED)
 {
   struct elf32_avr_stub_hash_entry *hsh;
-  struct elf32_avr_link_hash_table *htab;
 
-  htab = in_arg;
   hsh = avr_stub_hash_entry (bh);
   hsh->is_actually_needed = FALSE;
 
@@ -2529,7 +2896,7 @@ elf32_avr_setup_section_lists (bfd *output_bfd,
   asection *section;
   asection **input_list, **list;
   bfd_size_type amt;
-  struct elf32_avr_link_hash_table *htab = avr_link_hash_table(info);
+  struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info);
 
   if (htab == NULL || htab->no_stubs)
     return 0;
@@ -2537,7 +2904,7 @@ elf32_avr_setup_section_lists (bfd *output_bfd,
   /* Count the number of input BFDs and find the top input section id.  */
   for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
        input_bfd != NULL;
-       input_bfd = input_bfd->link_next)
+       input_bfd = input_bfd->link.next)
     {
       bfd_count += 1;
       for (section = input_bfd->sections;
@@ -2592,6 +2959,7 @@ get_local_syms (bfd *input_bfd, struct bfd_link_info *info)
   unsigned int bfd_indx;
   Elf_Internal_Sym *local_syms, **all_local_syms;
   struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info);
+  bfd_size_type amt;
 
   if (htab == NULL)
     return -1;
@@ -2599,7 +2967,7 @@ get_local_syms (bfd *input_bfd, struct bfd_link_info *info)
   /* We want to read in symbol extension records only once.  To do this
      we need to read in the local symbols in parallel and save them for
      later use; so hold pointers to the local symbols in an array.  */
-  bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
+  amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
   all_local_syms = bfd_zmalloc (amt);
   htab->all_local_syms = all_local_syms;
   if (all_local_syms == NULL)
@@ -2610,7 +2978,7 @@ get_local_syms (bfd *input_bfd, struct bfd_link_info *info)
      export stubs.  */
   for (bfd_indx = 0;
        input_bfd != NULL;
-       input_bfd = input_bfd->link_next, bfd_indx++)
+       input_bfd = input_bfd->link.next, bfd_indx++)
     {
       Elf_Internal_Shdr *symtab_hdr;
 
@@ -2687,7 +3055,7 @@ elf32_avr_size_stubs (bfd *output_bfd,
       bfd_hash_traverse (&htab->bstab, avr_mark_stub_not_to_be_necessary, htab);
       for (input_bfd = info->input_bfds, bfd_indx = 0;
            input_bfd != NULL;
-           input_bfd = input_bfd->link_next, bfd_indx++)
+           input_bfd = input_bfd->link.next, bfd_indx++)
         {
           Elf_Internal_Shdr *symtab_hdr;
           asection *section;
@@ -2760,15 +3128,20 @@ elf32_avr_size_stubs (bfd *output_bfd,
                       /* It's a local symbol.  */
                       Elf_Internal_Sym *sym;
                       Elf_Internal_Shdr *hdr;
+                     unsigned int shndx;
 
                       sym = local_syms + r_indx;
-                      hdr = elf_elfsections (input_bfd)[sym->st_shndx];
-                      sym_sec = hdr->bfd_section;
                       if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
                         sym_value = sym->st_value;
-                      destination = (sym_value + irela->r_addend
-                                     + sym_sec->output_offset
-                                     + sym_sec->output_section->vma);
+                     shndx = sym->st_shndx;
+                     if (shndx < elf_numsections (input_bfd))
+                       {
+                         hdr = elf_elfsections (input_bfd)[shndx];
+                         sym_sec = hdr->bfd_section;
+                         destination = (sym_value + irela->r_addend
+                                        + sym_sec->output_offset
+                                        + sym_sec->output_section->vma);
+                       }
                     }
                   else
                     {
@@ -2949,20 +3322,19 @@ elf32_avr_build_stubs (struct bfd_link_info *info)
 }
 
 #define ELF_ARCH               bfd_arch_avr
+#define ELF_TARGET_ID          AVR_ELF_DATA
 #define ELF_MACHINE_CODE       EM_AVR
 #define ELF_MACHINE_ALT1       EM_AVR_OLD
 #define ELF_MAXPAGESIZE                1
 
-#define TARGET_LITTLE_SYM       bfd_elf32_avr_vec
+#define TARGET_LITTLE_SYM       avr_elf32_vec
 #define TARGET_LITTLE_NAME     "elf32-avr"
 
 #define bfd_elf32_bfd_link_hash_table_create elf32_avr_link_hash_table_create
-#define bfd_elf32_bfd_link_hash_table_free   elf32_avr_link_hash_table_free
 
 #define elf_info_to_howto                   avr_info_to_howto_rela
 #define elf_info_to_howto_rel               NULL
 #define elf_backend_relocate_section         elf32_avr_relocate_section
-#define elf_backend_check_relocs             elf32_avr_check_relocs
 #define elf_backend_can_gc_sections          1
 #define elf_backend_rela_normal                     1
 #define elf_backend_final_write_processing \
This page took 0.046607 seconds and 4 git commands to generate.