Add target_id to elf_backend_data.
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index 21f92a4235a6e5ca1bf8b6ff57fedc7a7b097f40..f81831995a3303fa03d7dd983684daf68dfe518c 100644 (file)
@@ -1,6 +1,6 @@
 /* 32-bit ELF support for ARM
    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008, 2009  Free Software Foundation, Inc.
+   2008, 2009, 2010  Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -222,7 +222,7 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
   HOWTO (R_ARM_THM_CALL,       /* type */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        25,                    /* bitsize */
+        24,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed,/* complain_on_overflow */
@@ -1721,6 +1721,7 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_ARM_RELATIVE,         R_ARM_RELATIVE},
     {BFD_RELOC_ARM_GOTOFF,           R_ARM_GOTOFF32},
     {BFD_RELOC_ARM_GOTPC,            R_ARM_GOTPC},
+    {BFD_RELOC_ARM_GOT_PREL,         R_ARM_GOT_PREL},
     {BFD_RELOC_ARM_GOT32,            R_ARM_GOT32},
     {BFD_RELOC_ARM_PLT32,            R_ARM_PLT32},
     {BFD_RELOC_ARM_TARGET1,         R_ARM_TARGET1},
@@ -1828,7 +1829,7 @@ elf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
        elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
 
        /* pr_pid */
-       elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
+       elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
 
        /* pr_reg */
        offset = 72;
@@ -2399,6 +2400,7 @@ struct a8_erratum_fix {
   unsigned long orig_insn;
   char *stub_name;
   enum elf32_arm_stub_type stub_type;
+  int st_type;
 };
 
 /* A table of relocs applied to branches which might trigger Cortex-A8
@@ -2407,9 +2409,10 @@ struct a8_erratum_fix {
 struct a8_erratum_reloc {
   bfd_vma from;
   bfd_vma destination;
+  struct elf32_arm_link_hash_entry *hash;
+  const char *sym_name;
   unsigned int r_type;
   unsigned char st_type;
-  const char *sym_name;
   bfd_boolean non_a8_stub;
 };
 
@@ -2439,13 +2442,13 @@ struct elf_arm_obj_tdata
 #define is_arm_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
    && elf_tdata (bfd) != NULL \
-   && elf_object_id (bfd) == ARM_ELF_TDATA)
+   && elf_object_id (bfd) == ARM_ELF_DATA)
 
 static bfd_boolean
 elf32_arm_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct elf_arm_obj_tdata),
-                                 ARM_ELF_TDATA);
+                                 ARM_ELF_DATA);
 }
 
 /* The ARM linker needs to keep track of the number of relocs that it
@@ -2515,7 +2518,8 @@ struct elf32_arm_link_hash_entry
 
 /* Get the ARM elf linker hash table from a link_info structure.  */
 #define elf32_arm_hash_table(info) \
-  ((struct elf32_arm_link_hash_table *) ((info)->hash))
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \
+  == ARM_ELF_DATA ? ((struct elf32_arm_link_hash_table *) ((info)->hash)) : NULL)
 
 #define arm_stub_hash_lookup(table, string, create, copy) \
   ((struct elf32_arm_stub_hash_entry *) \
@@ -2649,6 +2653,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Number of elements in stub_group.  */
+  int top_id;
+
   /* Assorted information used by elf32_arm_size_stubs.  */
   unsigned int bfd_count;
   int top_index;
@@ -2744,6 +2751,9 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   struct elf32_arm_link_hash_table *htab;
 
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   /* BPABI objects never have a GOT, or associated sections.  */
   if (htab->symbian_p)
     return TRUE;
@@ -2773,6 +2783,9 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
   struct elf32_arm_link_hash_table *htab;
 
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   if (!htab->sgot && !create_got_section (dynobj, info))
     return FALSE;
 
@@ -2891,7 +2904,8 @@ elf32_arm_link_hash_table_create (bfd *abfd)
 
   if (!_bfd_elf_link_hash_table_init (& ret->root, abfd,
                                      elf32_arm_link_hash_newfunc,
-                                     sizeof (struct elf32_arm_link_hash_entry)))
+                                     sizeof (struct elf32_arm_link_hash_entry),
+                                     ARM_ELF_DATA))
     {
       free (ret);
       return NULL;
@@ -2936,6 +2950,7 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->add_stub_section = NULL;
   ret->layout_sections_again = NULL;
   ret->stub_group = NULL;
+  ret->top_id = 0;
   ret->bfd_count = 0;
   ret->top_index = 0;
   ret->input_list = NULL;
@@ -2971,6 +2986,9 @@ using_thumb_only (struct elf32_arm_link_hash_table *globals)
                                       Tag_CPU_arch);
   int profile;
 
+  if (arch == TAG_CPU_ARCH_V6_M || arch == TAG_CPU_ARCH_V6S_M)
+    return TRUE;
+
   if (arch != TAG_CPU_ARCH_V7 && arch != TAG_CPU_ARCH_V7E_M)
     return FALSE;
 
