* elflink.c (_bfd_elf_merge_symbol): Revert previous patch.
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index 2a2d4611ab5310c5081c8f7b4be22b8cf1364d1c..b449ee8333164d08bd997360b75c0869ff29570c 100644 (file)
@@ -1,6 +1,6 @@
 /* 32-bit ELF support for ARM
    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008 Free Software Foundation, Inc.
+   2008, 2009  Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -61,8 +61,6 @@
 #define ARM_ELF_ABI_VERSION            0
 #define ARM_ELF_OS_ABI_VERSION         ELFOSABI_ARM
 
-static struct elf_backend_data elf32_arm_vxworks_bed;
-
 static bfd_boolean elf32_arm_write_section (bfd *output_bfd,
                                            struct bfd_link_info *link_info,
                                            asection *sec,
@@ -2228,12 +2226,14 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
 enum elf32_arm_stub_type {
   arm_stub_none,
   DEF_STUBS
+  /* Note the first a8_veneer type */
+  arm_stub_a8_veneer_lwm = arm_stub_a8_veneer_b_cond
 };
 #undef DEF_STUB
 
 typedef struct
 {
-  const insn_sequence* template;
+  const insn_sequence* template_sequence;
   int template_size;
 } stub_def;
 
@@ -2521,6 +2521,17 @@ struct elf32_arm_link_hash_entry
   ((struct elf32_arm_stub_hash_entry *) \
    bfd_hash_lookup ((table), (string), (create), (copy)))
 
+/* Array to keep track of which stub sections have been created, and
+   information on stub grouping.  */
+struct map_stub
+{
+  /* This is the section to which stubs in the group will be
+     attached.  */
+  asection *link_sec;
+  /* The stub section.  */
+  asection *stub_sec;
+};
+
 /* ARM ELF linker hash table.  */
 struct elf32_arm_link_hash_table
 {
@@ -2618,8 +2629,8 @@ struct elf32_arm_link_hash_table
     bfd_vma offset;
   } tls_ldm_got;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_sec_cache sym_sec;
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
 
   /* For convenience in allocate_dynrelocs.  */
   bfd * obfd;
@@ -2636,14 +2647,7 @@ struct elf32_arm_link_hash_table
 
   /* Array to keep track of which stub sections have been created, and
      information on stub grouping.  */
-  struct map_stub
-  {
-    /* This is the section to which stubs in the group will be
-       attached.  */
-    asection *link_sec;
-    /* The stub section.  */
-    asection *stub_sec;
-  } *stub_group;
+  struct map_stub *stub_group;
 
   /* Assorted information used by elf32_arm_size_stubs.  */
   unsigned int bfd_count;
@@ -2664,7 +2668,8 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
   if (ret == NULL)
-    ret = bfd_hash_allocate (table, sizeof (struct elf32_arm_link_hash_entry));
+    ret = (struct elf32_arm_link_hash_entry *)
+        bfd_hash_allocate (table, sizeof (struct elf32_arm_link_hash_entry));
   if (ret == NULL)
     return (struct bfd_hash_entry *) ret;
 
@@ -2698,8 +2703,8 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
      subclass.  */
   if (entry == NULL)
     {
-      entry = bfd_hash_allocate (table,
-                                sizeof (struct elf32_arm_stub_hash_entry));
+      entry = (struct bfd_hash_entry *)
+          bfd_hash_allocate (table, sizeof (struct elf32_arm_stub_hash_entry));
       if (entry == NULL)
        return entry;
     }
@@ -2716,12 +2721,15 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
       eh->stub_offset = 0;
       eh->target_value = 0;
       eh->target_section = NULL;
+      eh->target_addend = 0;
+      eh->orig_insn = 0;
       eh->stub_type = arm_stub_none;
       eh->stub_size = 0;
       eh->stub_template = NULL;
       eh->stub_template_size = 0;
       eh->h = NULL;
       eh->id_sec = NULL;
+      eh->output_name = NULL;
     }
 
   return entry;
@@ -2748,15 +2756,9 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   if (!htab->sgot || !htab->sgotplt)
     abort ();
 
-  htab->srelgot = bfd_make_section_with_flags (dynobj,
-                                              RELOC_SECTION (htab, ".got"),
-                                              (SEC_ALLOC | SEC_LOAD
-                                               | SEC_HAS_CONTENTS
-                                               | SEC_IN_MEMORY
-                                               | SEC_LINKER_CREATED
-                                               | SEC_READONLY));
-  if (htab->srelgot == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
+  htab->srelgot = bfd_get_section_by_name (dynobj,
+                                          RELOC_SECTION (htab, ".got"));
+  if (htab->srelgot == NULL)
     return FALSE;
   return TRUE;
 }
@@ -2883,7 +2885,7 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   struct elf32_arm_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct elf32_arm_link_hash_table);
 
-  ret = bfd_malloc (amt);
+  ret = (struct elf32_arm_link_hash_table *) bfd_malloc (amt);
   if (ret == NULL)
     return NULL;
 
@@ -2927,7 +2929,7 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->vxworks_p = 0;
   ret->symbian_p = 0;
   ret->use_rel = 1;
-  ret->sym_sec.abfd = NULL;
+  ret->sym_cache.abfd = NULL;
   ret->obfd = abfd;
   ret->tls_ldm_got.refcount = 0;
   ret->stub_bfd = NULL;
@@ -2988,6 +2990,26 @@ using_thumb2 (struct elf32_arm_link_hash_table *globals)
   return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7;
 }
 