@@ -3038,7 +3056,7 @@ static enum elf32_arm_stub_type
 arm_type_of_stub (struct bfd_link_info *info,
                  asection *input_sec,
                  const Elf_Internal_Rela *rel,
-                 unsigned char st_type,
+                 int *actual_st_type,
                  struct elf32_arm_link_hash_entry *hash,
                  bfd_vma destination,
                  asection *sym_sec,
@@ -3053,6 +3071,7 @@ arm_type_of_stub (struct bfd_link_info *info,
   int thumb_only;
   enum elf32_arm_stub_type stub_type = arm_stub_none;
   int use_plt = 0;
+  int st_type = *actual_st_type;
 
   /* We don't know the actual type of destination in case it is of
      type STT_SECTION: give up.  */
@@ -3060,6 +3079,8 @@ arm_type_of_stub (struct bfd_link_info *info,
     return stub_type;
 
   globals = elf32_arm_hash_table (info);
+  if (globals == NULL)
+    return stub_type;
 
   thumb_only = using_thumb_only (globals);
 
@@ -3070,14 +3091,15 @@ arm_type_of_stub (struct bfd_link_info *info,
              + input_sec->output_section->vma
              + rel->r_offset);
 
-  branch_offset = (bfd_signed_vma)(destination - location);
-
   r_type = ELF32_R_TYPE (rel->r_info);
 
   /* Keep a simpler condition, for the sake of clarity.  */
-  if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1)
+  if (globals->splt != NULL
+      && hash != NULL
+      && hash->root.plt.offset != (bfd_vma) -1)
     {
       use_plt = 1;
+
       /* Note when dealing with PLT entries: the main PLT stub is in
         ARM mode, so if the branch is in Thumb mode, another
         Thumb->ARM stub will be inserted later just before the ARM
@@ -3086,8 +3108,15 @@ arm_type_of_stub (struct bfd_link_info *info,
         Thumb->Arm one and branch directly to the ARM PLT entry
         because it avoids spreading offset corrections in several
         places.  */
+
+      destination = (globals->splt->output_section->vma
+                    + globals->splt->output_offset
+                    + hash->root.plt.offset);
+      st_type = STT_FUNC;
     }
 
+  branch_offset = (bfd_signed_vma)(destination - location);
+
   if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24)
     {
       /* Handle cases where:
@@ -3181,7 +3210,9 @@ arm_type_of_stub (struct bfd_link_info *info,
            }
        }
     }
-  else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32)
+  else if (r_type == R_ARM_CALL
+          || r_type == R_ARM_JUMP24
+          || r_type == R_ARM_PLT32)
     {
       if (st_type == STT_ARM_TFUNC)
        {
@@ -3236,6 +3267,12 @@ arm_type_of_stub (struct bfd_link_info *info,
        }
     }
 
+  /* If a stub is needed, record the actual destination type.  */
+  if (stub_type != arm_stub_none)
+    {
+      *actual_st_type = st_type;
+    }
+
   return stub_type;
 }
 
@@ -3245,31 +3282,34 @@ static char *
 elf32_arm_stub_name (const asection *input_section,
                     const asection *sym_sec,
                     const struct elf32_arm_link_hash_entry *hash,
-                    const Elf_Internal_Rela *rel)
+                    const Elf_Internal_Rela *rel,
+                    enum elf32_arm_stub_type stub_type)
 {
   char *stub_name;
   bfd_size_type len;
 
   if (hash)
     {
-      len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1;
+      len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1 + 2 + 1;
       stub_name = (char *) bfd_malloc (len);
       if (stub_name != NULL)
-       sprintf (stub_name, "%08x_%s+%x",
+       sprintf (stub_name, "%08x_%s+%x_%d",
                 input_section->id & 0xffffffff,
                 hash->root.root.root.string,
-                (int) rel->r_addend & 0xffffffff);
+                (int) rel->r_addend & 0xffffffff,
+                (int) stub_type);
     }
   else
     {
-      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
+      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 2 + 1;
       stub_name = (char *) bfd_malloc (len);
       if (stub_name != NULL)
-       sprintf (stub_name, "%08x_%x:%x+%x",
+       sprintf (stub_name, "%08x_%x:%x+%x_%d",
                 input_section->id & 0xffffffff,
                 sym_sec->id & 0xffffffff,
                 (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
-                (int) rel->r_addend & 0xffffffff);
+                (int) rel->r_addend & 0xffffffff,
+                (int) stub_type);
     }
 
   return stub_name;
@@ -3283,7 +3323,8 @@ elf32_arm_get_stub_entry (const asection *input_section,
                          const asection *sym_sec,
                          struct elf_link_hash_entry *hash,
                          const Elf_Internal_Rela *rel,
-                         struct elf32_arm_link_hash_table *htab)
+                         struct elf32_arm_link_hash_table *htab,
+                         enum elf32_arm_stub_type stub_type)
 {
   struct elf32_arm_stub_hash_entry *stub_entry;
   struct elf32_arm_link_hash_entry *h = (struct elf32_arm_link_hash_entry *) hash;
@@ -3301,7 +3342,8 @@ elf32_arm_get_stub_entry (const asection *input_section,
 
   if (h != NULL && h->stub_cache != NULL
       && h->stub_cache->h == h
-      && h->stub_cache->id_sec == id_sec)
+      && h->stub_cache->id_sec == id_sec
+      && h->stub_cache->stub_type == stub_type)
     {
       stub_entry = h->stub_cache;
     }
@@ -3309,7 +3351,7 @@ elf32_arm_get_stub_entry (const asection *input_section,
     {
       char *stub_name;
 
-      stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel);
+      stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel, stub_type);
       if (stub_name == NULL)
        return NULL;
 
@@ -3433,24 +3475,52 @@ static bfd_reloc_status_type elf32_arm_final_link_relocate
    Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *,
    const char *, int, struct elf_link_hash_entry *, bfd_boolean *, char **);
 
+static unsigned int
+arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
+{
+  switch (stub_type)
+    {
+    case arm_stub_a8_veneer_b_cond:
+    case arm_stub_a8_veneer_b:
+    case arm_stub_a8_veneer_bl:
+      return 2;
+
+    case arm_stub_long_branch_any_any:
+    case arm_stub_long_branch_v4t_arm_thumb:
+    case arm_stub_long_branch_thumb_only:
+    case arm_stub_long_branch_v4t_thumb_thumb:
+    case arm_stub_long_branch_v4t_thumb_arm:
+    case arm_stub_short_branch_v4t_thumb_arm:
+    case arm_stub_long_branch_any_arm_pic:
+    case arm_stub_long_branch_any_thumb_pic:
+    case arm_stub_long_branch_v4t_thumb_thumb_pic:
+    case arm_stub_long_branch_v4t_arm_thumb_pic:
+    case arm_stub_long_branch_v4t_thumb_arm_pic:
+    case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_a8_veneer_blx:
+      return 4;
+    
+    default:
+      abort ();  /* Should be unreachable.  */
+    }
+}
+
 static bfd_boolean
 arm_build_one_stub (struct bfd_hash_entry *gen_entry,
                    void * in_arg)
 {
 #define MAXRELOCS 2
   struct elf32_arm_stub_hash_entry *stub_entry;
+  struct elf32_arm_link_hash_table *globals;
   struct bfd_link_info *info;
-  struct elf32_arm_link_hash_table *htab;
   asection *stub_sec;
   bfd *stub_bfd;
-  bfd_vma stub_addr;
   bfd_byte *loc;
   bfd_vma sym_value;
   int template_size;
   int size;
   const insn_sequence *template_sequence;
   int i;
-  struct elf32_arm_link_hash_table * globals;
   int stub_reloc_idx[MAXRELOCS] = {-1, -1};
   int stub_reloc_offset[MAXRELOCS] = {0, 0};
   int nrelocs = 0;
@@ -3460,26 +3530,22 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   info = (struct bfd_link_info *) in_arg;
 
   globals = elf32_arm_hash_table (info);
+  if (globals == NULL)
+    return FALSE;
 
-  htab = elf32_arm_hash_table (info);
   stub_sec = stub_entry->stub_sec;
 
-  if ((htab->fix_cortex_a8 < 0)
-      != (stub_entry->stub_type >= arm_stub_a8_veneer_lwm))
-    /* We have to do the a8 fixes last, as they are less aligned than
-       the other veneers.  */
+  if ((globals->fix_cortex_a8 < 0)
+      != (arm_stub_required_alignment (stub_entry->stub_type) == 2))
+    /* We have to do less-strictly-aligned fixes last.  */
     return TRUE;
-  
+
   /* Make a note of the offset within the stubs for this entry.  */
   stub_entry->stub_offset = stub_sec->size;
   loc = stub_sec->contents + stub_entry->stub_offset;
 
   stub_bfd = stub_sec->owner;
 
-  /* This is the address of the start of the stub.  */
-  stub_addr = stub_sec->output_section->vma + stub_sec->output_offset
-    + stub_entry->stub_offset;
-
   /* This is the address of the stub destination.  */
   sym_value = (stub_entry->target_value
               + stub_entry->target_section->output_offset
@@ -3504,17 +3570,17 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
                 BFD_ASSERT ((data & 0xff00) == 0xd000);
                 data |= ((stub_entry->orig_insn >> 22) & 0xf) << 8;
              }
-           put_thumb_insn (globals, stub_bfd, data, loc + size);
+           bfd_put_16 (stub_bfd, data, loc + size);
            size += 2;
          }
          break;
 
        case THUMB32_TYPE:
-          put_thumb_insn (globals, stub_bfd,
-                          (template_sequence[i].data >> 16) & 0xffff,
-                          loc + size);
-          put_thumb_insn (globals, stub_bfd, template_sequence[i].data & 0xffff,
-                          loc + size + 2);
+         bfd_put_16 (stub_bfd,
+                     (template_sequence[i].data >> 16) & 0xffff,
+                     loc + size);
+         bfd_put_16 (stub_bfd, template_sequence[i].data & 0xffff,
+                     loc + size + 2);
           if (template_sequence[i].r_type != R_ARM_NONE)
             {
               stub_reloc_idx[nrelocs] = i;
@@ -3524,8 +3590,8 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
           break;
 
        case ARM_TYPE:
-         put_arm_insn (globals, stub_bfd, template_sequence[i].data,
-                        loc + size);
+         bfd_put_32 (stub_bfd, template_sequence[i].data,
+                     loc + size);
          /* Handle cases where the target is encoded within the
             instruction.  */
          if (template_sequence[i].r_type == R_ARM_JUMP24)
@@ -3604,11 +3670,23 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
       }
     else
       {
-       _bfd_final_link_relocate (elf32_arm_howto_from_type
-           (template_sequence[stub_reloc_idx[i]].r_type), stub_bfd, stub_sec,
-         stub_sec->contents, stub_entry->stub_offset + stub_reloc_offset[i],
-         sym_value + stub_entry->target_addend,
-         template_sequence[stub_reloc_idx[i]].reloc_addend);
+       Elf_Internal_Rela rel;
+       bfd_boolean unresolved_reloc;
+       char *error_message;
+       bfd_vma points_to = sym_value + stub_entry->target_addend
+         + template_sequence[stub_reloc_idx[i]].reloc_addend;
+
+       rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i];
+       rel.r_info = ELF32_R_INFO (0,
+                                   template_sequence[stub_reloc_idx[i]].r_type);
+       rel.r_addend = 0;
+
+       elf32_arm_final_link_relocate (elf32_arm_howto_from_type
+           (template_sequence[stub_reloc_idx[i]].r_type),
+         stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel,
+         points_to, info, stub_entry->target_section, "", stub_entry->st_type,
+         (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc,
+         &error_message);
       }
 
   return TRUE;
@@ -3665,16 +3743,14 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type,
 
 static bfd_boolean
 arm_size_one_stub (struct bfd_hash_entry *gen_entry,
-                  void * in_arg)
+                  void *in_arg ATTRIBUTE_UNUSED)
 {
   struct elf32_arm_stub_hash_entry *stub_entry;
-  struct elf32_arm_link_hash_table *htab;
   const insn_sequence *template_sequence;
   int template_size, size;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
-  htab = (struct elf32_arm_link_hash_table *) in_arg;
 
   BFD_ASSERT((stub_entry->stub_type > arm_stub_none)
             && stub_entry->stub_type < ARRAY_SIZE(stub_definitions));
@@ -3710,6 +3786,8 @@ elf32_arm_setup_section_lists (bfd *output_bfd,
   bfd_size_type amt;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
 
+  if (htab == NULL)
+    return 0;
   if (! is_elf_hash_table (htab))
     return 0;
 
@@ -3733,6 +3811,7 @@ elf32_arm_setup_section_lists (bfd *output_bfd,
   htab->stub_group = (struct map_stub *) bfd_zmalloc (amt);
   if (htab->stub_group == NULL)
     return -1;
+  htab->top_id = top_id;
 
   /* We can't use output_bfd->section_count here to find the top output
      section index as some sections may have been removed, and
@@ -3781,11 +3860,14 @@ elf32_arm_next_input_section (struct bfd_link_info *info,
 {
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
 
+  if (htab == NULL)
+    return;
+
   if (isec->output_section->index <= htab->top_index)
     {
       asection **list = htab->input_list + isec->output_section->index;
 
-      if (*list != bfd_abs_section_ptr)
+      if (*list != bfd_abs_section_ptr && (isec->flags & SEC_CODE) != 0)
        {
          /* Steal the link_sec pointer for our list.  */
 #define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
@@ -3940,6 +4022,9 @@ cortex_a8_erratum_scan (bfd *input_bfd,
   unsigned int num_a8_fixes = *num_a8_fixes_p;
   unsigned int a8_fix_table_size = *a8_fix_table_size_p;
 
+  if (htab == NULL)
+    return FALSE;
+
   for (section = input_bfd->sections;
        section != NULL;
        section = section->next)
@@ -4015,14 +4100,14 @@ cortex_a8_erratum_scan (bfd *input_bfd,
                }
 
              is_32bit_branch = is_b || is_bl || is_blx || is_bcc;
-                          
+
               if (((base_vma + i) & 0xfff) == 0xffe
                  && insn_32bit
                  && is_32bit_branch
                  && last_was_32bit
                  && ! last_was_branch)
                 {
-                  bfd_signed_vma offset;
+                  bfd_signed_vma offset = 0;
                   bfd_boolean force_target_arm = FALSE;
                  bfd_boolean force_target_thumb = FALSE;
                   bfd_vma target;
@@ -4039,6 +4124,7 @@ cortex_a8_erratum_scan (bfd *input_bfd,
                    {
                      char *error_message = NULL;
                      struct elf_link_hash_entry *entry;
+                     bfd_boolean use_plt = FALSE;
 
                      /* We don't care about the error returned from this
                         function, only if there is glue or not.  */
@@ -4048,12 +4134,18 @@ cortex_a8_erratum_scan (bfd *input_bfd,
                      if (entry)
                        found->non_a8_stub = TRUE;
 
-                     if (found->r_type == R_ARM_THM_CALL
-                         && found->st_type != STT_ARM_TFUNC)
-                       force_target_arm = TRUE;
-                     else if (found->r_type == R_ARM_THM_CALL
-                              && found->st_type == STT_ARM_TFUNC)
-                       force_target_thumb = TRUE;
+                     /* Keep a simpler condition, for the sake of clarity.  */
+                     if (htab->splt != NULL && found->hash != NULL
+                         && found->hash->root.plt.offset != (bfd_vma) -1)
+                       use_plt = TRUE;
+
+                     if (found->r_type == R_ARM_THM_CALL)
+                       {
+                         if (found->st_type != STT_ARM_TFUNC || use_plt)
+                           force_target_arm = TRUE;
+                         else
+                           force_target_thumb = TRUE;
+                       }
                    }
 
                   /* Check if we have an offending branch instruction.  */
@@ -4186,6 +4278,8 @@ cortex_a8_erratum_scan (bfd *input_bfd,
                           a8_fixes[num_a8_fixes].orig_insn = insn;
                           a8_fixes[num_a8_fixes].stub_name = stub_name;
                           a8_fixes[num_a8_fixes].stub_type = stub_type;
+                          a8_fixes[num_a8_fixes].st_type =
+                           is_blx ? STT_FUNC : STT_ARM_TFUNC;
 
                           num_a8_fixes++;
                         }
@@ -4201,11 +4295,11 @@ cortex_a8_erratum_scan (bfd *input_bfd,
       if (elf_section_data (section)->this_hdr.contents == NULL)
         free (contents);
     }
-  
+
   *a8_fixes_p = a8_fixes;
   *num_a8_fixes_p = num_a8_fixes;
   *a8_fix_table_size_p = a8_fix_table_size;
-  
+
   return FALSE;
 }
 
@@ -4231,6 +4325,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
   struct a8_erratum_reloc *a8_relocs = NULL;
   unsigned int num_a8_relocs = 0, a8_reloc_table_size = 10, i;
 
+  if (htab == NULL)
+    return FALSE;
+
   if (htab->fix_cortex_a8)
     {
       a8_fixes = (struct a8_erratum_fix *)
@@ -4353,7 +4450,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
                  const char *sym_name;
                  char *stub_name;
                  const asection *id_sec;
-                 unsigned char st_type;
+                 int st_type;
                  bfd_boolean created_stub = FALSE;
 
                  r_type = ELF32_R_TYPE (irela->r_info);
@@ -4411,7 +4508,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
                        /* This is an undefined symbol.  It can never
                           be resolved. */
                        continue;
-                 
+
                      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
                        sym_value = sym->st_value;
                      destination = (sym_value + irela->r_addend
@@ -4450,7 +4547,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
                             use the PLT stub as target address to
                             decide whether a branch stub is
                             needed.  */
-                         if (globals->splt != NULL && hash != NULL
+                         if (globals != NULL
+                             && globals->splt != NULL
+                             && hash != NULL
                              && hash->root.plt.offset != (bfd_vma) -1)
                            {
                              sym_sec = globals->splt;
@@ -4475,7 +4574,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
                          struct elf32_arm_link_hash_table *globals =
                            elf32_arm_hash_table (info);
 
-                         if (globals->splt != NULL && hash != NULL
+                         if (globals != NULL
+                             && globals->splt != NULL
+                             && hash != NULL
                              && hash->root.plt.offset != (bfd_vma) -1)
                            {
                              sym_sec = globals->splt;
@@ -4501,7 +4602,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
                    {
                      /* Determine what (if any) linker stub is needed.  */
                      stub_type = arm_type_of_stub (info, section, irela,
-                                                   st_type, hash,
+                                                   &st_type, hash,
                                                    destination, sym_sec,
                                                    input_bfd, sym_name);
                      if (stub_type == arm_stub_none)
@@ -4512,7 +4613,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
                      /* Get the name of this stub.  */
                      stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash,
-                                                      irela);
+                                                      irela, stub_type);
                      if (!stub_name)
                        goto error_ret_free_internal;
 
@@ -4611,6 +4712,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
                           a8_relocs[num_a8_relocs].st_type = st_type;
                           a8_relocs[num_a8_relocs].sym_name = sym_name;
                           a8_relocs[num_a8_relocs].non_a8_stub = created_stub;
+                          a8_relocs[num_a8_relocs].hash = hash;
 
                           num_a8_relocs++;
                         }
@@ -4712,7 +4814,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
           stub_entry->target_value = a8_fixes[i].offset;
           stub_entry->target_addend = a8_fixes[i].addend;
           stub_entry->orig_insn = a8_fixes[i].orig_insn;
-          stub_entry->st_type = STT_ARM_TFUNC;
+         stub_entry->st_type = a8_fixes[i].st_type;
 
           size = find_stub_size_and_template (a8_fixes[i].stub_type,
                                               &template_sequence,
@@ -4753,6 +4855,8 @@ elf32_arm_build_stubs (struct bfd_link_info *info)
   struct elf32_arm_link_hash_table *htab;
 
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   for (stub_sec = htab->stub_bfd->sections;
        stub_sec != NULL;
@@ -4798,6 +4902,8 @@ find_thumb_glue (struct bfd_link_info *link_info,
 
   /* We need a pointer to the armelf specific hash table.  */
   hash_table = elf32_arm_hash_table (link_info);
+  if (hash_table == NULL)
+    return NULL;
 
   tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name)
                                   + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
@@ -4832,6 +4938,8 @@ find_arm_glue (struct bfd_link_info *link_info,
 
   /* We need a pointer to the elfarm specific hash table.  */
   hash_table = elf32_arm_hash_table (link_info);
+  if (hash_table == NULL)
+    return NULL;
 
   tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name)
                                   + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
@@ -4994,7 +5102,6 @@ record_arm_to_thumb_glue (struct bfd_link_info * link_info,
   bfd_size_type size;
 
   globals = elf32_arm_hash_table (link_info);
-
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
@@ -5067,7 +5174,6 @@ record_arm_bx_glue (struct bfd_link_info * link_info, int reg)
     return;
 
   globals = elf32_arm_hash_table (link_info);
-
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
@@ -5160,11 +5266,9 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
   struct bfd_link_hash_entry *bh;
   bfd_vma val;
   struct _arm_elf_section_data *sec_data;
-  int errcount;
   elf32_vfp11_erratum_list *newerr;
 
   hash_table = elf32_arm_hash_table (link_info);
-
   BFD_ASSERT (hash_table != NULL);
   BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL);
 
@@ -5199,7 +5303,7 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
   myh->forced_local = 1;
 
   /* Link veneer back to calling location.  */
-  errcount = ++(sec_data->erratumcount);
+  sec_data->erratumcount += 1;
   newerr = (elf32_vfp11_erratum_list *)
       bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
 
@@ -5329,7 +5433,6 @@ bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info)
   BFD_ASSERT (!(abfd->flags & DYNAMIC));
 
   globals = elf32_arm_hash_table (info);
-
   BFD_ASSERT (globals != NULL);
 
   if (globals->bfd_of_glue_owner != NULL)
@@ -5369,7 +5472,6 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
   /* Here we have a bfd that is to be included on the link.  We have a
      hook to do reloc rummaging, before section sizes are nailed down.  */
   globals = elf32_arm_hash_table (link_info);
-
   BFD_ASSERT (globals != NULL);
 
   check_use_blx (globals);
@@ -5570,6 +5672,9 @@ bfd_elf32_arm_set_cortex_a8_fix (bfd *obfd, struct bfd_link_info *link_info)
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
   obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd);
 
+  if (globals == NULL)
+    return;
+
   if (globals->fix_cortex_a8 == -1)
     {
       /* Turn on Cortex-A8 erratum workaround for ARMv7-A.  */
@@ -5589,6 +5694,8 @@ bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
   obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd);
 
+  if (globals == NULL)
+    return;
   /* We assume that ARMv7+ does not need the VFP11 denorm erratum fix.  */
   if (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V7)
     {
@@ -5693,7 +5800,7 @@ static enum bfd_arm_vfp11_pipe
 bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
                            int *numregs)
 {
-  enum bfd_arm_vfp11_pipe pipe = VFP11_BAD;
+  enum bfd_arm_vfp11_pipe vpipe = VFP11_BAD;
   bfd_boolean is_double = ((insn & 0xf00) == 0xb00) ? 1 : 0;
 
   if ((insn & 0x0f000e10) == 0x0e000a00)  /* A data-processing insn.  */
@@ -5712,7 +5819,7 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
         case 1: /* fnmac[sd].  */
         case 2: /* fmsc[sd].  */
         case 3: /* fnmsc[sd].  */
-          pipe = VFP11_FMAC;
+          vpipe = VFP11_FMAC;
           bfd_arm_vfp11_write_mask (destmask, fd);
           regs[0] = fd;
           regs[1] = bfd_arm_vfp11_regno (insn, is_double, 16, 7);  /* Fn.  */
@@ -5724,11 +5831,11 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
         case 5: /* fnmul[sd].  */
         case 6: /* fadd[sd].  */
         case 7: /* fsub[sd].  */
-          pipe = VFP11_FMAC;
+          vpipe = VFP11_FMAC;
           goto vfp_binop;
 
         case 8: /* fdiv[sd].  */
-          pipe = VFP11_DS;
+          vpipe = VFP11_DS;
           vfp_binop:
           bfd_arm_vfp11_write_mask (destmask, fd);
           regs[0] = bfd_arm_vfp11_regno (insn, is_double, 16, 7);   /* Fn.  */
@@ -5758,14 +5865,14 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
               case 27: /* ftosiz[sd].  */
                 /* These instructions will not bounce due to underflow.  */
                 *numregs = 0;
-                pipe = VFP11_FMAC;
+                vpipe = VFP11_FMAC;
                 break;
 
               case 3: /* fsqrt[sd].  */
                 /* fsqrt cannot underflow, but it can (perhaps) overwrite
                    registers to cause the erratum in previous instructions.  */
                 bfd_arm_vfp11_write_mask (destmask, fd);
-                pipe = VFP11_DS;
+                vpipe = VFP11_DS;
                 break;
 
               case 15: /* fcvt{ds,sd}.  */
@@ -5780,7 +5887,7 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
 
                   *numregs = rnum;
 
-                  pipe = VFP11_FMAC;
+                  vpipe = VFP11_FMAC;
                 }
                 break;
 
@@ -5810,7 +5917,7 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
             }
        }
 
-      pipe = VFP11_LS;
+      vpipe = VFP11_LS;
     }
   else if ((insn & 0x0e100e00) == 0x0c100a00)  /* A load insn.  */
     {
@@ -5845,7 +5952,7 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
           return VFP11_BAD;
         }
 
-      pipe = VFP11_LS;
+      vpipe = VFP11_LS;
     }
   /* Single-register transfer. Note L==0.  */
   else if ((insn & 0x0f100e10) == 0x0e000a10)
@@ -5867,10 +5974,10 @@ bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
           break;
         }
 
-      pipe = VFP11_LS;
+      vpipe = VFP11_LS;
     }
 
-  return pipe;
+  return vpipe;
 }
 
 
@@ -5892,6 +5999,9 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
   int use_vector = (globals->vfp11_fix == BFD_ARM_VFP11_FIX_VECTOR);
 
+  if (globals == NULL)
+    return FALSE;
+
   /* We use a simple FSM to match troublesome VFP11 instruction sequences.
      The states transition as follows:
 
@@ -5990,17 +6100,17 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
                   | (contents[i + 1] << 8)
                   | contents[i];
               unsigned int writemask = 0;
-              enum bfd_arm_vfp11_pipe pipe;
+              enum bfd_arm_vfp11_pipe vpipe;
 
               switch (state)
                 {
                 case 0:
-                  pipe = bfd_arm_vfp11_insn_decode (insn, &writemask, regs,
+                  vpipe = bfd_arm_vfp11_insn_decode (insn, &writemask, regs,
                                                     &numregs);
                   /* I'm assuming the VFP11 erratum can trigger with denorm
                      operands on either the FMAC or the DS pipeline. This might
                      lead to slightly overenthusiastic veneer insertion.  */
-                  if (pipe == VFP11_FMAC || pipe == VFP11_DS)
+                  if (vpipe == VFP11_FMAC || vpipe == VFP11_DS)
                     {
                       state = use_vector ? 1 : 2;
                       first_fmac = i;
@@ -6011,10 +6121,10 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
                 case 1:
                   {
                     int other_regs[3], other_numregs;
-                    pipe = bfd_arm_vfp11_insn_decode (insn, &writemask,
+                    vpipe = bfd_arm_vfp11_insn_decode (insn, &writemask,
                                                      other_regs,
                                                       &other_numregs);
-                    if (pipe != VFP11_BAD
+                    if (vpipe != VFP11_BAD
                         && bfd_arm_vfp11_antidependency (writemask, regs,
                                                         numregs))
                       state = 3;
@@ -6026,10 +6136,10 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
                 case 2:
                   {
                     int other_regs[3], other_numregs;
-                    pipe = bfd_arm_vfp11_insn_decode (insn, &writemask,
+                    vpipe = bfd_arm_vfp11_insn_decode (insn, &writemask,
                                                      other_regs,
                                                       &other_numregs);
-                    if (pipe != VFP11_BAD
+                    if (vpipe != VFP11_BAD
                         && bfd_arm_vfp11_antidependency (writemask, regs,
                                                         numregs))
                       state = 3;
@@ -6049,9 +6159,8 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
                 {
                   elf32_vfp11_erratum_list *newerr =(elf32_vfp11_erratum_list *)
                       bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
-                  int errcount;
 
-                  errcount = ++(elf32_arm_section_data (sec)->erratumcount);
+                  elf32_arm_section_data (sec)->erratumcount += 1;
 
                   newerr->u.b.vfp_insn = veneer_of_insn;
 
@@ -6115,6 +6224,8 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd,
     return;
 
   globals = elf32_arm_hash_table (link_info);
+  if (globals == NULL)
+    return;
 
   tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen
                                   (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
@@ -6197,6 +6308,8 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
   struct elf32_arm_link_hash_table *globals;
 
   globals = elf32_arm_hash_table (link_info);
+  if (globals == NULL)
+    return;
 
   globals->target1_is_rel = target1_is_rel;
   if (strcmp (target2_type, "rel") == 0)
@@ -6272,7 +6385,6 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info,
     return FALSE;
 
   globals = elf32_arm_hash_table (info);
-
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
@@ -6370,7 +6482,6 @@ elf32_arm_create_thumb_stub (struct bfd_link_info * info,
     return NULL;
 
   globals = elf32_arm_hash_table (info);
-
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
@@ -6466,7 +6577,6 @@ elf32_arm_to_thumb_stub (struct bfd_link_info * info,
   struct elf32_arm_link_hash_table * globals;
 
   globals = elf32_arm_hash_table (info);
-
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
@@ -6521,7 +6631,6 @@ elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf)
     return TRUE;
 
   globals = elf32_arm_hash_table (info);
-
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
@@ -6557,7 +6666,6 @@ elf32_arm_bx_glue (struct bfd_link_info * info, int reg)
   struct elf32_arm_link_hash_table *globals;
 
   globals = elf32_arm_hash_table (info);
-
   BFD_ASSERT (globals != NULL);
   BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
 
@@ -6595,6 +6703,9 @@ elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED,
     return;
 
   globals = elf32_arm_hash_table (link_info);
+  if (globals == NULL)
+    return;
+
   /* If blx is available then exported Thumb symbols are OK and there is
      nothing to do.  */
   if (globals->use_blx)
@@ -6761,8 +6872,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   unsigned long                 r_symndx;
   bfd_byte *                    hit_data = contents + rel->r_offset;
   bfd *                         dynobj = NULL;
-  Elf_Internal_Shdr *           symtab_hdr;
-  struct elf_link_hash_entry ** sym_hashes;
   bfd_vma *                     local_got_offsets;
   asection *                    sgot = NULL;
   asection *                    splt = NULL;
@@ -6772,6 +6881,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   struct elf32_arm_link_hash_table * globals;
 
   globals = elf32_arm_hash_table (info);
+  if (globals == NULL)
+    return bfd_reloc_notsupported;
 
   BFD_ASSERT (is_arm_elf (input_bfd));
 
@@ -6799,8 +6910,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
       sgot = bfd_get_section_by_name (dynobj, ".got");
       splt = bfd_get_section_by_name (dynobj, ".plt");
     }
-  symtab_hdr = & elf_symtab_hdr (input_bfd);
-  sym_hashes = elf_sym_hashes (input_bfd);
   local_got_offsets = elf_local_got_offsets (input_bfd);
   r_symndx = ELF32_R_SYM (rel->r_info);
 
@@ -6875,11 +6984,12 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
         run time.  */
       if ((info->shared || globals->root.is_relocatable_executable)
          && (input_section->flags & SEC_ALLOC)
-         && !(elf32_arm_hash_table (info)->vxworks_p
+         && !(globals->vxworks_p
               && strcmp (input_section->output_section->name,
                          ".tls_vars") == 0)
          && ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI)
              || !SYMBOL_CALLS_LOCAL (info, h))
+         && (!strstr (input_section->name, STUB_SUFFIX))
          && (h == NULL
              || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
              || h->root.type != bfd_link_hash_undefweak)
@@ -7004,7 +7114,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        case R_ARM_PC24:          /* Arm B/BL instruction.  */
        case R_ARM_PLT32:
          {
-         bfd_signed_vma branch_offset;
          struct elf32_arm_stub_hash_entry *stub_entry = NULL;
 
          if (r_type == R_ARM_XPC25)
@@ -7040,45 +7149,46 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              || r_type == R_ARM_JUMP24
              || r_type == R_ARM_PLT32)
            {
-             bfd_vma from;
-             
-             /* If the call goes through a PLT entry, make sure to
-                check distance to the right destination address.  */
-             if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
-               {
-                 value = (splt->output_section->vma
-                          + splt->output_offset
-                          + h->plt.offset);
-                 *unresolved_reloc_p = FALSE;
-                 /* The PLT entry is in ARM mode, regardless of the
-                    target function.  */
-                 sym_flags = STT_FUNC;
-               }
+             enum elf32_arm_stub_type stub_type = arm_stub_none;
+             struct elf32_arm_link_hash_entry *hash;
 
-             from = (input_section->output_section->vma
-                     + input_section->output_offset
-                     + rel->r_offset);
-             branch_offset = (bfd_signed_vma)(value - from);
-
-             if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
-                 || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET
-                 || ((sym_flags == STT_ARM_TFUNC)
-                     && (((r_type == R_ARM_CALL) && !globals->use_blx)
-                         || (r_type == R_ARM_JUMP24)
-                         || (r_type == R_ARM_PLT32) ))
-                 )
+             hash = (struct elf32_arm_link_hash_entry *) h;
+             stub_type = arm_type_of_stub (info, input_section, rel,
+                                           &sym_flags, hash,
+                                           value, sym_sec,
+                                           input_bfd, sym_name);
+
+             if (stub_type != arm_stub_none)
                {
                  /* The target is out of reach, so redirect the
                     branch to the local stub for this function.  */
 
                  stub_entry = elf32_arm_get_stub_entry (input_section,
                                                         sym_sec, h,
-                                                        rel, globals);
+                                                        rel, globals,
+                                                        stub_type);
                  if (stub_entry != NULL)
                    value = (stub_entry->stub_offset
                             + stub_entry->stub_sec->output_offset
                             + stub_entry->stub_sec->output_section->vma);
                }
+             else
+               {
+                 /* If the call goes through a PLT entry, make sure to
+                    check distance to the right destination address.  */
+                 if (h != NULL
+                     && splt != NULL
+                     && h->plt.offset != (bfd_vma) -1)
+                   {
+                     value = (splt->output_section->vma
+                              + splt->output_offset
+                              + h->plt.offset);
+                     *unresolved_reloc_p = FALSE;
+                     /* The PLT entry is in ARM mode, regardless of the
+                        target function.  */
+                     sym_flags = STT_FUNC;
+                   }
+               }
            }
 
          /* The ARM ELF ABI says that this reloc is computed as: S - P + A
@@ -7212,7 +7322,11 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
     case R_ARM_ABS8:
       value += addend;
-      if ((long) value > 0x7f || (long) value < -0x80)
+
+      /* There is no way to tell whether the user intended to use a signed or
+        unsigned addend.  When checking for overflow we accept either,
+        as specified by the AAELF.  */
+      if ((long) value > 0xff || (long) value < -0x80)
        return bfd_reloc_overflow;
 
       bfd_put_8 (input_bfd, value, hit_data);
@@ -7221,7 +7335,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
     case R_ARM_ABS16:
       value += addend;
 
-      if ((long) value > 0x7fff || (long) value < -0x8000)
+      /* See comment for R_ARM_ABS8.  */
+      if ((long) value > 0xffff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -7458,58 +7573,29 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              }
          }
 
-       /* Handle calls via the PLT.  */
-       if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
-         {
-           value = (splt->output_section->vma
-                    + splt->output_offset
-                    + h->plt.offset);
-           if (globals->use_blx && r_type == R_ARM_THM_CALL)
-             {
-               /* If the Thumb BLX instruction is available, convert the
-                  BL to a BLX instruction to call the ARM-mode PLT entry.  */
-               lower_insn = (lower_insn & ~0x1000) | 0x0800;
-               sym_flags = STT_FUNC;
-             }
-           else
-             {
-               /* Target the Thumb stub before the ARM PLT entry.  */
-               value -= PLT_THUMB_STUB_SIZE;
-               sym_flags = STT_ARM_TFUNC;
-             }
-           *unresolved_reloc_p = FALSE;
-         }
-
+       enum elf32_arm_stub_type stub_type = arm_stub_none;
        if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24)
          {
            /* Check if a stub has to be inserted because the destination
               is too far.  */
-           bfd_vma from;
-           bfd_signed_vma branch_offset;
-           struct elf32_arm_stub_hash_entry *stub_entry = NULL;
-
-           from = (input_section->output_section->vma
-                   + input_section->output_offset
-                   + rel->r_offset);
-           branch_offset = (bfd_signed_vma)(value - from);
-
-           if ((!thumb2
-                && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET
-                    || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET)))
-               ||
-               (thumb2
-                && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
-                    || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
-               || ((sym_flags != STT_ARM_TFUNC)
-                   && (((r_type == R_ARM_THM_CALL) && !globals->use_blx)
-                       || r_type == R_ARM_THM_JUMP24)))
+           struct elf32_arm_stub_hash_entry *stub_entry;
+           struct elf32_arm_link_hash_entry *hash;
+
+           hash = (struct elf32_arm_link_hash_entry *) h;
+
+           stub_type = arm_type_of_stub (info, input_section, rel,
+                                         &sym_flags, hash, value, sym_sec,
+                                         input_bfd, sym_name);
+
+           if (stub_type != arm_stub_none)
              {
                /* The target is out of reach or we are changing modes, so
                   redirect the branch to the local stub for this
                   function.  */
                stub_entry = elf32_arm_get_stub_entry (input_section,
                                                       sym_sec, h,
-                                                      rel, globals);
+                                                      rel, globals,
+                                                      stub_type);
                if (stub_entry != NULL)
                  value = (stub_entry->stub_offset
                           + stub_entry->stub_sec->output_offset
@@ -7526,6 +7612,33 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              }
          }
 
+       /* Handle calls via the PLT.  */
+       if (stub_type == arm_stub_none
+           && h != NULL
+           && splt != NULL
+           && h->plt.offset != (bfd_vma) -1)
+         {
+           value = (splt->output_section->vma
+                    + splt->output_offset
+                    + h->plt.offset);
+
+           if (globals->use_blx && r_type == R_ARM_THM_CALL)
+             {
+               /* If the Thumb BLX instruction is available, convert
+                  the BL to a BLX instruction to call the ARM-mode
+                  PLT entry.  */
+               lower_insn = (lower_insn & ~0x1000) | 0x0800;
+               sym_flags = STT_FUNC;
+             }
+           else
+             {
+               /* Target the Thumb stub before the ARM PLT entry.  */
+               value -= PLT_THUMB_STUB_SIZE;
+               sym_flags = STT_ARM_TFUNC;
+             }
+           *unresolved_reloc_p = FALSE;
+         }
+
        relocation = value + signed_addend;
 
        relocation -= (input_section->output_section->vma
@@ -7547,7 +7660,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bitsize = howto->bitsize;
        if (!thumb2)
          bitsize -= 2;
-       reloc_signed_max = ((1 << (bitsize - 1)) - 1) >> howto->rightshift;
+       reloc_signed_max = (1 << (bitsize - 1)) - 1;
        reloc_signed_min = ~reloc_signed_max;
 
        /* Assumes two's complement.  */
@@ -8742,6 +8855,8 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
   struct elf32_arm_link_hash_table * globals;
 
   globals = elf32_arm_hash_table (info);
+  if (globals == NULL)
+    return FALSE;
 
   symtab_hdr = & elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -9044,9 +9159,9 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
   return TRUE;
 }
 
-/* Add a new unwind edit to the list described by HEAD, TAIL.  If INDEX is zero,
+/* Add a new unwind edit to the list described by HEAD, TAIL.  If TINDEX is zero,
    adds the edit to the start of the list.  (The list must be built in order of
-   ascending INDEX: the function's callers are primarily responsible for
+   ascending TINDEX: the function's callers are primarily responsible for
    maintaining that condition).  */
 
 static void
@@ -9054,16 +9169,16 @@ add_unwind_table_edit (arm_unwind_table_edit **head,
                       arm_unwind_table_edit **tail,
                       arm_unwind_edit_type type,
                       asection *linked_section,
-                      unsigned int index)
+                      unsigned int tindex)
 {
   arm_unwind_table_edit *new_edit = (arm_unwind_table_edit *)
       xmalloc (sizeof (arm_unwind_table_edit));
   
   new_edit->type = type;
   new_edit->linked_section = linked_section;
-  new_edit->index = index;
+  new_edit->index = tindex;
   
-  if (index > 0)
+  if (tindex > 0)
     {
       new_edit->next = NULL;
 
@@ -9125,6 +9240,8 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec)
      2. Duplicate entries are merged together (EXIDX_CANTUNWIND, or unwind
         codes which have been inlined into the index).
 
+   If MERGE_EXIDX_ENTRIES is false, duplicate entries are not merged.
+
    The edits are applied when the tables are written
    (in elf32_arm_write_section).
 */
@@ -9132,7 +9249,8 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec)
 bfd_boolean
 elf32_arm_fix_exidx_coverage (asection **text_section_order,
                              unsigned int num_text_sections,
-                             struct bfd_link_info *info)
+                             struct bfd_link_info *info,
+                             bfd_boolean merge_exidx_entries)
 {
   bfd *inp;
   unsigned int last_second_word = 0, i;
@@ -9173,8 +9291,7 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order,
 
   /* Walk all text sections in order of increasing VMA.  Eilminate duplicate
      index table entries (EXIDX_CANTUNWIND and inlined unwind opcodes),
-     and add EXIDX_CANTUNWIND entries for sections with no unwind table data.
-   */
+     and add EXIDX_CANTUNWIND entries for sections with no unwind table data.  */
 
   for (i = 0; i < num_text_sections; i++)
     {
@@ -9245,7 +9362,8 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order,
          /* Inlined unwinding data.  Merge if equal to previous.  */
          else if ((second_word & 0x80000000) != 0)
            {
-             if (last_second_word == second_word && last_unwind_type == 1)
+             if (merge_exidx_entries
+                  && last_second_word == second_word && last_unwind_type == 1)
                elide = 1;
              unwind_type = 1;
              last_second_word = second_word;
@@ -9313,11 +9431,29 @@ static bfd_boolean
 elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info)
 {
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info);
+  asection *sec, *osec;
+
+  if (globals == NULL)
+    return FALSE;
 
   /* Invoke the regular ELF backend linker to do all the work.  */
   if (!bfd_elf_final_link (abfd, info))
     return FALSE;
 
+  /* Process stub sections (eg BE8 encoding, ...).  */
+  struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
+  int i;
+  for(i=0; i<htab->top_id; i++) {
+    sec = htab->stub_group[i].stub_sec;
+    if (sec) {
+      osec = sec->output_section;
+      elf32_arm_write_section (abfd, info, sec, sec->contents);
+      if (! bfd_set_section_contents (abfd, osec, sec->contents,
+                                     sec->output_offset, sec->size))
+       return FALSE;
+    }
+  }
+
   /* Write out any glue sections now that we have created all the
      stubs.  */
   if (globals->bfd_of_glue_owner != NULL)
@@ -9504,9 +9640,9 @@ elf32_arm_obj_attrs_arg_type (int tag)
 static int
 elf32_arm_obj_attrs_order (int num)
 {
-  if (num == 4)
+  if (num == LEAST_KNOWN_OBJ_ATTRIBUTE)
     return Tag_conformance;
-  if (num == 5)
+  if (num == LEAST_KNOWN_OBJ_ATTRIBUTE + 1)
     return Tag_nodefaults;
   if ((num - 2) < Tag_nodefaults)
     return num - 2;
@@ -9765,11 +9901,33 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
       /* This is the first object.  Copy the attributes.  */
       _bfd_elf_copy_obj_attributes (ibfd, obfd);
 
+      out_attr = elf_known_obj_attributes_proc (obfd);
+
       /* Use the Tag_null value to indicate the attributes have been
         initialized.  */
-      elf_known_obj_attributes_proc (obfd)[0].i = 1;
+      out_attr[0].i = 1;
 
-      return TRUE;
+      /* We do not output objects with Tag_MPextension_use_legacy - we move
+        the attribute's value to Tag_MPextension_use.  */
+      if (out_attr[Tag_MPextension_use_legacy].i != 0)
+       {
+         if (out_attr[Tag_MPextension_use].i != 0
+             && out_attr[Tag_MPextension_use_legacy].i
+               != out_attr[Tag_MPextension_use].i)
+           {
+             _bfd_error_handler
+               (_("Error: %B has both the current and legacy "
+                  "Tag_MPextension_use attributes"), ibfd);
+             result = FALSE;
+           }
+
+         out_attr[Tag_MPextension_use] =
+           out_attr[Tag_MPextension_use_legacy];
+         out_attr[Tag_MPextension_use_legacy].type = 0;
+         out_attr[Tag_MPextension_use_legacy].i = 0;
+       }
+
+      return result;
     }
 
   in_attr = elf_known_obj_attributes_proc (ibfd);
@@ -9784,12 +9942,13 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
        {
          _bfd_error_handler
            (_("error: %B uses VFP register arguments, %B does not"),
-            ibfd, obfd);
+            in_attr[Tag_ABI_VFP_args].i ? ibfd : obfd,
+            in_attr[Tag_ABI_VFP_args].i ? obfd : ibfd);
          result = FALSE;
        }
     }
 
-  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
+  for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
     {
       /* Merge this attribute with existing attributes.  */
       switch (i)
@@ -9873,27 +10032,26 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
        case Tag_ABI_FP_exceptions:
        case Tag_ABI_FP_user_exceptions:
        case Tag_ABI_FP_number_model:
-       case Tag_VFP_HP_extension:
+       case Tag_FP_HP_extension:
        case Tag_CPU_unaligned_access:
        case Tag_T2EE_use:
-       case Tag_Virtualization_use:
        case Tag_MPextension_use:
          /* Use the largest value specified.  */
          if (in_attr[i].i > out_attr[i].i)
            out_attr[i].i = in_attr[i].i;
          break;
 
-       case Tag_ABI_align8_preserved:
+       case Tag_ABI_align_preserved:
        case Tag_ABI_PCS_RO_data:
          /* Use the smallest value specified.  */
          if (in_attr[i].i < out_attr[i].i)
            out_attr[i].i = in_attr[i].i;
          break;
 
-       case Tag_ABI_align8_needed:
+       case Tag_ABI_align_needed:
          if ((in_attr[i].i > 0 || out_attr[i].i > 0)
-             && (in_attr[Tag_ABI_align8_preserved].i == 0
-                 || out_attr[Tag_ABI_align8_preserved].i == 0))
+             && (in_attr[Tag_ABI_align_preserved].i == 0
+                 || out_attr[Tag_ABI_align_preserved].i == 0))
            {
              /* This error message should be enabled once all non-conformant
                 binaries in the toolchain have had the attributes set
@@ -9914,6 +10072,27 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
            out_attr[i].i = in_attr[i].i;
          break;
 
+       case Tag_Virtualization_use:
+         /* The virtualization tag effectively stores two bits of
+            information: the intended use of TrustZone (in bit 0), and the
+            intended use of Virtualization (in bit 1).  */
+         if (out_attr[i].i == 0)
+           out_attr[i].i = in_attr[i].i;
+         else if (in_attr[i].i != 0
+                  && in_attr[i].i != out_attr[i].i)
+           {
+             if (in_attr[i].i <= 3 && out_attr[i].i <= 3)
+               out_attr[i].i = 3;
+             else
+               {
+                 _bfd_error_handler
+                   (_("error: %B: unable to merge virtualization attributes "
+                      "with %B"),
+                    obfd, ibfd);
+                 result = FALSE;
+               }
+           }
+         break;
 
        case Tag_CPU_arch_profile:
          if (out_attr[i].i != in_attr[i].i)
@@ -9941,8 +10120,13 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
                }
            }
          break;
-       case Tag_VFP_arch:
+       case Tag_FP_arch:
            {
+             /* Tag_ABI_HardFP_use is handled along with Tag_FP_arch since
+                the meaning of Tag_ABI_HardFP_use depends on Tag_FP_arch
+                when it's 0.  It might mean absence of FP hardware if
+                Tag_FP_arch is zero, otherwise it is effectively SP + DP.  */
+
              static const struct
              {
                  int ver;
@@ -9961,6 +10145,40 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
              int regs;
              int newval;
 
+             /* If the output has no requirement about FP hardware,
+                follow the requirement of the input.  */
+             if (out_attr[i].i == 0)
+               {
+                 BFD_ASSERT (out_attr[Tag_ABI_HardFP_use].i == 0);
+                 out_attr[i].i = in_attr[i].i;
+                 out_attr[Tag_ABI_HardFP_use].i
+                   = in_attr[Tag_ABI_HardFP_use].i;
+                 break;
+               }
+             /* If the input has no requirement about FP hardware, do
+                nothing.  */
+             else if (in_attr[i].i == 0)
+               {
+                 BFD_ASSERT (in_attr[Tag_ABI_HardFP_use].i == 0);
+                 break;
+               }
+
+             /* Both the input and the output have nonzero Tag_FP_arch.
+                So Tag_ABI_HardFP_use is (SP & DP) when it's zero.  */
+
+             /* If both the input and the output have zero Tag_ABI_HardFP_use,
+                do nothing.  */
+             if (in_attr[Tag_ABI_HardFP_use].i == 0
+                 && out_attr[Tag_ABI_HardFP_use].i == 0)
+               ;
+             /* If the input and the output have different Tag_ABI_HardFP_use,
+                the combination of them is 3 (SP & DP).  */
+             else if (in_attr[Tag_ABI_HardFP_use].i
+                      != out_attr[Tag_ABI_HardFP_use].i)
+               out_attr[Tag_ABI_HardFP_use].i = 3;
+
+             /* Now we can handle Tag_FP_arch.  */
+
              /* Values greater than 6 aren't defined, so just pick the
                 biggest */
              if (in_attr[i].i > 6 && in_attr[i].i > out_attr[i].i)
@@ -10081,12 +10299,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
          /* Merged in target-independent code.  */
          break;
        case Tag_ABI_HardFP_use:
-         /* 1 (SP) and 2 (DP) conflict, so combine to 3 (SP & DP).  */
-         if ((in_attr[i].i == 1 && out_attr[i].i == 2)
-             || (in_attr[i].i == 2 && out_attr[i].i == 1))
-           out_attr[i].i = 3;
-         else if (in_attr[i].i > out_attr[i].i)
-           out_attr[i].i = in_attr[i].i;
+         /* This is handled along with Tag_FP_arch.  */
          break;
        case Tag_ABI_FP_16bit_format:
          if (in_attr[i].i != 0 && out_attr[i].i != 0)
@@ -10103,6 +10316,52 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
            out_attr[i].i = in_attr[i].i;
          break;
 
+       case Tag_DIV_use:
+         /* This tag is set to zero if we can use UDIV and SDIV in Thumb
+            mode on a v7-M or v7-R CPU; to one if we can not use UDIV or
+            SDIV at all; and to two if we can use UDIV or SDIV on a v7-A
+            CPU.  We will merge as follows: If the input attribute's value
+            is one then the output attribute's value remains unchanged.  If
+            the input attribute's value is zero or two then if the output
+            attribute's value is one the output value is set to the input
+            value, otherwise the output value must be the same as the
+            inputs.  */ 
+         if (in_attr[i].i != 1 && out_attr[i].i != 1) 
+           { 
+             if (in_attr[i].i != out_attr[i].i)
+               {
+                 _bfd_error_handler
+                   (_("DIV usage mismatch between %B and %B"),
+                    ibfd, obfd); 
+                 result = FALSE;
+               }
+           } 
+
+         if (in_attr[i].i != 1)
+           out_attr[i].i = in_attr[i].i; 
+         
+         break;
+
+       case Tag_MPextension_use_legacy:
+         /* We don't output objects with Tag_MPextension_use_legacy - we
+            move the value to Tag_MPextension_use.  */
+         if (in_attr[i].i != 0 && in_attr[Tag_MPextension_use].i != 0)
+           {
+             if (in_attr[Tag_MPextension_use].i != in_attr[i].i)
+               {
+                 _bfd_error_handler
+                   (_("%B has has both the current and legacy "
+                      "Tag_MPextension_use attributes"), 
+                    ibfd);
+                 result = FALSE;
+               }
+           }
+
+         if (in_attr[i].i > out_attr[Tag_MPextension_use].i)
+           out_attr[Tag_MPextension_use] = in_attr[i];
+
+         break;
+
        case Tag_nodefaults:
          /* This tag is set if it exists, but the value is unused (and is
             typically zero).  We don't actually need to do anything here -
@@ -10168,7 +10427,8 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, obfd);
+  if (!_bfd_elf_merge_object_attributes (ibfd, obfd))
+    return FALSE;
 
   /* Check for any attributes not known on ARM.  */
   in_list = elf_other_obj_attributes_proc (ibfd);
@@ -10461,6 +10721,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
     return TRUE;
 
   globals = elf32_arm_hash_table (info);
+  if (globals == NULL)
+    return FALSE;
 
   elf_section_data (sec)->local_dynrel = NULL;
 
@@ -10507,7 +10769,7 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
          break;
 
        case R_ARM_TLS_LDM32:
-         elf32_arm_hash_table (info)->tls_ldm_got.refcount -= 1;
+         globals->tls_ldm_got.refcount -= 1;
          break;
 
        case R_ARM_ABS32:
@@ -10592,7 +10854,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
   const Elf_Internal_Rela *rel_end;
   bfd *dynobj;
   asection *sreloc;
-  bfd_vma *local_got_offsets;
   struct elf32_arm_link_hash_table *htab;
   bfd_boolean needs_plt;
   unsigned long nsyms;
@@ -10603,6 +10864,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
   BFD_ASSERT (is_arm_elf (abfd));
 
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   sreloc = NULL;
 
   /* Create dynamic sections for relocatable executables so that we can
@@ -10615,8 +10879,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
     }
 
   dynobj = elf_hash_table (info)->dynobj;
-  local_got_offsets = elf_local_got_offsets (abfd);
-
   symtab_hdr = & elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   nsyms = NUM_SHDR_ENTRIES (symtab_hdr);
@@ -11125,6 +11387,9 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
   struct elf32_arm_link_hash_table *globals;
 
   globals = elf32_arm_hash_table (info);
+  if (globals == NULL)
+    return FALSE;
+
   dynobj = elf_hash_table (info)->dynobj;
 
   /* Make sure we know what is going on here.  */
@@ -11263,6 +11528,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 
   info = (struct bfd_link_info *) inf;
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   if (htab->root.dynamic_sections_created
       && h->plt.refcount > 0)
@@ -11492,7 +11759,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
            }
        }
 
-      if (elf32_arm_hash_table (info)->vxworks_p)
+      if (htab->vxworks_p)
        {
          struct elf32_arm_relocs_copied **pp;
 
@@ -11613,6 +11880,9 @@ bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *info,
   struct elf32_arm_link_hash_table *globals;
 
   globals = elf32_arm_hash_table (info);
+  if (globals == NULL)
+    return;
+
   globals->byteswap_code = byteswap_code;
 }
 
@@ -11630,6 +11900,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   struct elf32_arm_link_hash_table *htab;
 
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
   check_use_blx (htab);
@@ -11656,7 +11929,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
-      bfd_boolean is_vxworks = elf32_arm_hash_table (info)->vxworks_p;
+      bfd_boolean is_vxworks = htab->vxworks_p;
 
       if (! is_arm_elf (ibfd))
        continue;
@@ -11904,6 +12177,9 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd,
 
   dynobj = elf_hash_table (info)->dynobj;
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   eh = (struct elf32_arm_link_hash_entry *) h;
 
   if (h->plt.offset != (bfd_vma) -1)
@@ -12194,20 +12470,23 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
   bfd * dynobj;
   asection * sgot;
   asection * sdyn;
+  struct elf32_arm_link_hash_table *htab;
+
+  htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   dynobj = elf_hash_table (info)->dynobj;
 
   sgot = bfd_get_section_by_name (dynobj, ".got.plt");
-  BFD_ASSERT (elf32_arm_hash_table (info)->symbian_p || sgot != NULL);
+  BFD_ASSERT (htab->symbian_p || sgot != NULL);
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       asection *splt;
       Elf32_External_Dyn *dyncon, *dynconend;
-      struct elf32_arm_link_hash_table *htab;
 
-      htab = elf32_arm_hash_table (info);
       splt = bfd_get_section_by_name (dynobj, ".plt");
       BFD_ASSERT (splt != NULL && sdyn != NULL);
 
@@ -12366,7 +12645,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
        }
 
       /* Fill in the first entry in the procedure linkage table.  */
-      if (splt->size > 0 && elf32_arm_hash_table (info)->plt_header_size)
+      if (splt->size > 0 && htab->plt_header_size)
        {
          const bfd_vma *plt0_entry;
          bfd_vma got_address, plt_address, got_displacement;
@@ -12493,7 +12772,7 @@ elf32_arm_post_process_headers (bfd * abfd, struct bfd_link_info * link_info ATT
   if (link_info)
     {
       globals = elf32_arm_hash_table (link_info);
-      if (globals->byteswap_code)
+      if (globals != NULL && globals->byteswap_code)
        i_ehdrp->e_flags |= EF_ARM_BE8;
     }
 }
@@ -12591,108 +12870,15 @@ elf32_arm_section_from_shdr (bfd *abfd,
   return TRUE;
 }
 
-/* A structure used to record a list of sections, independently
-   of the next and prev fields in the asection structure.  */
-typedef struct section_list
-{
-  asection * sec;
-  struct section_list * next;
-  struct section_list * prev;
-}
-section_list;
-
-/* Unfortunately we need to keep a list of sections for which
-   an _arm_elf_section_data structure has been allocated.  This
-   is because it is possible for functions like elf32_arm_write_section
-   to be called on a section which has had an elf_data_structure
-   allocated for it (and so the used_by_bfd field is valid) but
-   for which the ARM extended version of this structure - the
-   _arm_elf_section_data structure - has not been allocated.  */
-static section_list * sections_with_arm_elf_section_data = NULL;
-
-static void
-record_section_with_arm_elf_section_data (asection * sec)
-{
-  struct section_list * entry;
-
-  entry = (struct section_list *) bfd_malloc (sizeof (* entry));
-  if (entry == NULL)
-    return;
-  entry->sec = sec;
-  entry->next = sections_with_arm_elf_section_data;
-  entry->prev = NULL;
-  if (entry->next != NULL)
-    entry->next->prev = entry;
-  sections_with_arm_elf_section_data = entry;
-}
-
-static struct section_list *
-find_arm_elf_section_entry (asection * sec)
-{
-  struct section_list * entry;
-  static struct section_list * last_entry = NULL;
-
-  /* This is a short cut for the typical case where the sections are added
-     to the sections_with_arm_elf_section_data list in forward order and
-     then looked up here in backwards order.  This makes a real difference
-     to the ld-srec/sec64k.exp linker test.  */
-  entry = sections_with_arm_elf_section_data;
-  if (last_entry != NULL)
-    {
-      if (last_entry->sec == sec)
-       entry = last_entry;
-      else if (last_entry->next != NULL
-              && last_entry->next->sec == sec)
-       entry = last_entry->next;
-    }
-
-  for (; entry; entry = entry->next)
-    if (entry->sec == sec)
-      break;
-
-  if (entry)
-    /* Record the entry prior to this one - it is the entry we are most
-       likely to want to locate next time.  Also this way if we have been
-       called from unrecord_section_with_arm_elf_section_data() we will not
-       be caching a pointer that is about to be freed.  */
-    last_entry = entry->prev;
-
-  return entry;
-}
-
 static _arm_elf_section_data *
 get_arm_elf_section_data (asection * sec)
 {
-  struct section_list * entry;
-
-  entry = find_arm_elf_section_entry (sec);
-
-  if (entry)
-    return elf32_arm_section_data (entry->sec);
+  if (sec && sec->owner && is_arm_elf (sec->owner))
+    return elf32_arm_section_data (sec);
   else
     return NULL;
 }
 
-static void
-unrecord_section_with_arm_elf_section_data (asection * sec)
-{
-  struct section_list * entry;
-
-  entry = find_arm_elf_section_entry (sec);
-
-  if (entry)
-    {
-      if (entry->prev != NULL)
-       entry->prev->next = entry->next;
-      if (entry->next != NULL)
-       entry->next->prev = entry->prev;
-      if (entry == sections_with_arm_elf_section_data)
-       sections_with_arm_elf_section_data = entry->next;
-      free (entry);
-    }
-}
-
-
 typedef struct
 {
   void *finfo;
@@ -12719,10 +12905,8 @@ elf32_arm_output_map_sym (output_arch_syminfo *osi,
                          bfd_vma offset)
 {
   static const char *names[3] = {"$a", "$t", "$d"};
-  struct elf32_arm_link_hash_table *htab;
   Elf_Internal_Sym sym;
 
-  htab = elf32_arm_hash_table (osi->info);
   sym.st_value = osi->sec->output_section->vma
                 + osi->sec->output_offset
                 + offset;
@@ -12730,6 +12914,7 @@ elf32_arm_output_map_sym (output_arch_syminfo *osi,
   sym.st_other = 0;
   sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
   sym.st_shndx = osi->sec_shndx;
+  elf32_arm_section_map_add (osi->sec, names[type][1], offset);
   return osi->func (osi->finfo, names[type], &sym, osi->sec, NULL) == 1;
 }
 
@@ -12744,8 +12929,6 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
   struct elf32_arm_link_hash_entry *eh;
   bfd_vma addr;
 
-  htab = elf32_arm_hash_table (osi->info);
-
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
@@ -12758,6 +12941,10 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
   if (h->plt.offset == (bfd_vma) -1)
     return TRUE;
 
+  htab = elf32_arm_hash_table (osi->info);
+  if (htab == NULL)
+    return FALSE;
+
   eh = (struct elf32_arm_link_hash_entry *) h;
   addr = h->plt.offset;
   if (htab->symbian_p)
@@ -12817,10 +13004,8 @@ static bfd_boolean
 elf32_arm_output_stub_sym (output_arch_syminfo *osi, const char *name,
                           bfd_vma offset, bfd_vma size)
 {
-  struct elf32_arm_link_hash_table *htab;
   Elf_Internal_Sym sym;
 
-  htab = elf32_arm_hash_table (osi->info);
   sym.st_value = osi->sec->output_section->vma
                 + osi->sec->output_offset
                 + offset;
@@ -12836,8 +13021,6 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
                  void * in_arg)
 {
   struct elf32_arm_stub_hash_entry *stub_entry;
-  struct bfd_link_info *info;
-  struct elf32_arm_link_hash_table *htab;
   asection *stub_sec;
   bfd_vma addr;
   char *stub_name;
@@ -12852,9 +13035,6 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
   stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
   osi = (output_arch_syminfo *) in_arg;
 
-  info = osi->info;
-
-  htab = elf32_arm_hash_table (info);
   stub_sec = stub_entry->stub_sec;
 
   /* Ensure this stub is attached to the current section being
@@ -12938,7 +13118,9 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
   return TRUE;
 }
 
-/* Output mapping symbols for linker generated sections.  */
+/* Output mapping symbols for linker generated sections,
+   and for those data-only sections that do not have a
+   $d.  */
 
 static bfd_boolean
 elf32_arm_output_arch_local_syms (bfd *output_bfd,
@@ -12953,14 +13135,47 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
   struct elf32_arm_link_hash_table *htab;
   bfd_vma offset;
   bfd_size_type size;
+  bfd *input_bfd;
 
   htab = elf32_arm_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   check_use_blx (htab);
 
   osi.finfo = finfo;
   osi.info = info;
   osi.func = func;
 
+  /* Add a $d mapping symbol to data-only sections that
+     don't have any mapping symbol.  This may result in (harmless) redundant
+     mapping symbols.  */
+  for (input_bfd = info->input_bfds;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    {
+      if ((input_bfd->flags & (BFD_LINKER_CREATED | HAS_SYMS)) == HAS_SYMS)
+       for (osi.sec = input_bfd->sections;
+            osi.sec != NULL;
+            osi.sec = osi.sec->next)
+         {
+           if (osi.sec->output_section != NULL
+               && ((osi.sec->output_section->flags & (SEC_ALLOC | SEC_CODE))
+                   != 0)
+               && (osi.sec->flags & (SEC_HAS_CONTENTS | SEC_LINKER_CREATED))
+                  == SEC_HAS_CONTENTS
+               && get_arm_elf_section_data (osi.sec) != NULL
+               && get_arm_elf_section_data (osi.sec)->mapcount == 0
+               && osi.sec->size > 0)
+             {
+               osi.sec_shndx = _bfd_elf_section_from_bfd_section
+                 (output_bfd, osi.sec->output_section);
+               if (osi.sec_shndx != (int)SHN_BAD)
+                 elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 0);
+             }
+         }
+    }
+
   /* ARM->Thumb glue.  */
   if (htab->arm_glue_size > 0)
     {
@@ -13085,8 +13300,6 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec)
       sec->used_by_bfd = sdata;
     }
 
-  record_section_with_arm_elf_section_data (sec);
-
   return _bfd_elf_new_section_hook (abfd, sec);
 }
 
@@ -13166,13 +13379,13 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
   bfd_vma veneered_insn_loc, veneer_entry_loc;
   bfd_signed_vma branch_offset;
   bfd *abfd;
-  unsigned int index;
+  unsigned int target;
 
   stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
   data = (struct a8_branch_to_stub_data *) in_arg;
 
   if (stub_entry->target_section != data->writing_section
-      || stub_entry->stub_type < arm_stub_a8_veneer_b_cond)
+      || stub_entry->stub_type < arm_stub_a8_veneer_lwm)
     return TRUE;
 
   contents = data->contents;
@@ -13191,7 +13404,7 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
   branch_offset = veneer_entry_loc - veneered_insn_loc - 4;
 
   abfd = stub_entry->target_section->owner;
-  index = stub_entry->target_value;
+  target = stub_entry->target_value;
 
   /* We attempt to avoid this condition by setting stubs_always_after_branch
      in elf32_arm_size_stubs if we've enabled the Cortex-A8 erratum workaround.
@@ -13252,8 +13465,8 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
       return FALSE;
     }
 
-  bfd_put_16 (abfd, (branch_insn >> 16) & 0xffff, &contents[index]);
-  bfd_put_16 (abfd, branch_insn & 0xffff, &contents[index + 2]);
+  bfd_put_16 (abfd, (branch_insn >> 16) & 0xffff, &contents[target]);
+  bfd_put_16 (abfd, branch_insn & 0xffff, &contents[target + 2]);
 
   return TRUE;
 }
@@ -13278,6 +13491,9 @@ elf32_arm_write_section (bfd *output_bfd,
   bfd_byte tmp;
   unsigned int i;
 
+  if (globals == NULL)
+    return FALSE;
+
   /* If this section has not been allocated an _arm_elf_section_data
      structure then we cannot record anything.  */
   arm_data = get_arm_elf_section_data (sec);
@@ -13295,7 +13511,7 @@ elf32_arm_write_section (bfd *output_bfd,
       for (errnode = arm_data->erratumlist; errnode != 0;
            errnode = errnode->next)
         {
-          bfd_vma index = errnode->vma - offset;
+          bfd_vma target = errnode->vma - offset;
 
           switch (errnode->type)
             {
@@ -13308,7 +13524,7 @@ elf32_arm_write_section (bfd *output_bfd,
                                   | 0x0a000000;
 
                /* The instruction is before the label.  */
-               index -= 4;
+               target -= 4;
 
                /* Above offset included in -4 below.  */
                branch_to_veneer = errnode->u.b.veneer->vma
@@ -13320,10 +13536,10 @@ elf32_arm_write_section (bfd *output_bfd,
                                           "range"), output_bfd);
 
                 insn |= (branch_to_veneer >> 2) & 0xffffff;
-                contents[endianflip ^ index] = insn & 0xff;
-                contents[endianflip ^ (index + 1)] = (insn >> 8) & 0xff;
-                contents[endianflip ^ (index + 2)] = (insn >> 16) & 0xff;
-                contents[endianflip ^ (index + 3)] = (insn >> 24) & 0xff;
+                contents[endianflip ^ target] = insn & 0xff;
+                contents[endianflip ^ (target + 1)] = (insn >> 8) & 0xff;
+                contents[endianflip ^ (target + 2)] = (insn >> 16) & 0xff;
+                contents[endianflip ^ (target + 3)] = (insn >> 24) & 0xff;
               }
               break;
 
@@ -13343,17 +13559,17 @@ elf32_arm_write_section (bfd *output_bfd,
 
                 /* Original instruction.  */
                 insn = errnode->u.v.branch->u.b.vfp_insn;
-                contents[endianflip ^ index] = insn & 0xff;
-                contents[endianflip ^ (index + 1)] = (insn >> 8) & 0xff;
-                contents[endianflip ^ (index + 2)] = (insn >> 16) & 0xff;
-                contents[endianflip ^ (index + 3)] = (insn >> 24) & 0xff;
+                contents[endianflip ^ target] = insn & 0xff;
+                contents[endianflip ^ (target + 1)] = (insn >> 8) & 0xff;
+                contents[endianflip ^ (target + 2)] = (insn >> 16) & 0xff;
+                contents[endianflip ^ (target + 3)] = (insn >> 24) & 0xff;
 
                 /* Branch back to insn after original insn.  */
                 insn = 0xea000000 | ((branch_from_veneer >> 2) & 0xffffff);
-                contents[endianflip ^ (index + 4)] = insn & 0xff;
-                contents[endianflip ^ (index + 5)] = (insn >> 8) & 0xff;
-                contents[endianflip ^ (index + 6)] = (insn >> 16) & 0xff;
-                contents[endianflip ^ (index + 7)] = (insn >> 24) & 0xff;
+                contents[endianflip ^ (target + 4)] = insn & 0xff;
+                contents[endianflip ^ (target + 5)] = (insn >> 8) & 0xff;
+                contents[endianflip ^ (target + 6)] = (insn >> 16) & 0xff;
+                contents[endianflip ^ (target + 7)] = (insn >> 24) & 0xff;
               }
               break;
 
@@ -13514,44 +13730,13 @@ elf32_arm_write_section (bfd *output_bfd,
     }
 
   free (map);
-  arm_data->mapcount = 0;
+  arm_data->mapcount = -1;
   arm_data->mapsize = 0;
   arm_data->map = NULL;
-  unrecord_section_with_arm_elf_section_data (sec);
 
   return FALSE;
 }
 
-static void
-unrecord_section_via_map_over_sections (bfd * abfd ATTRIBUTE_UNUSED,
-                                       asection * sec,
-                                       void * ignore ATTRIBUTE_UNUSED)
-{
-  unrecord_section_with_arm_elf_section_data (sec);
-}
-
-static bfd_boolean
-elf32_arm_close_and_cleanup (bfd * abfd)
-{
-  if (abfd->sections)
-    bfd_map_over_sections (abfd,
-                          unrecord_section_via_map_over_sections,
-                          NULL);
-
-  return _bfd_elf_close_and_cleanup (abfd);
-}
-
-static bfd_boolean
-elf32_arm_bfd_free_cached_info (bfd * abfd)
-{
-  if (abfd->sections)
-    bfd_map_over_sections (abfd,
-                          unrecord_section_via_map_over_sections,
-                          NULL);
-
-  return _bfd_free_cached_info (abfd);
-}
-
 /* Display STT_ARM_TFUNC symbols as functions.  */
 
 static void
@@ -13715,6 +13900,7 @@ const struct elf_size_info elf32_arm_size_info =
 };
 
 #define ELF_ARCH                       bfd_arch_arm
+#define ELF_TARGET_ID                  ARM_ELF_DATA
 #define ELF_MACHINE_CODE               EM_ARM
 #ifdef __QNXTARGET__
 #define ELF_MAXPAGESIZE                        0x1000
@@ -13738,8 +13924,6 @@ const struct elf_size_info elf32_arm_size_info =
 #define bfd_elf32_find_inliner_info            elf32_arm_find_inliner_info
 #define bfd_elf32_new_section_hook             elf32_arm_new_section_hook
 #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol
-#define bfd_elf32_close_and_cleanup             elf32_arm_close_and_cleanup
-#define bfd_elf32_bfd_free_cached_info          elf32_arm_bfd_free_cached_info
 #define bfd_elf32_bfd_final_link               elf32_arm_final_link
 
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
This page took 0.056992 seconds and 4 git commands to generate.