+/* Determine what kind of NOPs are available.  */
+
+static bfd_boolean
+arch_has_arm_nop (struct elf32_arm_link_hash_table *globals)
+{
+  const int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+                                            Tag_CPU_arch);
+  return arch == TAG_CPU_ARCH_V6T2
+        || arch == TAG_CPU_ARCH_V6K
+        || arch == TAG_CPU_ARCH_V7;
+}
+
+static bfd_boolean
+arch_has_thumb2_nop (struct elf32_arm_link_hash_table *globals)
+{
+  const int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+                                            Tag_CPU_arch);
+  return arch == TAG_CPU_ARCH_V6T2 || arch == TAG_CPU_ARCH_V7;
+}
+
 static bfd_boolean
 arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
 {
@@ -3229,7 +3251,7 @@ elf32_arm_stub_name (const asection *input_section,
   if (hash)
     {
       len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1;
-      stub_name = bfd_malloc (len);
+      stub_name = (char *) bfd_malloc (len);
       if (stub_name != NULL)
        sprintf (stub_name, "%08x_%s+%x",
                 input_section->id & 0xffffffff,
@@ -3239,7 +3261,7 @@ elf32_arm_stub_name (const asection *input_section,
   else
     {
       len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
-      stub_name = bfd_malloc (len);
+      stub_name = (char *) bfd_malloc (len);
       if (stub_name != NULL)
        sprintf (stub_name, "%08x_%x:%x+%x",
                 input_section->id & 0xffffffff,
@@ -3324,7 +3346,7 @@ elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section,
 
          namelen = strlen (link_sec->name);
          len = namelen + sizeof (STUB_SUFFIX);
-         s_name = bfd_alloc (htab->stub_bfd, len);
+         s_name = (char *) bfd_alloc (htab->stub_bfd, len);
          if (s_name == NULL)
            return NULL;
 
@@ -3424,7 +3446,7 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   bfd_vma sym_value;
   int template_size;
   int size;
-  const insn_sequence *template;
+  const insn_sequence *template_sequence;
   int i;
   struct elf32_arm_link_hash_table * globals;
   int stub_reloc_idx[MAXRELOCS] = {-1, -1};
@@ -3440,6 +3462,12 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   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.  */
+    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;
@@ -3455,18 +3483,18 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
               + stub_entry->target_section->output_offset
               + stub_entry->target_section->output_section->vma);
 
-  template = stub_entry->stub_template;
+  template_sequence = stub_entry->stub_template;
   template_size = stub_entry->stub_template_size;
 
   size = 0;
   for (i = 0; i < template_size; i++)
     {
-      switch (template[i].type)
+      switch (template_sequence[i].type)
        {
        case THUMB16_TYPE:
          {
-           bfd_vma data = template[i].data;
-           if (template[i].reloc_addend != 0)
+           bfd_vma data = (bfd_vma) template_sequence[i].data;
+           if (template_sequence[i].reloc_addend != 0)
              {
                 /* We've borrowed the reloc_addend field to mean we should
                    insert a condition code into this (Thumb-1 branch)
@@ -3480,11 +3508,12 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
          break;
 
        case THUMB32_TYPE:
-          put_thumb_insn (globals, stub_bfd, (template[i].data >> 16) & 0xffff,
+          put_thumb_insn (globals, stub_bfd,
+                          (template_sequence[i].data >> 16) & 0xffff,
                           loc + size);
-          put_thumb_insn (globals, stub_bfd, template[i].data & 0xffff,
+          put_thumb_insn (globals, stub_bfd, template_sequence[i].data & 0xffff,
                           loc + size + 2);
-          if (template[i].r_type != R_ARM_NONE)
+          if (template_sequence[i].r_type != R_ARM_NONE)
             {
               stub_reloc_idx[nrelocs] = i;
               stub_reloc_offset[nrelocs++] = size;
@@ -3493,10 +3522,11 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
           break;
 
        case ARM_TYPE:
-         put_arm_insn (globals, stub_bfd, template[i].data, loc + size);
+         put_arm_insn (globals, stub_bfd, template_sequence[i].data,
+                        loc + size);
          /* Handle cases where the target is encoded within the
             instruction.  */
-         if (template[i].r_type == R_ARM_JUMP24)
+         if (template_sequence[i].r_type == R_ARM_JUMP24)
            {
              stub_reloc_idx[nrelocs] = i;
              stub_reloc_offset[nrelocs++] = size;
@@ -3505,7 +3535,7 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
          break;
 
        case DATA_TYPE:
-         bfd_put_32 (stub_bfd, template[i].data, loc + size);
+         bfd_put_32 (stub_bfd, template_sequence[i].data, loc + size);
          stub_reloc_idx[nrelocs] = i;
          stub_reloc_offset[nrelocs++] = size;
          size += 4;
@@ -3532,22 +3562,23 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   BFD_ASSERT (nrelocs != 0 && nrelocs <= MAXRELOCS);
 
   for (i = 0; i < nrelocs; i++)
-    if (template[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP24
-       || template[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP19
-       || template[stub_reloc_idx[i]].r_type == R_ARM_THM_CALL
-       || template[stub_reloc_idx[i]].r_type == R_ARM_THM_XPC22)
+    if (template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP24
+       || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP19
+       || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_CALL
+       || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_XPC22)
       {
        Elf_Internal_Rela rel;
        bfd_boolean unresolved_reloc;
        char *error_message;
        int sym_flags
-         = (template[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22)
+         = (template_sequence[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22)
            ? STT_ARM_TFUNC : 0;
        bfd_vma points_to = sym_value + stub_entry->target_addend;
 
        rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i];
-       rel.r_info = ELF32_R_INFO (0, template[stub_reloc_idx[i]].r_type);
-       rel.r_addend = template[stub_reloc_idx[i]].reloc_addend;
+       rel.r_info = ELF32_R_INFO (0,
+                                   template_sequence[stub_reloc_idx[i]].r_type);
+       rel.r_addend = template_sequence[stub_reloc_idx[i]].reloc_addend;
 
        if (stub_entry->stub_type == arm_stub_a8_veneer_b_cond && i == 0)
          /* The first relocation in the elf32_arm_stub_a8_veneer_b_cond[]
@@ -3555,24 +3586,27 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
             branch.  */
          points_to = sym_value;
 
+       /* There may be unintended consequences if this is not true.  */
+       BFD_ASSERT (stub_entry->h == NULL);
+
        /* Note: _bfd_final_link_relocate doesn't handle these relocations
           properly.  We should probably use this function unconditionally,
           rather than only for certain relocations listed in the enclosing
           conditional, for the sake of consistency.  */
        elf32_arm_final_link_relocate (elf32_arm_howto_from_type
-           (template[stub_reloc_idx[i]].r_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, "", sym_flags,
-         (struct elf_link_hash_entry *) stub_entry, &unresolved_reloc,
+         (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc,
          &error_message);
       }
     else
       {
        _bfd_final_link_relocate (elf32_arm_howto_from_type
-           (template[stub_reloc_idx[i]].r_type), stub_bfd, stub_sec,
+           (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[stub_reloc_idx[i]].reloc_addend);
+         template_sequence[stub_reloc_idx[i]].reloc_addend);
       }
 
   return TRUE;
@@ -3587,17 +3621,17 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type,
                             const insn_sequence **stub_template,
                             int *stub_template_size)
 {
-  const insn_sequence *template = NULL;
+  const insn_sequence *template_sequence = NULL;
   int template_size = 0, i;
   unsigned int size;
 
-  template = stub_definitions[stub_type].template;
+  template_sequence = stub_definitions[stub_type].template_sequence;
   template_size = stub_definitions[stub_type].template_size;
 
   size = 0;
   for (i = 0; i < template_size; i++)
     {
-      switch (template[i].type)
+      switch (template_sequence[i].type)
        {
        case THUMB16_TYPE:
          size += 2;
@@ -3616,7 +3650,7 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type,
     }
 
   if (stub_template)
-    *stub_template = template;
+    *stub_template = template_sequence;
 
   if (stub_template_size)
     *stub_template_size = template_size;
@@ -3633,7 +3667,7 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry,
 {
   struct elf32_arm_stub_hash_entry *stub_entry;
   struct elf32_arm_link_hash_table *htab;
-  const insn_sequence *template;
+  const insn_sequence *template_sequence;
   int template_size, size;
 
   /* Massage our args to the form they really have.  */
@@ -3643,11 +3677,11 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry,
   BFD_ASSERT((stub_entry->stub_type > arm_stub_none)
             && stub_entry->stub_type < ARRAY_SIZE(stub_definitions));
 
-  size = find_stub_size_and_template (stub_entry->stub_type, &template,
+  size = find_stub_size_and_template (stub_entry->stub_type, &template_sequence,
                                      &template_size);
 
   stub_entry->stub_size = size;
-  stub_entry->stub_template = template;
+  stub_entry->stub_template = template_sequence;
   stub_entry->stub_template_size = template_size;
 
   size = (size + 7) & ~7;
@@ -3694,7 +3728,7 @@ elf32_arm_setup_section_lists (bfd *output_bfd,
   htab->bfd_count = bfd_count;
 
   amt = sizeof (struct map_stub) * (top_id + 1);
-  htab->stub_group = bfd_zmalloc (amt);
+  htab->stub_group = (struct map_stub *) bfd_zmalloc (amt);
   if (htab->stub_group == NULL)
     return -1;
 
@@ -3711,7 +3745,7 @@ elf32_arm_setup_section_lists (bfd *output_bfd,
 
   htab->top_index = top_index;
   amt = sizeof (asection *) * (top_index + 1);
-  input_list = bfd_malloc (amt);
+  input_list = (asection **) bfd_malloc (amt);
   htab->input_list = input_list;
   if (input_list == NULL)
     return -1;
@@ -3868,7 +3902,8 @@ group_sections (struct elf32_arm_link_hash_table *htab,
 static int
 a8_reloc_compare (const void *a, const void *b)
 {
-  const struct a8_erratum_reloc *ra = a, *rb = b;
+  const struct a8_erratum_reloc *ra = (const struct a8_erratum_reloc *) a;
+  const struct a8_erratum_reloc *rb = (const struct a8_erratum_reloc *) b;
 
   if (ra->from < rb->from)
     return -1;
@@ -3883,16 +3918,19 @@ static struct elf_link_hash_entry *find_thumb_glue (struct bfd_link_info *,
 
 /* Helper function to scan code for sequences which might trigger the Cortex-A8
    branch/TLB erratum.  Fill in the table described by A8_FIXES_P,
-   NUM_A8_FIXES_P, A8_FIX_TABLE_SIZE_P.  Return 1 if an error occurs, 0
+   NUM_A8_FIXES_P, A8_FIX_TABLE_SIZE_P.  Returns true if an error occurs, false
    otherwise.  */
 
-static int
-cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
+static bfd_boolean
+cortex_a8_erratum_scan (bfd *input_bfd,
+                       struct bfd_link_info *info,
                        struct a8_erratum_fix **a8_fixes_p,
                        unsigned int *num_a8_fixes_p,
                        unsigned int *a8_fix_table_size_p,
                        struct a8_erratum_reloc *a8_relocs,
-                       unsigned int num_a8_relocs)
+                       unsigned int num_a8_relocs,
+                       unsigned prev_num_a8_fixes,
+                       bfd_boolean *stub_changed_p)
 {
   asection *section;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
@@ -3921,7 +3959,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
       if (elf_section_data (section)->this_hdr.contents != NULL)
         contents = elf_section_data (section)->this_hdr.contents;
       else if (! bfd_malloc_and_get_section (input_bfd, section, &contents))
-        return 1;
+        return TRUE;
 
       sec_data = elf32_arm_section_data (section);
 
@@ -3948,9 +3986,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
                * The branch target is in the same 4KB region as the
                  first half of the branch.
                * The instruction before the branch is a 32-bit
-                 length non-branch instruction.
-          */
-
+                 length non-branch instruction.  */
           for (i = span_start; i < span_end;)
             {
               unsigned int insn = bfd_getl16 (&contents[i]);
@@ -3978,10 +4014,13 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
 
              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)
+              if (((base_vma + i) & 0xfff) == 0xffe
+                 && insn_32bit
+                 && is_32bit_branch
+                 && last_was_32bit
+                 && ! last_was_branch)
                 {
-                  bfd_vma offset;
+                  bfd_signed_vma offset;
                   bfd_boolean force_target_arm = FALSE;
                  bfd_boolean force_target_thumb = FALSE;
                   bfd_vma target;
@@ -3989,9 +4028,10 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
                   struct a8_erratum_reloc key, *found;
 
                   key.from = base_vma + i;
-                  found = bsearch (&key, a8_relocs, num_a8_relocs,
-                                   sizeof (struct a8_erratum_reloc),
-                                   &a8_reloc_compare);
+                  found = (struct a8_erratum_reloc *)
+                      bsearch (&key, a8_relocs, num_a8_relocs,
+                               sizeof (struct a8_erratum_reloc),
+                               &a8_reloc_compare);
 
                  if (found)
                    {
@@ -4030,7 +4070,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
                       offset |= (insn & 0x800) ? 0x80000 : 0;
                       offset |= (insn & 0x4000000) ? 0x100000 : 0;
                       if (offset & 0x100000)
-                        offset |= ~0xfffff;
+                        offset |= ~ ((bfd_signed_vma) 0xfffff);
                       stub_type = arm_stub_a8_veneer_b_cond;
                     }
                   else if (is_b || is_bl || is_blx)
@@ -4047,10 +4087,10 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
                       offset |= i1 << 23;
                       offset |= s << 24;
                       if (offset & 0x1000000)
-                        offset |= ~0xffffff;
+                        offset |= ~ ((bfd_signed_vma) 0xffffff);
 
                       if (is_blx)
-                        offset &= ~3u;
+                        offset &= ~ ((bfd_signed_vma) 3);
 
                       stub_type = is_blx ? arm_stub_a8_veneer_blx :
                         is_bl ? arm_stub_a8_veneer_bl : arm_stub_a8_veneer_b;
@@ -4083,14 +4123,15 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
                        }
 
                       if (is_blx)
-                        pc_for_insn &= ~3u;
+                        pc_for_insn &= ~ ((bfd_vma) 3);
 
                       /* If we found a relocation, use the proper destination,
                         not the offset in the (unrelocated) instruction.
                         Note this is always done if we switched the stub type
                         above.  */
                       if (found)
-                        offset = found->destination - pc_for_insn;
+                        offset =
+                         (bfd_signed_vma) (found->destination - pc_for_insn);
 
                       target = pc_for_insn + offset;
 
@@ -4102,19 +4143,39 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
 
                       if (((base_vma + i) & ~0xfff) == (target & ~0xfff))
                         {
-                          char *stub_name;
+                          char *stub_name = NULL;
 
                           if (num_a8_fixes == a8_fix_table_size)
                             {
                               a8_fix_table_size *= 2;
-                              a8_fixes = bfd_realloc (a8_fixes,
-                                sizeof (struct a8_erratum_fix)
-                                * a8_fix_table_size);
+                              a8_fixes = (struct a8_erratum_fix *)
+                                  bfd_realloc (a8_fixes,
+                                               sizeof (struct a8_erratum_fix)
+                                               * a8_fix_table_size);
                             }
 
-                          stub_name = bfd_malloc (8 + 1 + 8 + 1);
-                          if (stub_name != NULL)
-                            sprintf (stub_name, "%x:%x", section->id, i);
+                         if (num_a8_fixes < prev_num_a8_fixes)
+                           {
+                             /* If we're doing a subsequent scan,
+                                check if we've found the same fix as
+                                before, and try and reuse the stub
+                                name.  */
+                             stub_name = a8_fixes[num_a8_fixes].stub_name;
+                             if ((a8_fixes[num_a8_fixes].section != section)
+                                 || (a8_fixes[num_a8_fixes].offset != i))
+                               {
+                                 free (stub_name);
+                                 stub_name = NULL;
+                                 *stub_changed_p = TRUE;
+                               }
+                           }
+
+                         if (!stub_name)
+                           {
+                             stub_name = (char *) bfd_malloc (8 + 1 + 8 + 1);
+                             if (stub_name != NULL)
+                               sprintf (stub_name, "%x:%x", section->id, i);
+                           }
 
                           a8_fixes[num_a8_fixes].input_bfd = input_bfd;
                           a8_fixes[num_a8_fixes].section = section;
@@ -4143,7 +4204,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info,
   *num_a8_fixes_p = num_a8_fixes;
   *a8_fix_table_size_p = a8_fix_table_size;
   
-  return 0;
+  return FALSE;
 }
 
 /* Determine and set the size of the stub section for a final link.
@@ -4162,19 +4223,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
 {
   bfd_size_type stub_group_size;
   bfd_boolean stubs_always_after_branch;
-  bfd_boolean stub_changed = 0;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
-  unsigned int num_a8_fixes = 0, prev_num_a8_fixes = 0, a8_fix_table_size = 10;
+  unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
   struct a8_erratum_reloc *a8_relocs = NULL;
   unsigned int num_a8_relocs = 0, a8_reloc_table_size = 10, i;
 
   if (htab->fix_cortex_a8)
     {
-      a8_fixes = bfd_zmalloc (sizeof (struct a8_erratum_fix)
-                              * a8_fix_table_size);
-      a8_relocs = bfd_zmalloc (sizeof (struct a8_erratum_reloc)
-                               * a8_reloc_table_size);
+      a8_fixes = (struct a8_erratum_fix *)
+          bfd_zmalloc (sizeof (struct a8_erratum_fix) * a8_fix_table_size);
+      a8_relocs = (struct a8_erratum_reloc *)
+          bfd_zmalloc (sizeof (struct a8_erratum_reloc) * a8_reloc_table_size);
     }
 
   /* Propagate mach to stub bfd, because it may not have been
@@ -4215,14 +4275,25 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
   group_sections (htab, stub_group_size, stubs_always_after_branch);
 
+  /* If we're applying the cortex A8 fix, we need to determine the
+     program header size now, because we cannot change it later --
+     that could alter section placements.  Notice the A8 erratum fix
+     ends up requiring the section addresses to remain unchanged
+     modulo the page size.  That's something we cannot represent
+     inside BFD, and we don't want to force the section alignment to
+     be the page size.  */
+  if (htab->fix_cortex_a8)
+    (*htab->layout_sections_again) ();
+
   while (1)
     {
       bfd *input_bfd;
       unsigned int bfd_indx;
       asection *stub_sec;
+      bfd_boolean stub_changed = FALSE;
+      unsigned prev_num_a8_fixes = num_a8_fixes;
 
       num_a8_fixes = 0;
-
       for (input_bfd = info->input_bfds, bfd_indx = 0;
           input_bfd != NULL;
           input_bfd = input_bfd->link_next, bfd_indx++)
@@ -4334,6 +4405,11 @@ elf32_arm_size_stubs (bfd *output_bfd,
                      sym = local_syms + r_indx;
                      hdr = elf_elfsections (input_bfd)[sym->st_shndx];
                      sym_sec = hdr->bfd_section;
+                     if (!sym_sec)
+                       /* 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
@@ -4364,7 +4440,25 @@ elf32_arm_size_stubs (bfd *output_bfd,
                        {
                          sym_sec = hash->root.root.u.def.section;
                          sym_value = hash->root.root.u.def.value;
-                         if (sym_sec->output_section != NULL)
+
+                         struct elf32_arm_link_hash_table *globals =
+                                                 elf32_arm_hash_table (info);
+
+                         /* For a destination in a shared library,
+                            use the PLT stub as target address to
+                            decide whether a branch stub is
+                            needed.  */
+                         if (globals->splt != NULL && hash != NULL
+                             && hash->root.plt.offset != (bfd_vma) -1)
+                           {
+                             sym_sec = globals->splt;
+                             sym_value = hash->root.plt.offset;
+                             if (sym_sec->output_section != NULL)
+                               destination = (sym_value
+                                              + sym_sec->output_offset
+                                              + sym_sec->output_section->vma);
+                           }
+                         else if (sym_sec->output_section != NULL)
                            destination = (sym_value + irela->r_addend
                                           + sym_sec->output_offset
                                           + sym_sec->output_section->vma);
@@ -4431,6 +4525,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
                        {
                          /* The proper stub has already been created.  */
                          free (stub_name);
+                         stub_entry->target_value = sym_value;
                          break;
                        }
 
@@ -4450,8 +4545,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
                       if (sym_name == NULL)
                        sym_name = "unnamed";
-                      stub_entry->output_name
-                       = bfd_alloc (htab->stub_bfd,
+                      stub_entry->output_name = (char *)
+                          bfd_alloc (htab->stub_bfd,
                                      sizeof (THUMB2ARM_GLUE_ENTRY_NAME)
                                      + strlen (sym_name));
                       if (stub_entry->output_name == NULL)
@@ -4502,9 +4597,10 @@ elf32_arm_size_stubs (bfd *output_bfd,
                           if (num_a8_relocs == a8_reloc_table_size)
                             {
                               a8_reloc_table_size *= 2;
-                              a8_relocs = bfd_realloc (a8_relocs,
-                                sizeof (struct a8_erratum_reloc)
-                                * a8_reloc_table_size);
+                              a8_relocs = (struct a8_erratum_reloc *)
+                                  bfd_realloc (a8_relocs,
+                                               sizeof (struct a8_erratum_reloc)
+                                               * a8_reloc_table_size);
                             }
 
                           a8_relocs[num_a8_relocs].from = from;
@@ -4527,18 +4623,21 @@ elf32_arm_size_stubs (bfd *output_bfd,
           if (htab->fix_cortex_a8)
            {
               /* Sort relocs which might apply to Cortex-A8 erratum.  */
-              qsort (a8_relocs, num_a8_relocs, sizeof (struct a8_erratum_reloc),
+              qsort (a8_relocs, num_a8_relocs,
+                    sizeof (struct a8_erratum_reloc),
                      &a8_reloc_compare);
 
               /* Scan for branches which might trigger Cortex-A8 erratum.  */
               if (cortex_a8_erratum_scan (input_bfd, info, &a8_fixes,
                                          &num_a8_fixes, &a8_fix_table_size,
-                                         a8_relocs, num_a8_relocs) != 0)
+                                         a8_relocs, num_a8_relocs,
+                                         prev_num_a8_fixes, &stub_changed)
+                 != 0)
                goto error_ret_free_local;
            }
        }
 
-      if (htab->fix_cortex_a8 && num_a8_fixes != prev_num_a8_fixes)
+      if (prev_num_a8_fixes != num_a8_fixes)
         stub_changed = TRUE;
 
       if (!stub_changed)
@@ -4577,8 +4676,6 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
-      stub_changed = FALSE;
-      prev_num_a8_fixes = num_a8_fixes;
     }
 
   /* Add stubs for Cortex-A8 erratum fixes now.  */
@@ -4592,7 +4689,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
           unsigned int section_id = a8_fixes[i].section->id;
           asection *link_sec = htab->stub_group[section_id].link_sec;
           asection *stub_sec = htab->stub_group[section_id].stub_sec;
-          const insn_sequence *template;
+          const insn_sequence *template_sequence;
           int template_size, size = 0;
 
           stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name,
@@ -4615,11 +4712,12 @@ elf32_arm_size_stubs (bfd *output_bfd,
           stub_entry->orig_insn = a8_fixes[i].orig_insn;
           stub_entry->st_type = STT_ARM_TFUNC;
 
-          size = find_stub_size_and_template (a8_fixes[i].stub_type, &template,
+          size = find_stub_size_and_template (a8_fixes[i].stub_type,
+                                              &template_sequence,
                                               &template_size);
 
           stub_entry->stub_size = size;
-          stub_entry->stub_template = template;
+          stub_entry->stub_template = template_sequence;
           stub_entry->stub_template_size = template_size;
         }
 
@@ -4666,7 +4764,7 @@ elf32_arm_build_stubs (struct bfd_link_info *info)
 
       /* Allocate memory to hold the linker stubs.  */
       size = stub_sec->size;
-      stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
+      stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size);
       if (stub_sec->contents == NULL && size != 0)
        return FALSE;
       stub_sec->size = 0;
@@ -4675,6 +4773,12 @@ elf32_arm_build_stubs (struct bfd_link_info *info)
   /* Build the stubs as directed by the stub hash table.  */
   table = &htab->stub_hash_table;
   bfd_hash_traverse (table, arm_build_one_stub, info);
+  if (htab->fix_cortex_a8)
+    {
+      /* Place the cortex a8 stubs last.  */
+      htab->fix_cortex_a8 = -1;
+      bfd_hash_traverse (table, arm_build_one_stub, info);
+    }
 
   return TRUE;
 }
@@ -4693,8 +4797,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);
 
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
-                        + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
+  tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name)
+                                  + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
 
   BFD_ASSERT (tmp_name);
 
@@ -4727,8 +4831,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);
 
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
-                        + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
+  tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name)
+                                  + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
 
   BFD_ASSERT (tmp_name);
 
@@ -4838,7 +4942,7 @@ arm_allocate_glue_section_space (bfd * abfd, bfd_size_type size, const char * na
   s = bfd_get_section_by_name (abfd, name);
   BFD_ASSERT (s != NULL);
 
-  contents = bfd_alloc (abfd, size);
+  contents = (bfd_byte *) bfd_alloc (abfd, size);
 
   BFD_ASSERT (s->size == size);
   s->contents = contents;
@@ -4897,7 +5001,8 @@ record_arm_to_thumb_glue (struct bfd_link_info * link_info,
 
   BFD_ASSERT (s != NULL);
 
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
+  tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name)
+                                  + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
 
   BFD_ASSERT (tmp_name);
 
@@ -4974,7 +5079,8 @@ record_arm_bx_glue (struct bfd_link_info * link_info, int reg)
   BFD_ASSERT (s != NULL);
 
   /* Add symbol for veneer.  */
-  tmp_name = bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1);
+  tmp_name = (char *)
+      bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1);
 
   BFD_ASSERT (tmp_name);
 
@@ -5011,7 +5117,8 @@ elf32_arm_section_map_add (asection *sec, char type, bfd_vma vma)
 
   if (sec_data->map == NULL)
     {
-      sec_data->map = bfd_malloc (sizeof (elf32_arm_section_map));
+      sec_data->map = (elf32_arm_section_map *)
+          bfd_malloc (sizeof (elf32_arm_section_map));
       sec_data->mapcount = 0;
       sec_data->mapsize = 1;
     }
@@ -5021,8 +5128,9 @@ elf32_arm_section_map_add (asection *sec, char type, bfd_vma vma)
   if (sec_data->mapcount > sec_data->mapsize)
     {
       sec_data->mapsize *= 2;
-      sec_data->map = bfd_realloc_or_free (sec_data->map, sec_data->mapsize
-                                          * sizeof (elf32_arm_section_map));
+      sec_data->map = (elf32_arm_section_map *)
+          bfd_realloc_or_free (sec_data->map, sec_data->mapsize
+                               * sizeof (elf32_arm_section_map));
     }
 
   if (sec_data->map)
@@ -5065,8 +5173,8 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
 
   BFD_ASSERT (s != NULL);
 
-  tmp_name = bfd_malloc ((bfd_size_type) strlen
-                        (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
+  tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen
+                                  (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
 
   BFD_ASSERT (tmp_name);
 
@@ -5090,7 +5198,8 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info,
 
   /* Link veneer back to calling location.  */
   errcount = ++(sec_data->erratumcount);
-  newerr = bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
+  newerr = (elf32_vfp11_erratum_list *)
+      bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
 
   newerr->type = VFP11_ERRATUM_ARM_VENEER;
   newerr->vma = -1;
@@ -5936,8 +6045,8 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
 
               if (state == 3)
                 {
-                  elf32_vfp11_erratum_list *newerr
-                    = bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
+                  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);
@@ -6005,8 +6114,8 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd,
 
   globals = elf32_arm_hash_table (link_info);
 
-  tmp_name = bfd_malloc ((bfd_size_type) strlen
-                          (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
+  tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen
+                                  (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
 
   for (sec = abfd->sections; sec != NULL; sec = sec->next)
     {
@@ -6893,7 +7002,6 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        case R_ARM_PC24:          /* Arm B/BL instruction.  */
        case R_ARM_PLT32:
          {
-         bfd_vma from;
          bfd_signed_vma branch_offset;
          struct elf32_arm_stub_hash_entry *stub_entry = NULL;
 
@@ -6930,6 +7038,8 @@ 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)
@@ -6938,6 +7048,9 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                           + 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;
                }
 
              from = (input_section->output_section->vma
@@ -6998,12 +7111,20 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
          signed_addend >>= howto->rightshift;
 
          /* A branch to an undefined weak symbol is turned into a jump to
-            the next instruction unless a PLT entry will be created.  */
-         if (h && h->root.type == bfd_link_hash_undefweak
-             && !(splt != NULL && h->plt.offset != (bfd_vma) -1))
+            the next instruction unless a PLT entry will be created.
+            Do the same for local undefined symbols.
+            The jump to the next instruction is optimized as a NOP depending
+            on the architecture.  */
+         if (h ? (h->root.type == bfd_link_hash_undefweak
+                  && !(splt != NULL && h->plt.offset != (bfd_vma) -1))
+             : bfd_is_und_section (sym_sec))
            {
-             value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000)
-                     | 0x0affffff;
+             value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000);
+
+             if (arch_has_arm_nop (globals))
+               value |= 0x0320f000;
+             else
+               value |= 0x01a00000; /* Using pre-UAL nop: mov r0, r0.  */
            }
          else
            {
@@ -7163,6 +7284,40 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
         return bfd_reloc_ok;
       }
 
+    case R_ARM_THM_PC8:
+      /* PR 10073:  This reloc is not generated by the GNU toolchain,
+        but it is supported for compatibility with third party libraries
+        generated by other compilers, specifically the ARM/IAR.  */
+      {
+       bfd_vma insn;
+       bfd_signed_vma relocation;
+
+       insn = bfd_get_16 (input_bfd, hit_data);
+
+        if (globals->use_rel)
+         addend = (insn & 0x00ff) << 2;
+
+       relocation = value + addend;
+       relocation -= (input_section->output_section->vma
+                      + input_section->output_offset
+                      + rel->r_offset);
+
+        value = abs (relocation);
+
+       /* We do not check for overflow of this reloc.  Although strictly
+          speaking this is incorrect, it appears to be necessary in order
+          to work with IAR generated relocs.  Since GCC and GAS do not
+          generate R_ARM_THM_PC8 relocs, the lack of a check should not be
+          a problem for them.  */
+       value &= 0x3fc;
+
+       insn = (insn & 0xff00) | (value >> 2);
+
+       bfd_put_16 (input_bfd, insn, hit_data);
+
+        return bfd_reloc_ok;
+      }
+
     case R_ARM_THM_PC12:
       /* Corresponds to: ldr.w reg, [pc, #offset].  */
       {
@@ -7214,15 +7369,25 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_vma check;
        bfd_signed_vma signed_check;
        int bitsize;
-       int thumb2 = using_thumb2 (globals);
+       const int thumb2 = using_thumb2 (globals);
 
        /* A branch to an undefined weak symbol is turned into a jump to
-          the next instruction unless a PLT entry will be created.  */
+          the next instruction unless a PLT entry will be created.
+          The jump to the next instruction is optimized as a NOP.W for
+          Thumb-2 enabled architectures.  */
        if (h && h->root.type == bfd_link_hash_undefweak
            && !(splt != NULL && h->plt.offset != (bfd_vma) -1))
          {
-           bfd_put_16 (input_bfd, 0xe000, hit_data);
-           bfd_put_16 (input_bfd, 0xbf00, hit_data + 2);
+           if (arch_has_thumb2_nop (globals))
+             {
+               bfd_put_16 (input_bfd, 0xf3af, hit_data);
+               bfd_put_16 (input_bfd, 0x8000, hit_data + 2);
+             }
+           else
+             {
+               bfd_put_16 (input_bfd, 0xe000, hit_data);
+               bfd_put_16 (input_bfd, 0xbf00, hit_data + 2);
+             }
            return bfd_reloc_ok;
          }
 
@@ -7302,10 +7467,14 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                /* 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;
+             {
+               /* Target the Thumb stub before the ARM PLT entry.  */
+               value -= PLT_THUMB_STUB_SIZE;
+               sym_flags = STT_ARM_TFUNC;
+             }
            *unresolved_reloc_p = FALSE;
          }
 
@@ -7935,7 +8104,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            (_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"),
             input_bfd, input_section,
             (long) rel->r_offset, howto->name);
-         return FALSE;
+         return (bfd_reloc_status_type) FALSE;
        }
       else
        value = tpoff (info, value);
@@ -8612,6 +8781,25 @@ elf32_arm_relocate_section (bfd *                  output_bfd,
          sym = local_syms + r_symndx;
          sym_type = ELF32_ST_TYPE (sym->st_info);
          sec = local_sections[r_symndx];
+
+         /* An object file might have a reference to a local
+            undefined symbol.  This is a daft object file, but we
+            should at least do something about it.  V4BX & NONE
+            relocations do not use the symbol and are explicitly
+            allowed to use the undefined symbol, so allow those.  */
+         if (r_type != R_ARM_V4BX
+             && r_type != R_ARM_NONE
+             && bfd_is_und_section (sec)
+             && ELF_ST_BIND (sym->st_info) != STB_WEAK)
+           {
+             if (!info->callbacks->undefined_symbol
+                 (info, bfd_elf_string_from_elf_section
+                  (input_bfd, symtab_hdr->sh_link, sym->st_name),
+                  input_bfd, input_section,
+                  rel->r_offset, TRUE))
+               return FALSE;
+           }
+         
          if (globals->use_rel)
            {
              relocation = (sec->output_section->vma
@@ -8866,7 +9054,8 @@ add_unwind_table_edit (arm_unwind_table_edit **head,
                       asection *linked_section,
                       unsigned int index)
 {
-  arm_unwind_table_edit *new_edit = xmalloc (sizeof (arm_unwind_table_edit));
+  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;
@@ -8960,7 +9149,7 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order,
          struct bfd_elf_section_data *elf_sec = elf_section_data (sec);
          Elf_Internal_Shdr *hdr = &elf_sec->this_hdr;
          
-         if (hdr->sh_type != SHT_ARM_EXIDX)
+         if (!hdr || hdr->sh_type != SHT_ARM_EXIDX)
            continue;
          
          if (elf_sec->linked_to)
@@ -9363,7 +9552,7 @@ set_secondary_compatible_arch (bfd *abfd, int arch)
   /* Note: the tag and its argument below are uleb128 values, though
      currently-defined values fit in one byte for each.  */
   if (!attr->s)
-    attr->s = bfd_alloc (abfd, 3);
+    attr->s = (char *) bfd_alloc (abfd, 3);
   attr->s[0] = Tag_CPU_arch;
   attr->s[1] = arch;
   attr->s[2] = '\0';
@@ -10019,301 +10208,83 @@ elf32_arm_versions_compatible (unsigned iver, unsigned over)
    object file when linking.  */
 
 static bfd_boolean
-elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
-{
-  flagword out_flags;
-  flagword in_flags;
-  bfd_boolean flags_compatible = TRUE;
-  asection *sec;
+elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd);
 
-  /* Check if we have the same endianess.  */
-  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
-    return FALSE;
+/* Display the flags field.  */
 
-  if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd))
-    return TRUE;
+static bfd_boolean
+elf32_arm_print_private_bfd_data (bfd *abfd, void * ptr)
+{
+  FILE * file = (FILE *) ptr;
+  unsigned long flags;
 
-  if (!elf32_arm_merge_eabi_attributes (ibfd, obfd))
-    return FALSE;
+  BFD_ASSERT (abfd != NULL && ptr != NULL);
 
-  /* The input BFD must have had its flags initialised.  */
-  /* The following seems bogus to me -- The flags are initialized in
-     the assembler but I don't think an elf_flags_init field is
-     written into the object.  */
-  /* BFD_ASSERT (elf_flags_init (ibfd)); */
+  /* Print normal ELF private data.  */
+  _bfd_elf_print_private_bfd_data (abfd, ptr);
 
-  in_flags  = elf_elfheader (ibfd)->e_flags;
-  out_flags = elf_elfheader (obfd)->e_flags;
+  flags = elf_elfheader (abfd)->e_flags;
+  /* Ignore init flag - it may not be set, despite the flags field
+     containing valid data.  */
 
-  /* In theory there is no reason why we couldn't handle this.  However
-     in practice it isn't even close to working and there is no real
-     reason to want it.  */
-  if (EF_ARM_EABI_VERSION (in_flags) >= EF_ARM_EABI_VER4
-      && !(ibfd->flags & DYNAMIC)
-      && (in_flags & EF_ARM_BE8))
-    {
-      _bfd_error_handler (_("error: %B is already in final BE8 format"),
-                         ibfd);
-      return FALSE;
-    }
+  /* xgettext:c-format */
+  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
 
-  if (!elf_flags_init (obfd))
+  switch (EF_ARM_EABI_VERSION (flags))
     {
-      /* If the input is the default architecture and had the default
-        flags then do not bother setting the flags for the output
-        architecture, instead allow future merges to do this.  If no
-        future merges ever set these flags then they will retain their
-         uninitialised values, which surprise surprise, correspond
-         to the default values.  */
-      if (bfd_get_arch_info (ibfd)->the_default
-         && elf_elfheader (ibfd)->e_flags == 0)
-       return TRUE;
+    case EF_ARM_EABI_UNKNOWN:
+      /* The following flag bits are GNU extensions and not part of the
+        official ARM ELF extended ABI.  Hence they are only decoded if
+        the EABI version is not set.  */
+      if (flags & EF_ARM_INTERWORK)
+       fprintf (file, _(" [interworking enabled]"));
 
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = in_flags;
+      if (flags & EF_ARM_APCS_26)
+       fprintf (file, " [APCS-26]");
+      else
+       fprintf (file, " [APCS-32]");
 
-      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
-         && bfd_get_arch_info (obfd)->the_default)
-       return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
+      if (flags & EF_ARM_VFP_FLOAT)
+       fprintf (file, _(" [VFP float format]"));
+      else if (flags & EF_ARM_MAVERICK_FLOAT)
+       fprintf (file, _(" [Maverick float format]"));
+      else
+       fprintf (file, _(" [FPA float format]"));
 
-      return TRUE;
-    }
+      if (flags & EF_ARM_APCS_FLOAT)
+       fprintf (file, _(" [floats passed in float registers]"));
 
-  /* Determine what should happen if the input ARM architecture
-     does not match the output ARM architecture.  */
-  if (! bfd_arm_merge_machines (ibfd, obfd))
-    return FALSE;
+      if (flags & EF_ARM_PIC)
+       fprintf (file, _(" [position independent]"));
 
-  /* Identical flags must be compatible.  */
-  if (in_flags == out_flags)
-    return TRUE;
+      if (flags & EF_ARM_NEW_ABI)
+       fprintf (file, _(" [new ABI]"));
 
-  /* Check to see if the input BFD actually contains any sections.  If
-     not, its flags may not have been initialised either, but it
-     cannot actually cause any incompatiblity.  Do not short-circuit
-     dynamic objects; their section list may be emptied by
-    elf_link_add_object_symbols.
+      if (flags & EF_ARM_OLD_ABI)
+       fprintf (file, _(" [old ABI]"));
 
-    Also check to see if there are no code sections in the input.
-    In this case there is no need to check for code specific flags.
-    XXX - do we need to worry about floating-point format compatability
-    in data sections ?  */
-  if (!(ibfd->flags & DYNAMIC))
-    {
-      bfd_boolean null_input_bfd = TRUE;
-      bfd_boolean only_data_sections = TRUE;
+      if (flags & EF_ARM_SOFT_FLOAT)
+       fprintf (file, _(" [software FP]"));
 
-      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
-       {
-         /* Ignore synthetic glue sections.  */
-         if (strcmp (sec->name, ".glue_7")
-             && strcmp (sec->name, ".glue_7t"))
-           {
-             if ((bfd_get_section_flags (ibfd, sec)
-                  & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
-                 == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
-               only_data_sections = FALSE;
+      flags &= ~(EF_ARM_INTERWORK | EF_ARM_APCS_26 | EF_ARM_APCS_FLOAT
+                | EF_ARM_PIC | EF_ARM_NEW_ABI | EF_ARM_OLD_ABI
+                | EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT
+                | EF_ARM_MAVERICK_FLOAT);
+      break;
 
-             null_input_bfd = FALSE;
-             break;
-           }
-       }
+    case EF_ARM_EABI_VER1:
+      fprintf (file, _(" [Version1 EABI]"));
 
-      if (null_input_bfd || only_data_sections)
-       return TRUE;
-    }
+      if (flags & EF_ARM_SYMSARESORTED)
+       fprintf (file, _(" [sorted symbol table]"));
+      else
+       fprintf (file, _(" [unsorted symbol table]"));
 
-  /* Complain about various flag mismatches.  */
-  if (!elf32_arm_versions_compatible (EF_ARM_EABI_VERSION (in_flags),
-                                     EF_ARM_EABI_VERSION (out_flags)))
-    {
-      _bfd_error_handler
-       (_("error: Source object %B has EABI version %d, but target %B has EABI version %d"),
-        ibfd, obfd,
-        (in_flags & EF_ARM_EABIMASK) >> 24,
-        (out_flags & EF_ARM_EABIMASK) >> 24);
-      return FALSE;
-    }
+      flags &= ~ EF_ARM_SYMSARESORTED;
+      break;
 
-  /* Not sure what needs to be checked for EABI versions >= 1.  */
-  /* VxWorks libraries do not use these flags.  */
-  if (get_elf_backend_data (obfd) != &elf32_arm_vxworks_bed
-      && get_elf_backend_data (ibfd) != &elf32_arm_vxworks_bed
-      && EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN)
-    {
-      if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26))
-       {
-         _bfd_error_handler
-           (_("error: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"),
-            ibfd, obfd,
-            in_flags & EF_ARM_APCS_26 ? 26 : 32,
-            out_flags & EF_ARM_APCS_26 ? 26 : 32);
-         flags_compatible = FALSE;
-       }
-
-      if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT))
-       {
-         if (in_flags & EF_ARM_APCS_FLOAT)
-           _bfd_error_handler
-             (_("error: %B passes floats in float registers, whereas %B passes them in integer registers"),
-              ibfd, obfd);
-         else
-           _bfd_error_handler
-             (_("error: %B passes floats in integer registers, whereas %B passes them in float registers"),
-              ibfd, obfd);
-
-         flags_compatible = FALSE;
-       }
-
-      if ((in_flags & EF_ARM_VFP_FLOAT) != (out_flags & EF_ARM_VFP_FLOAT))
-       {
-         if (in_flags & EF_ARM_VFP_FLOAT)
-           _bfd_error_handler
-             (_("error: %B uses VFP instructions, whereas %B does not"),
-              ibfd, obfd);
-         else
-           _bfd_error_handler
-             (_("error: %B uses FPA instructions, whereas %B does not"),
-              ibfd, obfd);
-
-         flags_compatible = FALSE;
-       }
-
-      if ((in_flags & EF_ARM_MAVERICK_FLOAT) != (out_flags & EF_ARM_MAVERICK_FLOAT))
-       {
-         if (in_flags & EF_ARM_MAVERICK_FLOAT)
-           _bfd_error_handler
-             (_("error: %B uses Maverick instructions, whereas %B does not"),
-              ibfd, obfd);
-         else
-           _bfd_error_handler
-             (_("error: %B does not use Maverick instructions, whereas %B does"),
-              ibfd, obfd);
-
-         flags_compatible = FALSE;
-       }
-
-#ifdef EF_ARM_SOFT_FLOAT
-      if ((in_flags & EF_ARM_SOFT_FLOAT) != (out_flags & EF_ARM_SOFT_FLOAT))
-       {
-         /* We can allow interworking between code that is VFP format
-            layout, and uses either soft float or integer regs for
-            passing floating point arguments and results.  We already
-            know that the APCS_FLOAT flags match; similarly for VFP
-            flags.  */
-         if ((in_flags & EF_ARM_APCS_FLOAT) != 0
-             || (in_flags & EF_ARM_VFP_FLOAT) == 0)
-           {
-             if (in_flags & EF_ARM_SOFT_FLOAT)
-               _bfd_error_handler
-                 (_("error: %B uses software FP, whereas %B uses hardware FP"),
-                  ibfd, obfd);
-             else
-               _bfd_error_handler
-                 (_("error: %B uses hardware FP, whereas %B uses software FP"),
-                  ibfd, obfd);
-
-             flags_compatible = FALSE;
-           }
-       }
-#endif
-
-      /* Interworking mismatch is only a warning.  */
-      if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK))
-       {
-         if (in_flags & EF_ARM_INTERWORK)
-           {
-             _bfd_error_handler
-               (_("Warning: %B supports interworking, whereas %B does not"),
-                ibfd, obfd);
-           }
-         else
-           {
-             _bfd_error_handler
-               (_("Warning: %B does not support interworking, whereas %B does"),
-                ibfd, obfd);
-           }
-       }
-    }
-
-  return flags_compatible;
-}
-
-/* Display the flags field.  */
-
-static bfd_boolean
-elf32_arm_print_private_bfd_data (bfd *abfd, void * ptr)
-{
-  FILE * file = (FILE *) ptr;
-  unsigned long flags;
-
-  BFD_ASSERT (abfd != NULL && ptr != NULL);
-
-  /* Print normal ELF private data.  */
-  _bfd_elf_print_private_bfd_data (abfd, ptr);
-
-  flags = elf_elfheader (abfd)->e_flags;
-  /* Ignore init flag - it may not be set, despite the flags field
-     containing valid data.  */
-
-  /* xgettext:c-format */
-  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
-
-  switch (EF_ARM_EABI_VERSION (flags))
-    {
-    case EF_ARM_EABI_UNKNOWN:
-      /* The following flag bits are GNU extensions and not part of the
-        official ARM ELF extended ABI.  Hence they are only decoded if
-        the EABI version is not set.  */
-      if (flags & EF_ARM_INTERWORK)
-       fprintf (file, _(" [interworking enabled]"));
-
-      if (flags & EF_ARM_APCS_26)
-       fprintf (file, " [APCS-26]");
-      else
-       fprintf (file, " [APCS-32]");
-
-      if (flags & EF_ARM_VFP_FLOAT)
-       fprintf (file, _(" [VFP float format]"));
-      else if (flags & EF_ARM_MAVERICK_FLOAT)
-       fprintf (file, _(" [Maverick float format]"));
-      else
-       fprintf (file, _(" [FPA float format]"));
-
-      if (flags & EF_ARM_APCS_FLOAT)
-       fprintf (file, _(" [floats passed in float registers]"));
-
-      if (flags & EF_ARM_PIC)
-       fprintf (file, _(" [position independent]"));
-
-      if (flags & EF_ARM_NEW_ABI)
-       fprintf (file, _(" [new ABI]"));
-
-      if (flags & EF_ARM_OLD_ABI)
-       fprintf (file, _(" [old ABI]"));
-
-      if (flags & EF_ARM_SOFT_FLOAT)
-       fprintf (file, _(" [software FP]"));
-
-      flags &= ~(EF_ARM_INTERWORK | EF_ARM_APCS_26 | EF_ARM_APCS_FLOAT
-                | EF_ARM_PIC | EF_ARM_NEW_ABI | EF_ARM_OLD_ABI
-                | EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT
-                | EF_ARM_MAVERICK_FLOAT);
-      break;
-
-    case EF_ARM_EABI_VER1:
-      fprintf (file, _(" [Version1 EABI]"));
-
-      if (flags & EF_ARM_SYMSARESORTED)
-       fprintf (file, _(" [sorted symbol table]"));
-      else
-       fprintf (file, _(" [unsorted symbol table]"));
-
-      flags &= ~ EF_ARM_SYMSARESORTED;
-      break;
-
-    case EF_ARM_EABI_VER2:
-      fprintf (file, _(" [Version2 EABI]"));
+    case EF_ARM_EABI_VER2:
+      fprintf (file, _(" [Version2 EABI]"));
 
       if (flags & EF_ARM_SYMSARESORTED)
        fprintf (file, _(" [sorted symbol table]"));
@@ -10662,7 +10633,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
                      size = symtab_hdr->sh_info;
                      size *= (sizeof (bfd_signed_vma) + sizeof (char));
-                     local_got_refcounts = bfd_zalloc (abfd, size);
+                     local_got_refcounts = (bfd_signed_vma *)
+                          bfd_zalloc (abfd, size);
                      if (local_got_refcounts == NULL)
                        return FALSE;
                      elf_local_got_refcounts (abfd) = local_got_refcounts;
@@ -10839,15 +10811,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    /* Track dynamic relocs needed for local syms too.
                       We really need local syms available to do this
                       easily.  Oh well.  */
-
                    asection *s;
                    void *vpp;
+                   Elf_Internal_Sym *isym;
 
-                   s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                                  sec, r_symndx);
-                   if (s == NULL)
+                   isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                                 abfd, r_symndx);
+                   if (isym == NULL)
                      return FALSE;
 
+                   s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+                   if (s == NULL)
+                     s = sec;
+
                    vpp = &elf_section_data (s)->local_dynrel;
                    head = (struct elf32_arm_relocs_copied **) vpp;
                  }
@@ -10857,7 +10833,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  {
                    bfd_size_type amt = sizeof *p;
 
-                   p = bfd_alloc (htab->root.dynobj, amt);
+                   p = (struct elf32_arm_relocs_copied *)
+                        bfd_alloc (htab->root.dynobj, amt);
                    if (p == NULL)
                      return FALSE;
                    p->next = *head;
@@ -11631,7 +11608,8 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
        {
          struct elf32_arm_relocs_copied *p;
 
-         for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
+         for (p = (struct elf32_arm_relocs_copied *)
+                   elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
              if (!bfd_is_abs_section (p->section)
                  && bfd_is_abs_section (p->section->output_section))
@@ -11785,7 +11763,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
        continue;
 
       /* Allocate memory for the section contents.  */
-      s->contents = bfd_zalloc (dynobj, s->size);
+      s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
        return FALSE;
     }
@@ -12580,7 +12558,7 @@ record_section_with_arm_elf_section_data (asection * sec)
 {
   struct section_list * entry;
 
-  entry = bfd_malloc (sizeof (* entry));
+  entry = (struct section_list *) bfd_malloc (sizeof (* entry));
   if (entry == NULL)
     return;
   entry->sec = sec;
@@ -12807,7 +12785,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
   bfd_vma addr;
   char *stub_name;
   output_arch_syminfo *osi;
-  const insn_sequence *template;
+  const insn_sequence *template_sequence;
   enum stub_insn_type prev_type;
   int size;
   int i;
@@ -12830,8 +12808,8 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
   addr = (bfd_vma) stub_entry->stub_offset;
   stub_name = stub_entry->output_name;
 
-  template = stub_entry->stub_template;
-  switch (template[0].type)
+  template_sequence = stub_entry->stub_template;
+  switch (template_sequence[0].type)
     {
     case ARM_TYPE:
       if (!elf32_arm_output_stub_sym (osi, stub_name, addr, stub_entry->stub_size))
@@ -12852,7 +12830,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
   size = 0;
   for (i = 0; i < stub_entry->stub_template_size; i++)
     {
-      switch (template[i].type)
+      switch (template_sequence[i].type)
        {
        case ARM_TYPE:
          sym_type = ARM_MAP_ARM;
@@ -12872,14 +12850,14 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
          return FALSE;
        }
 
-      if (template[i].type != prev_type)
+      if (template_sequence[i].type != prev_type)
        {
-         prev_type = template[i].type;
+         prev_type = template_sequence[i].type;
          if (!elf32_arm_output_map_sym (osi, sym_type, addr + size))
            return FALSE;
        }
 
-      switch (template[i].type)
+      switch (template_sequence[i].type)
        {
        case ARM_TYPE:
        case THUMB32_TYPE:
@@ -13044,7 +13022,7 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec)
       _arm_elf_section_data *sdata;
       bfd_size_type amt = sizeof (*sdata);
 
-      sdata = bfd_zalloc (abfd, amt);
+      sdata = (_arm_elf_section_data *) bfd_zalloc (abfd, amt);
       if (sdata == NULL)
        return FALSE;
       sec->used_by_bfd = sdata;
@@ -13336,7 +13314,7 @@ elf32_arm_write_section (bfd *output_bfd,
          size (before we merged duplicate entries and inserted EXIDX_CANTUNWIND
         markers) was sec->rawsize.  (This isn't the case if we perform no
         edits, then rawsize will be zero and we should use size).  */
-      bfd_byte *edited_contents = bfd_malloc (sec->size);
+      bfd_byte *edited_contents = (bfd_byte *) bfd_malloc (sec->size);
       unsigned int input_size = sec->rawsize ? sec->rawsize : sec->size;
       unsigned int in_index, out_index;
       bfd_vma add_to_offsets = 0;
@@ -13609,7 +13587,8 @@ elf32_arm_modify_segment_map (bfd *abfd,
        m = m->next;
       if (!m)
        {
-         m = bfd_zalloc (abfd, sizeof (struct elf_segment_map));
+         m = (struct elf_segment_map *)
+              bfd_zalloc (abfd, sizeof (struct elf_segment_map));
          if (m == NULL)
            return FALSE;
          m->p_type = PT_ARM_EXIDX;
@@ -13821,6 +13800,231 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
 #include "elf32-target.h"
 
 
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+
+static bfd_boolean
+elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
+{
+  flagword out_flags;
+  flagword in_flags;
+  bfd_boolean flags_compatible = TRUE;
+  asection *sec;
+
+  /* Check if we have the same endianess.  */
+  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+    return FALSE;
+
+  if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd))
+    return TRUE;
+
+  if (!elf32_arm_merge_eabi_attributes (ibfd, obfd))
+    return FALSE;
+
+  /* The input BFD must have had its flags initialised.  */
+  /* The following seems bogus to me -- The flags are initialized in
+     the assembler but I don't think an elf_flags_init field is
+     written into the object.  */
+  /* BFD_ASSERT (elf_flags_init (ibfd)); */
+
+  in_flags  = elf_elfheader (ibfd)->e_flags;
+  out_flags = elf_elfheader (obfd)->e_flags;
+
+  /* In theory there is no reason why we couldn't handle this.  However
+     in practice it isn't even close to working and there is no real
+     reason to want it.  */
+  if (EF_ARM_EABI_VERSION (in_flags) >= EF_ARM_EABI_VER4
+      && !(ibfd->flags & DYNAMIC)
+      && (in_flags & EF_ARM_BE8))
+    {
+      _bfd_error_handler (_("error: %B is already in final BE8 format"),
+                         ibfd);
+      return FALSE;
+    }
+
+  if (!elf_flags_init (obfd))
+    {
+      /* If the input is the default architecture and had the default
+        flags then do not bother setting the flags for the output
+        architecture, instead allow future merges to do this.  If no
+        future merges ever set these flags then they will retain their
+         uninitialised values, which surprise surprise, correspond
+         to the default values.  */
+      if (bfd_get_arch_info (ibfd)->the_default
+         && elf_elfheader (ibfd)->e_flags == 0)
+       return TRUE;
+
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = in_flags;
+
+      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+         && bfd_get_arch_info (obfd)->the_default)
+       return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
+
+      return TRUE;
+    }
+
+  /* Determine what should happen if the input ARM architecture
+     does not match the output ARM architecture.  */
+  if (! bfd_arm_merge_machines (ibfd, obfd))
+    return FALSE;
+
+  /* Identical flags must be compatible.  */
+  if (in_flags == out_flags)
+    return TRUE;
+
+  /* Check to see if the input BFD actually contains any sections.  If
+     not, its flags may not have been initialised either, but it
+     cannot actually cause any incompatiblity.  Do not short-circuit
+     dynamic objects; their section list may be emptied by
+    elf_link_add_object_symbols.
+
+    Also check to see if there are no code sections in the input.
+    In this case there is no need to check for code specific flags.
+    XXX - do we need to worry about floating-point format compatability
+    in data sections ?  */
+  if (!(ibfd->flags & DYNAMIC))
+    {
+      bfd_boolean null_input_bfd = TRUE;
+      bfd_boolean only_data_sections = TRUE;
+
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       {
+         /* Ignore synthetic glue sections.  */
+         if (strcmp (sec->name, ".glue_7")
+             && strcmp (sec->name, ".glue_7t"))
+           {
+             if ((bfd_get_section_flags (ibfd, sec)
+                  & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
+                 == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
+               only_data_sections = FALSE;
+
+             null_input_bfd = FALSE;
+             break;
+           }
+       }
+
+      if (null_input_bfd || only_data_sections)
+       return TRUE;
+    }
+
+  /* Complain about various flag mismatches.  */
+  if (!elf32_arm_versions_compatible (EF_ARM_EABI_VERSION (in_flags),
+                                     EF_ARM_EABI_VERSION (out_flags)))
+    {
+      _bfd_error_handler
+       (_("error: Source object %B has EABI version %d, but target %B has EABI version %d"),
+        ibfd, obfd,
+        (in_flags & EF_ARM_EABIMASK) >> 24,
+        (out_flags & EF_ARM_EABIMASK) >> 24);
+      return FALSE;
+    }
+
+  /* Not sure what needs to be checked for EABI versions >= 1.  */
+  /* VxWorks libraries do not use these flags.  */
+  if (get_elf_backend_data (obfd) != &elf32_arm_vxworks_bed
+      && get_elf_backend_data (ibfd) != &elf32_arm_vxworks_bed
+      && EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN)
+    {
+      if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26))
+       {
+         _bfd_error_handler
+           (_("error: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"),
+            ibfd, obfd,
+            in_flags & EF_ARM_APCS_26 ? 26 : 32,
+            out_flags & EF_ARM_APCS_26 ? 26 : 32);
+         flags_compatible = FALSE;
+       }
+
+      if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT))
+       {
+         if (in_flags & EF_ARM_APCS_FLOAT)
+           _bfd_error_handler
+             (_("error: %B passes floats in float registers, whereas %B passes them in integer registers"),
+              ibfd, obfd);
+         else
+           _bfd_error_handler
+             (_("error: %B passes floats in integer registers, whereas %B passes them in float registers"),
+              ibfd, obfd);
+
+         flags_compatible = FALSE;
+       }
+
+      if ((in_flags & EF_ARM_VFP_FLOAT) != (out_flags & EF_ARM_VFP_FLOAT))
+       {
+         if (in_flags & EF_ARM_VFP_FLOAT)
+           _bfd_error_handler
+             (_("error: %B uses VFP instructions, whereas %B does not"),
+              ibfd, obfd);
+         else
+           _bfd_error_handler
+             (_("error: %B uses FPA instructions, whereas %B does not"),
+              ibfd, obfd);
+
+         flags_compatible = FALSE;
+       }
+
+      if ((in_flags & EF_ARM_MAVERICK_FLOAT) != (out_flags & EF_ARM_MAVERICK_FLOAT))
+       {
+         if (in_flags & EF_ARM_MAVERICK_FLOAT)
+           _bfd_error_handler
+             (_("error: %B uses Maverick instructions, whereas %B does not"),
+              ibfd, obfd);
+         else
+           _bfd_error_handler
+             (_("error: %B does not use Maverick instructions, whereas %B does"),
+              ibfd, obfd);
+
+         flags_compatible = FALSE;
+       }
+
+#ifdef EF_ARM_SOFT_FLOAT
+      if ((in_flags & EF_ARM_SOFT_FLOAT) != (out_flags & EF_ARM_SOFT_FLOAT))
+       {
+         /* We can allow interworking between code that is VFP format
+            layout, and uses either soft float or integer regs for
+            passing floating point arguments and results.  We already
+            know that the APCS_FLOAT flags match; similarly for VFP
+            flags.  */
+         if ((in_flags & EF_ARM_APCS_FLOAT) != 0
+             || (in_flags & EF_ARM_VFP_FLOAT) == 0)
+           {
+             if (in_flags & EF_ARM_SOFT_FLOAT)
+               _bfd_error_handler
+                 (_("error: %B uses software FP, whereas %B uses hardware FP"),
+                  ibfd, obfd);
+             else
+               _bfd_error_handler
+                 (_("error: %B uses hardware FP, whereas %B uses software FP"),
+                  ibfd, obfd);
+
+             flags_compatible = FALSE;
+           }
+       }
+#endif
+
+      /* Interworking mismatch is only a warning.  */
+      if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK))
+       {
+         if (in_flags & EF_ARM_INTERWORK)
+           {
+             _bfd_error_handler
+               (_("Warning: %B supports interworking, whereas %B does not"),
+                ibfd, obfd);
+           }
+         else
+           {
+             _bfd_error_handler
+               (_("Warning: %B does not support interworking, whereas %B does"),
+                ibfd, obfd);
+           }
+       }
+    }
+
+  return flags_compatible;
+}
+
+
 /* Symbian OS Targets.  */
 
 #undef  TARGET_LITTLE_SYM
This page took 0.052186 seconds and 4 git commands to generate.