This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, ARM] Work around Cortex-A8 erratum in linker


Hi,

This patch contains a workaround for an erratum in ARM Cortex-A8
processors. The (position-dependent) nature of the erratum is such that
it is necessary to interoperate with the relaxation pass performed at
the end of linking which inserts long branch/interworking stubs.

The erratum (657417: A 32-bit branch instruction that spans two 4K
regions can result in an incorrect operation) affects only Thumb-2
code.  The method used to work around the problem is to insert a stub
(in a different page) and branch to that, then have the stub jump back
to the original destination.

The workaround is enabled by default if the link targets the ARMv7 (-A
or unspecified) architecture. It can be enabled otherwise by passing
--fix-cortex-a8 to the linker, or disabled unconditionally by passing
--no-fix-cortex-a8.

Tested with cross to arm-linux-gnueabi, with new test cases. OK to
apply?

Thanks,

Julian

ChangeLog

    ld/
    * emultempl/armelf.em (fix_cortex_a8): New.
    (arm_elf_before_allocation): Call bfd_elf32_arm_set_cortex_a8_fix.
    (arm_elf_create_output_section_statements): Add fix_cortex_a8 to
    bfd_elf32_arm_set_target_relocs.
    (OPTION_FIX_CORTEX_A8, OPTION_NO_FIX_CORTEX_A8): New.
    (PARSE_AND_LIST_LONGOPTS): Add [no-]fix-cortex-a8 options.
    (PARSE_AND_LIST_OPTIONS): Add [no-]fix-cortex-a8 options.
    (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_[NO_]FIX_CORTEX_A8.
    * ld.texinfo (--[no-]fix-cortex-a8): Briefly document new options.

    bfd/
    * elf32-arm.c (THUMB16_BCOND_INSN, THUMB32_INSN, THUMB32_B_INSN):
    New macros.
    (elf32_arm_stub_a8_veneer_b_cond, elf32_arm_stub_a8_veneer_b)
    (elf32_arm_stub_a8_veneer_blx): New stub sequences.
    (elf32_arm_stub_type): Add arm_stub_a8_veneer_b_cond,
    arm_stub_a8_veneer_b and arm_stub_a8_veneer_blx.
    (elf32_arm_stub_hash_entry): Add target_addend, orig_insn fields.
    (a8_erratum_fix, a8_erratum_reloc): New structs.
    (elf32_arm_link_hash_table): Add a8_erratum_fixes,
    num_a8_erratum_fixes, fix_cortex_a8 fields.
    (elf32_arm_link_hash_table_create): Zero fix_cortex_a8.
    (elf32_arm_add_stub): Split into two parts, creating...
    (elf32_arm_create_or_find_stub_sec): New function.
    (elf32_arm_final_link_relocate): Add forward declaration.
    (arm_build_one_stub): Add support for THUMB32_TYPE, Thumb-2
    relocations, multiple relocations per stub.
    (find_stub_size_and_template): New (using parts of
    arm_size_one_stub).
    (arm_size_one_stub): Use find_stub_size_and_template.
    (a8_reloc_compare): New.
    (find_thumb_glue): Add forward declaration.
    (cortex_a8_erratum_scan): New.
    (elf32_arm_size_stubs): Add Cortex-A8 erratum workaround support.
    (bfd_elf32_arm_set_cortex_a8_fix): New.
    (bfd_elf32_arm_set_target_relocs): Add fix_cortex_a8 argument.
    (arm_map_one_stub): Add THUMB32_TYPE support.
    (a8_branch_to_stub_data): New.
    (make_branch_to_a8_stub): New.
    (elf32_arm_write_section): Add Cortex-A8 erratum workaround support.
    * bfd-in.h (bfd_elf32_arm_set_cortex_a8_fix): New.
    (bfd_elf32_arm_set_target_relocs): Add argument for controlling
    Cortex-A8 erratum workaround.
    * bfd-in2.h: Regenerate.

    ld/testsuite/
    * ld-arm/cortex-a8-arm-target.s: New.
    * ld-arm/cortex-a8-thumb-target.s: New.
    * ld-arm/cortex-a8-fix-b-rel.s: New.
    * ld-arm/cortex-a8-fix-b-rel-arm.d: New.
    * ld-arm/cortex-a8-fix-b-rel-thumb.d: New.
    * ld-arm/cortex-a8-fix-b.s: New.
    * ld-arm/cortex-a8-fix-b.d: New.
    * ld-arm/cortex-a8-fix-bl-rel.s: New.
    * ld-arm/cortex-a8-fix-bl-rel-arm.d: New.
    * ld-arm/cortex-a8-fix-bl-rel-thumb.d: New.
    * ld-arm/cortex-a8-fix-bl.s: New.
    * ld-arm/cortex-a8-fix-bl.d: New.
    * ld-arm/cortex-a8-fix-bcc-rel.s: New.
    * ld-arm/cortex-a8-fix-bcc-rel-thumb.d: New.
    * ld-arm/cortex-a8-fix-bcc.s: New.
    * ld-arm/cortex-a8-fix-bcc.d: New.
    * ld-arm/cortex-a8-fix-blx-rel.s: New.
    * ld-arm/cortex-a8-fix-blx-rel-arm.d: New.
    * ld-arm/cortex-a8-fix-blx-rel-thumb.d: New.
    * ld-arm/cortex-a8-fix-blx.s: New.
    * ld-arm/cortex-a8-fix-blx.d: New.
    * ld-arm/arm-elf.exp: Add new tests.
--- .pc/cortex-a8-fix-3/bfd/bfd-in.h	2009-05-01 03:22:19.000000000 -0700
+++ bfd/bfd-in.h	2009-05-01 03:45:22.000000000 -0700
@@ -825,6 +825,9 @@ extern void bfd_elf32_arm_init_maps
 extern void bfd_elf32_arm_set_vfp11_fix
   (bfd *, struct bfd_link_info *);
 
+extern void bfd_elf32_arm_set_cortex_a8_fix
+  (bfd *, struct bfd_link_info *);
+
 extern bfd_boolean bfd_elf32_arm_vfp11_erratum_scan
   (bfd *, struct bfd_link_info *);
 
@@ -860,7 +863,7 @@ extern bfd_boolean bfd_elf32_arm_process
 
 void bfd_elf32_arm_set_target_relocs
   (bfd *, struct bfd_link_info *, int, char *, int, int, bfd_arm_vfp11_fix,
-   int, int, int);
+   int, int, int, int);
 
 extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking
   (bfd *, struct bfd_link_info *);
--- .pc/cortex-a8-fix-3/bfd/bfd-in2.h	2009-05-01 03:22:19.000000000 -0700
+++ bfd/bfd-in2.h	2009-05-01 03:45:22.000000000 -0700
@@ -832,6 +832,9 @@ extern void bfd_elf32_arm_init_maps
 extern void bfd_elf32_arm_set_vfp11_fix
   (bfd *, struct bfd_link_info *);
 
+extern void bfd_elf32_arm_set_cortex_a8_fix
+  (bfd *, struct bfd_link_info *);
+
 extern bfd_boolean bfd_elf32_arm_vfp11_erratum_scan
   (bfd *, struct bfd_link_info *);
 
@@ -867,7 +870,7 @@ extern bfd_boolean bfd_elf32_arm_process
 
 void bfd_elf32_arm_set_target_relocs
   (bfd *, struct bfd_link_info *, int, char *, int, int, bfd_arm_vfp11_fix,
-   int, int, int);
+   int, int, int, int);
 
 extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking
   (bfd *, struct bfd_link_info *);
--- .pc/cortex-a8-fix-3/bfd/elf32-arm.c	2009-05-01 03:22:19.000000000 -0700
+++ bfd/elf32-arm.c	2009-05-01 04:09:44.000000000 -0700
@@ -2024,11 +2024,15 @@ enum stub_insn_type
     DATA_TYPE
   };
 
-#define THUMB16_INSN(X)    {(X), THUMB16_TYPE, R_ARM_NONE, 0}
-#define THUMB32_INSN(X)    {(X), THUMB32_TYPE, R_ARM_NONE, 0}
-#define ARM_INSN(X)        {(X), ARM_TYPE, R_ARM_NONE, 0}
-#define ARM_REL_INSN(X, Z) {(X), ARM_TYPE, R_ARM_JUMP24, (Z)}
-#define DATA_WORD(X,Y,Z)   {(X), DATA_TYPE, (Y), (Z)}
+#define THUMB16_INSN(X)		{(X), THUMB16_TYPE, R_ARM_NONE, 0}
+/* A bit of a hack.  A Thumb conditional branch, in which the proper condition
+   is inserted in arm_build_one_stub().  */
+#define THUMB16_BCOND_INSN(X)	{(X), THUMB16_TYPE, R_ARM_NONE, 1}
+#define THUMB32_INSN(X)		{(X), THUMB32_TYPE, R_ARM_NONE, 0}
+#define THUMB32_B_INSN(X, Z)	{(X), THUMB32_TYPE, R_ARM_THM_JUMP24, (Z)}
+#define ARM_INSN(X)		{(X), ARM_TYPE, R_ARM_NONE, 0}
+#define ARM_REL_INSN(X, Z)	{(X), ARM_TYPE, R_ARM_JUMP24, (Z)}
+#define DATA_WORD(X,Y,Z)	{(X), DATA_TYPE, (Y), (Z)}
 
 typedef struct
 {
@@ -2162,6 +2166,34 @@ static const insn_sequence elf32_arm_stu
     DATA_WORD(0, R_ARM_REL32, 0),     /* dcd  R_ARM_REL32(X) */
   };
 
+/* Cortex-A8 erratum-workaround stubs.  */
+
+/* Stub used for conditional branches (which may be beyond +/-1MB away, so we
+   can't use a conditional branch to reach this stub).  */
+
+static const insn_sequence elf32_arm_stub_a8_veneer_b_cond[] =
+  {
+    THUMB16_BCOND_INSN(0xd001),         /* b<cond>.n true.  */
+    THUMB32_B_INSN(0xf000b800, -4),     /* b.w insn_after_original_branch.  */
+    THUMB32_B_INSN(0xf000b800, -4)      /* true: b.w original_branch_dest.  */
+  };
+
+/* Stub used for b.w and bl.w instructions.  */
+
+static const insn_sequence elf32_arm_stub_a8_veneer_b[] =
+  {
+    THUMB32_B_INSN(0xf000b800, -4)	/* b.w original_branch_dest.  */
+  };
+
+/* Stub used for Thumb-2 blx.w instructions.  We modified the original blx.w
+   instruction (which switches to ARM mode) to point to this stub.  Jump to the
+   real destination using an ARM-mode branch.  */
+
+static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
+  {
+    ARM_REL_INSN(0xea000000, -8)	/* b original_branch_dest.  */
+  };
+
 /* Section name for stubs is the associated section name plus this
    string.  */
 #define STUB_SUFFIX ".stub"
@@ -2181,6 +2213,10 @@ enum elf32_arm_stub_type
   arm_stub_long_branch_v4t_thumb_arm_pic,
   arm_stub_long_branch_thumb_only_pic,
   arm_stub_long_branch_v4t_thumb_thumb_pic,
+  arm_stub_a8_veneer_b_cond,
+  arm_stub_a8_veneer_b,
+  arm_stub_a8_veneer_bl,
+  arm_stub_a8_veneer_blx
 };
 
 struct elf32_arm_stub_hash_entry
@@ -2199,6 +2235,13 @@ struct elf32_arm_stub_hash_entry
   bfd_vma target_value;
   asection *target_section;
 
+  /* Offset to apply to relocation referencing target_value.  */
+  bfd_vma target_addend;
+
+  /* The instruction which caused this stub to be generated (only valid for
+     Cortex-A8 erratum workaround stubs at present).  */
+  unsigned long orig_insn;
+
   /* The stub type.  */
   enum elf32_arm_stub_type stub_type;
   /* Its encoding size in bytes.  */
@@ -2280,6 +2323,34 @@ _arm_elf_section_data;
 #define elf32_arm_section_data(sec) \
   ((_arm_elf_section_data *) elf_section_data (sec))
 
+/* A fix which might be required for Cortex-A8 Thumb-2 branch/TLB erratum.
+   These fixes are subject to a relaxation procedure (in elf32_arm_size_stubs),
+   so may be created multiple times: we use an array of these entries whilst
+   relaxing which we can refresh easily, then create stubs for each potentially
+   erratum-triggering instruction once we've settled on a solution.  */
+
+struct a8_erratum_fix {
+  bfd *input_bfd;
+  asection *section;
+  bfd_vma offset;
+  bfd_vma addend;
+  unsigned long orig_insn;
+  char *stub_name;
+  enum elf32_arm_stub_type stub_type;
+};
+
+/* A table of relocs applied to branches which might trigger Cortex-A8
+   erratum.  */
+
+struct a8_erratum_reloc {
+  bfd_vma from;
+  bfd_vma destination;
+  unsigned int r_type;
+  unsigned char st_type;
+  const char *sym_name;
+  bfd_boolean non_a8_stub;
+};
+
 /* The size of the thread control block.  */
 #define TCB_SIZE	8
 
@@ -2411,6 +2482,12 @@ struct elf32_arm_link_hash_table
      veneers.  */
   bfd_size_type vfp11_erratum_glue_size;
 
+  /* A table of fix locations for Cortex-A8 Thumb-2 branch/TLB erratum.  This
+     holds Cortex-A8 erratum fix locations between elf32_arm_size_stubs() and
+     elf32_arm_write_section().  */
+  struct a8_erratum_fix *a8_erratum_fixes;
+  unsigned int num_a8_erratum_fixes;
+
   /* An arbitrary input BFD chosen to hold the glue sections.  */
   bfd * bfd_of_glue_owner;
 
@@ -2429,6 +2506,9 @@ struct elf32_arm_link_hash_table
      2 = Generate v4 interworing stubs.  */
   int fix_v4bx;
 
+  /* Whether we should fix the Cortex-A8 Thumb-2 branch/TLB erratum.  */
+  int fix_cortex_a8;
+
   /* Nonzero if the ARM/Thumb BLX instructions are available for use.  */
   int use_blx;
 
@@ -2768,6 +2848,7 @@ elf32_arm_link_hash_table_create (bfd *a
   ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE;
   ret->vfp11_erratum_glue_size = 0;
   ret->num_vfp11_fixes = 0;
+  ret->fix_cortex_a8 = 0;
   ret->bfd_of_glue_owner = NULL;
   ret->byteswap_code = 0;
   ret->target1_is_rel = 0;
@@ -3157,17 +3238,16 @@ elf32_arm_get_stub_entry (const asection
   return stub_entry;
 }
 
-/* Add a new stub entry to the stub hash.  Not all fields of the new
-   stub entry are initialised.  */
+/* Find or create a stub section.  Returns a pointer to the stub section, and
+   the section to which the stub section will be attached (in *LINK_SEC_P). 
+   LINK_SEC_P may be NULL.  */
 
-static struct elf32_arm_stub_hash_entry *
-elf32_arm_add_stub (const char *stub_name,
-		    asection *section,
-		    struct elf32_arm_link_hash_table *htab)
+static asection *
+elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section,
+				   struct elf32_arm_link_hash_table *htab)
 {
   asection *link_sec;
   asection *stub_sec;
-  struct elf32_arm_stub_hash_entry *stub_entry;
 
   link_sec = htab->stub_group[section->id].link_sec;
   stub_sec = htab->stub_group[section->id].stub_sec;
@@ -3195,6 +3275,28 @@ elf32_arm_add_stub (const char *stub_nam
 	}
       htab->stub_group[section->id].stub_sec = stub_sec;
     }
+  
+  if (link_sec_p)
+    *link_sec_p = link_sec;
+  
+  return stub_sec;
+}
+
+/* Add a new stub entry to the stub hash.  Not all fields of the new
+   stub entry are initialised.  */
+
+static struct elf32_arm_stub_hash_entry *
+elf32_arm_add_stub (const char *stub_name,
+		    asection *section,
+		    struct elf32_arm_link_hash_table *htab)
+{
+  asection *link_sec;
+  asection *stub_sec;
+  struct elf32_arm_stub_hash_entry *stub_entry;
+
+  stub_sec = elf32_arm_create_or_find_stub_sec (&link_sec, section, htab);
+  if (stub_sec == NULL)
+    return NULL;
 
   /* Enter this entry into the linker stub hash table.  */
   stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name,
@@ -3240,10 +3342,16 @@ put_thumb_insn (struct elf32_arm_link_ha
     bfd_putb16 (val, ptr);
 }
 
+static bfd_reloc_status_type elf32_arm_final_link_relocate
+  (reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *,
+   Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *,
+   const char *, int, struct elf_link_hash_entry *, bfd_boolean *, char **);
+
 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 bfd_link_info *info;
   struct elf32_arm_link_hash_table *htab;
@@ -3257,8 +3365,9 @@ arm_build_one_stub (struct bfd_hash_entr
   const insn_sequence *template;
   int i;
   struct elf32_arm_link_hash_table * globals;
-  int stub_reloc_idx = -1;
-  int stub_reloc_offset = 0;
+  int stub_reloc_idx[MAXRELOCS] = {-1, -1};
+  int stub_reloc_offset[MAXRELOCS] = {0, 0};
+  int nrelocs = 0;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
@@ -3293,26 +3402,51 @@ arm_build_one_stub (struct bfd_hash_entr
       switch (template[i].type)
 	{
 	case THUMB16_TYPE:
-	  put_thumb_insn (globals, stub_bfd, template[i].data, loc + size);
-	  size += 2;
+	  {
+	    bfd_vma data = template[i].data;
+	    if (template[i].reloc_addend != 0)
+	      {
+                /* We've borrowed the reloc_addend field to mean we should
+                   insert a condition code into this (Thumb-1 branch)
+                   instruction.  See THUMB16_BCOND_INSN.  */
+                BFD_ASSERT ((data & 0xff00) == 0xd000);
+                data |= ((stub_entry->orig_insn >> 22) & 0xf) << 8;
+	      }
+	    put_thumb_insn (globals, stub_bfd, data, loc + size);
+	    size += 2;
+	  }
 	  break;
 
+	case THUMB32_TYPE:
+          put_thumb_insn (globals, stub_bfd, (template[i].data >> 16) & 0xffff,
+                          loc + size);
+          put_thumb_insn (globals, stub_bfd, template[i].data & 0xffff,
+                          loc + size + 2);
+          if (template[i].r_type != R_ARM_NONE)
+            {
+              stub_reloc_idx[nrelocs] = i;
+              stub_reloc_offset[nrelocs++] = size;
+            }
+          size += 4;
+          break;
+
+
 	case ARM_TYPE:
 	  put_arm_insn (globals, stub_bfd, template[i].data, loc + size);
 	  /* Handle cases where the target is encoded within the
 	     instruction.  */
 	  if (template[i].r_type == R_ARM_JUMP24)
 	    {
-	      stub_reloc_idx = i;
-	      stub_reloc_offset = size;
+	      stub_reloc_idx[nrelocs] = i;
+	      stub_reloc_offset[nrelocs++] = size;
 	    }
 	  size += 4;
 	  break;
 
 	case DATA_TYPE:
 	  bfd_put_32 (stub_bfd, template[i].data, loc + size);
-	  stub_reloc_idx = i;
-	  stub_reloc_offset = size;
+	  stub_reloc_idx[nrelocs] = i;
+	  stub_reloc_offset[nrelocs++] = size;
 	  size += 4;
 	  break;
 
@@ -3332,36 +3466,71 @@ arm_build_one_stub (struct bfd_hash_entr
   if (stub_entry->st_type == STT_ARM_TFUNC)
     sym_value |= 1;
 
-  /* Assume there is one and only one entry to relocate in each stub.  */
-  BFD_ASSERT (stub_reloc_idx != -1);
+  /* Assume there is at least one and at most MAXRELOCS entries to relocate
+     in each stub.  */
+  BFD_ASSERT (nrelocs != 0 && nrelocs <= MAXRELOCS);
 
-  _bfd_final_link_relocate (elf32_arm_howto_from_type (template[stub_reloc_idx].r_type),
-			    stub_bfd, stub_sec, stub_sec->contents,
-			    stub_entry->stub_offset + stub_reloc_offset,
-			    sym_value, template[stub_reloc_idx].reloc_addend);
+  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)
+      {
+	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)
+	    ? 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;
+
+	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[]
+	     template should refer back to the instruction after the original
+	     branch.  */
+	  points_to = sym_value;
+
+	/* 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),
+	  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,
+	  &error_message);
+      }
+    else
+      {
+	_bfd_final_link_relocate (elf32_arm_howto_from_type
+	    (template[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);
+      }
 
   return TRUE;
+#undef MAXRELOCS
 }
 
-/* As above, but don't actually build the stub.  Just bump offset so
-   we know stub section sizes.  */
+/* Calculate the template, template size and instruction size for a stub.
+   Return value is the instruction size.  */
 
-static bfd_boolean
-arm_size_one_stub (struct bfd_hash_entry *gen_entry,
-		   void * in_arg)
+static unsigned int
+find_stub_size_and_template (enum elf32_arm_stub_type stub_type,
+			     const insn_sequence **stub_template,
+			     int *stub_template_size)
 {
-  struct elf32_arm_stub_hash_entry *stub_entry;
-  struct elf32_arm_link_hash_table *htab;
-  const insn_sequence *template;
-  int template_size;
-  int size;
-  int i;
-
-  /* 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;
+  const insn_sequence *template = NULL;
+  int template_size = 0, i;
+  unsigned int size;
 
-  switch (stub_entry->stub_type)
+  switch (stub_type)
     {
     case arm_stub_long_branch_any_any:
       template =  elf32_arm_stub_long_branch_any_any;
@@ -3411,9 +3580,22 @@ arm_size_one_stub (struct bfd_hash_entry
       template = elf32_arm_stub_long_branch_v4t_thumb_thumb_pic;
       template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_v4t_thumb_thumb_pic);
       break;
+    case arm_stub_a8_veneer_b_cond:
+      template = elf32_arm_stub_a8_veneer_b_cond;
+      template_size = ARRAY_SIZE (elf32_arm_stub_a8_veneer_b_cond);
+      break;
+    case arm_stub_a8_veneer_b:
+    case arm_stub_a8_veneer_bl:
+      template = elf32_arm_stub_a8_veneer_b;
+      template_size = ARRAY_SIZE (elf32_arm_stub_a8_veneer_b);
+      break;
+    case arm_stub_a8_veneer_blx:
+      template = elf32_arm_stub_a8_veneer_blx;
+      template_size = ARRAY_SIZE (elf32_arm_stub_a8_veneer_blx);
+      break;
     default:
       BFD_FAIL ();
-      return FALSE;
+      return 0;
     }
 
   size = 0;
@@ -3426,19 +3608,46 @@ arm_size_one_stub (struct bfd_hash_entry
 	  break;
 
 	case ARM_TYPE:
-	  size += 4;
-	  break;
-
+	case THUMB32_TYPE:
 	case DATA_TYPE:
 	  size += 4;
 	  break;
 
 	default:
 	  BFD_FAIL ();
-	  return FALSE;
+	  return 0;
 	}
     }
 
+  if (stub_template)
+    *stub_template = template;
+
+  if (stub_template_size)
+    *stub_template_size = template_size;
+
+  return size;
+}
+
+/* As arm_build_one_stub, but don't actually build the stub.  Just bump offset
+   so we know stub section sizes.  */
+
+static bfd_boolean
+arm_size_one_stub (struct bfd_hash_entry *gen_entry,
+                   void * in_arg)
+{
+  struct elf32_arm_stub_hash_entry *stub_entry;
+  struct elf32_arm_link_hash_table *htab;
+  const insn_sequence *template;
+  int template_size;
+  int 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;
+
+  size = find_stub_size_and_template (stub_entry->stub_type, &template,
+                                      &template_size);
+
   stub_entry->stub_size = size;
   stub_entry->stub_template = template;
   stub_entry->stub_template_size = template_size;
@@ -3655,6 +3864,290 @@ group_sections (struct elf32_arm_link_ha
 #undef NEXT_SEC
 }
 
+/* Comparison function for sorting/searching relocations relating to Cortex-A8
+   erratum fix.  */
+
+static int
+a8_reloc_compare (const void *a, const void *b)
+{
+  const struct a8_erratum_reloc *ra = a, *rb = b;
+
+  if (ra->from < rb->from)
+    return -1;
+  else if (ra->from > rb->from)
+    return 1;
+  else
+    return 0;
+}
+
+static struct elf_link_hash_entry *find_thumb_glue (struct bfd_link_info *,
+						    const char *, char **);
+
+/* 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
+   otherwise.  */
+
+static int
+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)
+{
+  asection *section;
+  struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
+  struct a8_erratum_fix *a8_fixes = *a8_fixes_p;
+  unsigned int num_a8_fixes = *num_a8_fixes_p;
+  unsigned int a8_fix_table_size = *a8_fix_table_size_p;
+  
+  for (section = input_bfd->sections;
+       section != NULL;
+       section = section->next)
+    {
+      bfd_byte *contents = NULL;
+      struct _arm_elf_section_data *sec_data;
+      unsigned int span;
+      bfd_vma base_vma;
+
+      if (elf_section_type (section) != SHT_PROGBITS
+          || (elf_section_flags (section) & SHF_EXECINSTR) == 0
+          || (section->flags & SEC_EXCLUDE) != 0
+          || (section->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+          || (section->output_section == bfd_abs_section_ptr))
+        continue;
+
+      base_vma = section->output_section->vma + section->output_offset;
+
+      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;
+
+      sec_data = elf32_arm_section_data (section);
+
+      for (span = 0; span < sec_data->mapcount; span++)
+        {
+          unsigned int span_start = sec_data->map[span].vma;
+          unsigned int span_end = (span == sec_data->mapcount - 1)
+            ? section->size : sec_data->map[span + 1].vma;
+          unsigned int i;
+          char span_type = sec_data->map[span].type;
+          bfd_boolean last_was_32bit = FALSE, last_was_branch = FALSE;
+
+          if (span_type != 't')
+            continue;
+
+          /* Span is entirely within a single 4KB region: skip scanning.  */
+          if (((base_vma + span_start) & ~0xfff)
+	      == ((base_vma + span_end) & ~0xfff))
+            continue;
+
+          /* Scan for 32-bit Thumb-2 branches which span two 4K regions, where:
+
+               * The opcode is BLX.W, BL.W, B.W, Bcc.W
+               * 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.
+          */
+
+          for (i = span_start; i < span_end;)
+            {
+              unsigned int insn = bfd_getl16 (&contents[i]);
+              bfd_boolean insn_32bit = FALSE, is_blx = FALSE, is_b = FALSE;
+	      bfd_boolean is_bl = FALSE, is_bcc = FALSE, is_32bit_branch;
+
+              if ((insn & 0xe000) == 0xe000 && (insn & 0x1800) != 0x0000)
+                insn_32bit = TRUE;
+
+	      if (insn_32bit)
+	        {
+                  /* Load the rest of the insn (in manual-friendly order).  */
+                  insn = (insn << 16) | bfd_getl16 (&contents[i + 2]);
+
+        	  /* Encoding T4: B<c>.W.  */
+        	  is_b = (insn & 0xf800d000) == 0xf0009000;
+        	  /* Encoding T1: BL<c>.W.  */
+        	  is_bl = (insn & 0xf800d000) == 0xf000d000;
+        	  /* Encoding T2: BLX<c>.W.  */
+        	  is_blx = (insn & 0xf800d000) == 0xf000c000;
+		  /* Encoding T3: B<c>.W (not permitted in IT block).  */
+		  is_bcc = (insn & 0xf800d000) == 0xf0008000
+			   && (insn & 0x07f00000) != 0x03800000;
+		}
+
+	      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_vma offset;
+                  bfd_boolean force_target_arm = FALSE;
+		  bfd_boolean force_target_thumb = FALSE;
+                  bfd_vma target;
+                  enum elf32_arm_stub_type stub_type = arm_stub_none;
+                  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);
+
+		  if (found)
+		    {
+		      char *error_message = NULL;
+		      struct elf_link_hash_entry *entry;
+
+		      /* We don't care about the error returned from this
+		         function, only if there is glue or not.  */
+		      entry = find_thumb_glue (info, found->sym_name,
+					       &error_message);
+
+		      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;
+		    }
+
+                  /* Check if we have an offending branch instruction.  */
+
+		  if (found && found->non_a8_stub)
+		    /* We've already made a stub for this instruction, e.g.
+		       it's a long branch or a Thumb->ARM stub.  Assume that
+		       stub will suffice to work around the A8 erratum (see
+		       setting of always_after_branch above).  */
+		    ;
+                  else if (is_bcc)
+                    {
+                      offset = (insn & 0x7ff) << 1;
+                      offset |= (insn & 0x3f0000) >> 4;
+                      offset |= (insn & 0x2000) ? 0x40000 : 0;
+                      offset |= (insn & 0x800) ? 0x80000 : 0;
+                      offset |= (insn & 0x4000000) ? 0x100000 : 0;
+                      if (offset & 0x100000)
+                        offset |= ~0xfffff;
+                      stub_type = arm_stub_a8_veneer_b_cond;
+                    }
+                  else if (is_b || is_bl || is_blx)
+                    {
+                      int s = (insn & 0x4000000) != 0;
+                      int j1 = (insn & 0x2000) != 0;
+                      int j2 = (insn & 0x800) != 0;
+                      int i1 = !(j1 ^ s);
+                      int i2 = !(j2 ^ s);
+
+                      offset = (insn & 0x7ff) << 1;
+                      offset |= (insn & 0x3ff0000) >> 4;
+                      offset |= i2 << 22;
+                      offset |= i1 << 23;
+                      offset |= s << 24;
+                      if (offset & 0x1000000)
+                        offset |= ~0xffffff;
+
+                      if (is_blx)
+                        offset &= ~3u;
+
+                      stub_type = is_blx ? arm_stub_a8_veneer_blx :
+                        is_bl ? arm_stub_a8_veneer_bl : arm_stub_a8_veneer_b;
+                    }
+
+                  if (stub_type != arm_stub_none)
+                    {
+                      bfd_vma pc_for_insn = base_vma + i + 4;
+
+		      /* The original instruction is a BL, but the target is
+		         an ARM instruction.  If we were not making a stub,
+			 the BL would have been converted to a BLX.  Use the
+			 BLX stub instead in that case.  */
+		      if (htab->use_blx && force_target_arm
+			  && stub_type == arm_stub_a8_veneer_bl)
+			{
+			  stub_type = arm_stub_a8_veneer_blx;
+			  is_blx = TRUE;
+			  is_bl = FALSE;
+			}
+		      /* Conversely, if the original instruction was
+			 BLX but the target is Thumb mode, use the BL
+			 stub.  */
+		      else if (force_target_thumb
+			       && stub_type == arm_stub_a8_veneer_blx)
+			{
+			  stub_type = arm_stub_a8_veneer_bl;
+			  is_blx = FALSE;
+			  is_bl = TRUE;
+			}
+
+                      if (is_blx)
+                        pc_for_insn &= ~3u;
+
+                      /* 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;
+
+                      target = pc_for_insn + offset;
+
+                      /* The BLX stub is ARM-mode code.  Adjust the offset to
+		         take the different PC value (+8 instead of +4) into
+			 account.  */
+                      if (stub_type == arm_stub_a8_veneer_blx)
+                        offset += 4;
+
+                      if (((base_vma + i) & ~0xfff) == (target & ~0xfff))
+                        {
+                          char *stub_name;
+
+                          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);
+                            }
+
+                          stub_name = 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;
+                          a8_fixes[num_a8_fixes].offset = i;
+                          a8_fixes[num_a8_fixes].addend = offset;
+                          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;
+
+                          num_a8_fixes++;
+                        }
+                    }
+                }
+
+              i += insn_32bit ? 4 : 2;
+              last_was_32bit = insn_32bit;
+	      last_was_branch = is_32bit_branch;
+            }
+        }
+
+      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 0;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -3673,6 +4166,19 @@ elf32_arm_size_stubs (bfd *output_bfd,
   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;
+  struct a8_erratum_reloc *a8_relocs = NULL;
+  unsigned int num_a8_relocs = 0, a8_reloc_table_size = 10;
+  unsigned int 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);
+    }
 
   /* Propagate mach to stub bfd, because it may not have been
      finalized when we created stub_bfd.  */
@@ -3684,6 +4190,13 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->add_stub_section = add_stub_section;
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
+
+  /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
+     as the first half of a 32-bit branch straddling two 4K pages.  This is a
+     crude way of enforcing that.  */
+  if (htab->fix_cortex_a8)
+    stubs_always_after_branch = 1;
+
   if (group_size < 0)
     stub_group_size = -group_size;
   else
@@ -3711,6 +4224,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
       unsigned int bfd_indx;
       asection *stub_sec;
 
+      num_a8_fixes = 0;
+
       for (input_bfd = info->input_bfds, bfd_indx = 0;
 	   input_bfd != NULL;
 	   input_bfd = input_bfd->link_next, bfd_indx++)
@@ -3719,6 +4234,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  asection *section;
 	  Elf_Internal_Sym *local_syms = NULL;
 
+	  num_a8_relocs = 0;
+
 	  /* We'll need the symbol table in a second.  */
 	  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
 	  if (symtab_hdr->sh_info == 0)
@@ -3767,6 +4284,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 		  char *stub_name;
 		  const asection *id_sec;
 		  unsigned char st_type;
+		  bfd_boolean created_stub = FALSE;
 
 		  r_type = ELF32_R_TYPE (irela->r_info);
 		  r_indx = ELF32_R_SYM (irela->r_info);
@@ -3785,6 +4303,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
 		      && (r_type != (unsigned int) R_ARM_THM_CALL)
 		      && (r_type != (unsigned int) R_ARM_JUMP24)
 		      && (r_type != (unsigned int) R_ARM_THM_JUMP24)
+		      && (r_type != (unsigned int) R_ARM_THM_JUMP19)
+		      && (r_type != (unsigned int) R_ARM_THM_XPC22)
 		      && (r_type != (unsigned int) R_ARM_PLT32))
 		    continue;
 
@@ -3884,80 +4404,145 @@ elf32_arm_size_stubs (bfd *output_bfd,
 		      sym_name = hash->root.root.root.string;
 		    }
 
-		  /* Determine what (if any) linker stub is needed.  */
-		  stub_type = arm_type_of_stub (info, section, irela, st_type,
-						hash, destination, sym_sec,
-						input_bfd, sym_name);
-		  if (stub_type == arm_stub_none)
-		    continue;
+                  do
+                    {
+		      /* Determine what (if any) linker stub is needed.  */
+		      stub_type = arm_type_of_stub (info, section, irela,
+						    st_type, hash,
+						    destination, sym_sec,
+						    input_bfd, sym_name);
+		      if (stub_type == arm_stub_none)
+			break;
 
-		  /* Support for grouping stub sections.  */
-		  id_sec = htab->stub_group[section->id].link_sec;
+		      /* Support for grouping stub sections.  */
+		      id_sec = htab->stub_group[section->id].link_sec;
 
-		  /* Get the name of this stub.  */
-		  stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash, irela);
-		  if (!stub_name)
-		    goto error_ret_free_internal;
+		      /* Get the name of this stub.  */
+		      stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash,
+						       irela);
+		      if (!stub_name)
+			goto error_ret_free_internal;
 
-		  stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table,
-						    stub_name,
-						    FALSE, FALSE);
-		  if (stub_entry != NULL)
-		    {
-		      /* The proper stub has already been created.  */
-		      free (stub_name);
-		      continue;
-		    }
+		      /* We've either created a stub for this reloc already,
+			 or we are about to.  */
+		      created_stub = TRUE;
 
-		  stub_entry = elf32_arm_add_stub (stub_name, section, htab);
-		  if (stub_entry == NULL)
-		    {
-		      free (stub_name);
-		      goto error_ret_free_internal;
-		    }
+		      stub_entry = arm_stub_hash_lookup
+				     (&htab->stub_hash_table, stub_name,
+				      FALSE, FALSE);
+		      if (stub_entry != NULL)
+			{
+			  /* The proper stub has already been created.  */
+			  free (stub_name);
+			  break;
+			}
 
-		  stub_entry->target_value = sym_value;
-		  stub_entry->target_section = sym_sec;
-		  stub_entry->stub_type = stub_type;
-		  stub_entry->h = hash;
-		  stub_entry->st_type = st_type;
+		      stub_entry = elf32_arm_add_stub (stub_name, section,
+						       htab);
+		      if (stub_entry == NULL)
+			{
+			  free (stub_name);
+			  goto error_ret_free_internal;
+			}
 
-		  if (sym_name == NULL)
-		    sym_name = "unnamed";
-		  stub_entry->output_name
-		    = bfd_alloc (htab->stub_bfd,
-				 sizeof (THUMB2ARM_GLUE_ENTRY_NAME)
-				 + strlen (sym_name));
-		  if (stub_entry->output_name == NULL)
-		    {
-		      free (stub_name);
-		      goto error_ret_free_internal;
-		    }
+		      stub_entry->target_value = sym_value;
+		      stub_entry->target_section = sym_sec;
+		      stub_entry->stub_type = stub_type;
+		      stub_entry->h = hash;
+		      stub_entry->st_type = st_type;
 
-		  /* For historical reasons, use the existing names for
-		     ARM-to-Thumb and Thumb-to-ARM stubs.  */
-		  if ( ((r_type == (unsigned int) R_ARM_THM_CALL)
-			|| (r_type == (unsigned int) R_ARM_THM_JUMP24))
-		       && st_type != STT_ARM_TFUNC)
-		    sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME,
-			     sym_name);
-		  else if ( ((r_type == (unsigned int) R_ARM_CALL)
-			     || (r_type == (unsigned int) R_ARM_JUMP24))
-			   && st_type == STT_ARM_TFUNC)
-		    sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME,
-			     sym_name);
-		  else
-		    sprintf (stub_entry->output_name, STUB_ENTRY_NAME,
-			     sym_name);
+		      if (sym_name == NULL)
+			sym_name = "unnamed";
+		      stub_entry->output_name
+			= bfd_alloc (htab->stub_bfd,
+				     sizeof (THUMB2ARM_GLUE_ENTRY_NAME)
+				     + strlen (sym_name));
+		      if (stub_entry->output_name == NULL)
+			{
+			  free (stub_name);
+			  goto error_ret_free_internal;
+			}
 
-		  stub_changed = TRUE;
+		      /* For historical reasons, use the existing names for
+			 ARM-to-Thumb and Thumb-to-ARM stubs.  */
+		      if ( ((r_type == (unsigned int) R_ARM_THM_CALL)
+			    || (r_type == (unsigned int) R_ARM_THM_JUMP24))
+			   && st_type != STT_ARM_TFUNC)
+			sprintf (stub_entry->output_name,
+				 THUMB2ARM_GLUE_ENTRY_NAME, sym_name);
+		      else if ( ((r_type == (unsigned int) R_ARM_CALL)
+				 || (r_type == (unsigned int) R_ARM_JUMP24))
+			       && st_type == STT_ARM_TFUNC)
+			sprintf (stub_entry->output_name,
+				 ARM2THUMB_GLUE_ENTRY_NAME, sym_name);
+		      else
+			sprintf (stub_entry->output_name, STUB_ENTRY_NAME,
+				 sym_name);
+
+		      stub_changed = TRUE;
+                    }
+                  while (0);
+
+                  /* Look for relocations which might trigger Cortex-A8
+                     erratum.  */
+                  if (htab->fix_cortex_a8
+                      && (r_type == (unsigned int) R_ARM_THM_JUMP24
+                          || r_type == (unsigned int) R_ARM_THM_JUMP19
+                          || r_type == (unsigned int) R_ARM_THM_CALL
+                          || r_type == (unsigned int) R_ARM_THM_XPC22))
+                    {
+                      bfd_vma from = section->output_section->vma
+                                     + section->output_offset
+                                     + irela->r_offset;
+
+                      if ((from & 0xfff) == 0xffe)
+                        {
+                          /* Found a candidate.  Note we haven't checked the
+                             destination is within 4K here: if we do so (and
+                             don't create an entry in a8_relocs) we can't tell
+                             that a branch should have been relocated when
+                             scanning later.  */
+                          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[num_a8_relocs].from = from;
+			  a8_relocs[num_a8_relocs].destination = destination;
+			  a8_relocs[num_a8_relocs].r_type = r_type;
+			  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;
+
+                          num_a8_relocs++;
+                        }
+                    }
 		}
 
-	      /* We're done with the internal relocs, free them.  */
-	      if (elf_section_data (section)->relocs == NULL)
-		free (internal_relocs);
+              /* We're done with the internal relocs, free them.  */
+              if (elf_section_data (section)->relocs == NULL)
+                free (internal_relocs);
+            }
+
+          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),
+                     &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)
+		goto error_ret_free_local;
 	    }
-	}
+        }
+
+      if (htab->fix_cortex_a8 && num_a8_fixes != prev_num_a8_fixes)
+        stub_changed = TRUE;
 
       if (!stub_changed)
 	break;
@@ -3977,9 +4562,78 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       bfd_hash_traverse (&htab->stub_hash_table, arm_size_one_stub, htab);
 
+      /* Add Cortex-A8 erratum veneers to stub section sizes too.  */
+      if (htab->fix_cortex_a8)
+        for (i = 0; i < num_a8_fixes; i++)
+          {
+	    stub_sec = elf32_arm_create_or_find_stub_sec (NULL,
+			 a8_fixes[i].section, htab);
+
+            if (stub_sec == NULL)
+	      goto error_ret_free_local;
+
+            stub_sec->size
+              += find_stub_size_and_template (a8_fixes[i].stub_type, NULL,
+                                              NULL);
+          }
+
       /* 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.  */
+  if (htab->fix_cortex_a8)
+    {
+      for (i = 0; i < num_a8_fixes; i++)
+        {
+          struct elf32_arm_stub_hash_entry *stub_entry;
+          char *stub_name = a8_fixes[i].stub_name;
+          asection *section = a8_fixes[i].section;
+          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;
+          int template_size, size = 0;
+
+          stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+                                             TRUE, FALSE);
+          if (stub_entry == NULL)
+            {
+              (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
+                                     section->owner,
+                                     stub_name);
+              return FALSE;
+            }
+
+          stub_entry->stub_sec = stub_sec;
+          stub_entry->stub_offset = 0;
+          stub_entry->id_sec = link_sec;
+          stub_entry->stub_type = a8_fixes[i].stub_type;
+          stub_entry->target_section = a8_fixes[i].section;
+          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;
+
+          size = find_stub_size_and_template (a8_fixes[i].stub_type, &template,
+                                              &template_size);
+
+          stub_entry->stub_size = size;
+          stub_entry->stub_template = template;
+          stub_entry->stub_template_size = template_size;
+        }
+
+      /* Stash the Cortex-A8 erratum fix array for use later in
+         elf32_arm_write_section().  */
+      htab->a8_erratum_fixes = a8_fixes;
+      htab->num_a8_erratum_fixes = num_a8_fixes;
+    }
+  else
+    {
+      htab->a8_erratum_fixes = NULL;
+      htab->num_a8_erratum_fixes = 0;
     }
 
   return TRUE;
@@ -4799,6 +5453,27 @@ bfd_elf32_arm_init_maps (bfd *abfd)
 }
 
 
+/* Auto-select enabling of Cortex-A8 erratum fix if the user didn't explicitly
+   say what they wanted.  */
+
+void
+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->fix_cortex_a8 == -1)
+    {
+      /* Turn on Cortex-A8 erratum workaround for ARMv7-A.  */
+      if (out_attr[Tag_CPU_arch].i == TAG_CPU_ARCH_V7
+	  && (out_attr[Tag_CPU_arch_profile].i == 'A'
+	      || out_attr[Tag_CPU_arch_profile].i == 0))
+	globals->fix_cortex_a8 = 1;
+      else
+	globals->fix_cortex_a8 = 0;
+    }
+}
+
 void
 bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
 {
@@ -5408,7 +6083,7 @@ bfd_elf32_arm_set_target_relocs (struct 
 				 int use_blx,
                                  bfd_arm_vfp11_fix vfp11_fix,
 				 int no_enum_warn, int no_wchar_warn,
-				 int pic_veneer)
+				 int pic_veneer, int fix_cortex_a8)
 {
   struct elf32_arm_link_hash_table *globals;
 
@@ -5430,6 +6105,7 @@ bfd_elf32_arm_set_target_relocs (struct 
   globals->use_blx |= use_blx;
   globals->vfp11_fix = vfp11_fix;
   globals->pic_veneer = pic_veneer;
+  globals->fix_cortex_a8 = fix_cortex_a8;
 
   BFD_ASSERT (is_arm_elf (output_bfd));
   elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
@@ -11914,6 +12590,7 @@ arm_map_one_stub (struct bfd_hash_entry 
 	return FALSE;
       break;
     case THUMB16_TYPE:
+    case THUMB32_TYPE:
       if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1,
 				      stub_entry->stub_size))
 	return FALSE;
@@ -11934,6 +12611,7 @@ arm_map_one_stub (struct bfd_hash_entry 
 	  break;
 
 	case THUMB16_TYPE:
+	case THUMB32_TYPE:
 	  sym_type = ARM_MAP_THUMB;
 	  break;
 
@@ -11956,6 +12634,7 @@ arm_map_one_stub (struct bfd_hash_entry 
       switch (template[i].type)
 	{
 	case ARM_TYPE:
+	case THUMB32_TYPE:
 	  size += 4;
 	  break;
 
@@ -12153,6 +12832,121 @@ elf32_arm_compare_mapping (const void * 
 }
 
 
+/* Data for make_branch_to_a8_stub().  */
+
+struct a8_branch_to_stub_data {
+  asection *writing_section;
+  bfd_byte *contents;
+};
+
+
+/* Helper to insert branches to Cortex-A8 erratum stubs in the right
+   places for a particular section.  */
+
+static bfd_boolean
+make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry,
+                       void *in_arg)
+{
+  struct elf32_arm_stub_hash_entry *stub_entry;
+  struct a8_branch_to_stub_data *data;
+  bfd_byte *contents;
+  unsigned long branch_insn;
+  bfd_vma veneered_insn_loc, veneer_entry_loc;
+  bfd_signed_vma branch_offset;
+  bfd *abfd;
+  unsigned int index;
+
+  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)
+    return TRUE;
+
+  contents = data->contents;
+
+  veneered_insn_loc = stub_entry->target_section->output_section->vma
+		      + stub_entry->target_section->output_offset
+		      + stub_entry->target_value;
+
+  veneer_entry_loc = stub_entry->stub_sec->output_section->vma
+		     + stub_entry->stub_sec->output_offset
+		     + stub_entry->stub_offset;
+
+  if (stub_entry->stub_type == arm_stub_a8_veneer_blx)
+    veneered_insn_loc &= ~3u;
+
+  branch_offset = veneer_entry_loc - veneered_insn_loc - 4;
+
+  abfd = stub_entry->target_section->owner;
+  index = 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.
+     This check is just to be on the safe side...  */
+  if ((veneered_insn_loc & ~0xfff) == (veneer_entry_loc & ~0xfff))
+    {
+      (*_bfd_error_handler) (_("%B: error: Cortex-A8 erratum stub is "
+			       "allocated in unsafe location"), abfd);
+      return FALSE;
+    }
+
+  switch (stub_entry->stub_type)
+    {
+    case arm_stub_a8_veneer_b:
+    case arm_stub_a8_veneer_b_cond:
+      branch_insn = 0xf0009000;
+      goto jump24;
+
+    case arm_stub_a8_veneer_blx:
+      branch_insn = 0xf000e800;
+      goto jump24;
+
+    case arm_stub_a8_veneer_bl:
+      {
+	unsigned int i1, j1, i2, j2, s;
+
+	branch_insn = 0xf000d000;
+
+      jump24:
+	if (branch_offset < -16777216 || branch_offset > 16777214)
+	  {
+	    /* There's not much we can do apart from complain if this
+	       happens.  */
+	    (*_bfd_error_handler) (_("%B: error: Cortex-A8 erratum stub out "
+				     "of range (input file too large)"), abfd);
+	    return FALSE;
+	  }
+
+	/* i1 = not(j1 eor s), so:
+	   not i1 = j1 eor s
+	   j1 = (not i1) eor s.  */
+
+	branch_insn |= (branch_offset >> 1) & 0x7ff;
+	branch_insn |= ((branch_offset >> 12) & 0x3ff) << 16;
+	i2 = (branch_offset >> 22) & 1;
+	i1 = (branch_offset >> 23) & 1;
+	s = (branch_offset >> 24) & 1;
+	j1 = (!i1) ^ s;
+	j2 = (!i2) ^ s;
+	branch_insn |= j2 << 11;
+	branch_insn |= j1 << 13;
+	branch_insn |= s << 26;
+      }
+      break;
+
+    default:
+      BFD_FAIL ();
+      return FALSE;
+    }
+
+  bfd_put_16 (abfd, (branch_insn >> 16) & 0xffff, &contents[index]);
+  bfd_put_16 (abfd, branch_insn & 0xffff, &contents[index + 2]);
+
+  return TRUE;
+}
+
+
 /* Do code byteswapping.  Return FALSE afterwards so that the section is
    written out as normal.  */
 
@@ -12162,7 +12956,7 @@ elf32_arm_write_section (bfd *output_bfd
 			 asection *sec,
 			 bfd_byte *contents)
 {
-  int mapcount, errcount;
+  unsigned int mapcount, errcount;
   _arm_elf_section_data *arm_data;
   struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
   elf32_arm_section_map *map;
@@ -12171,7 +12965,7 @@ elf32_arm_write_section (bfd *output_bfd
   bfd_vma end;
   bfd_vma offset = sec->output_section->vma + sec->output_offset;
   bfd_byte tmp;
-  int i;
+  unsigned int i;
 
   /* If this section has not been allocated an _arm_elf_section_data
      structure then we cannot record anything.  */
@@ -12258,6 +13052,18 @@ elf32_arm_write_section (bfd *output_bfd
         }
     }
 
+  /* Fix code to point to Cortex-A8 erratum stubs.  */
+  if (globals->fix_cortex_a8)
+    {
+      struct a8_branch_to_stub_data data;
+
+      data.writing_section = sec;
+      data.contents = contents;
+
+      bfd_hash_traverse (&globals->stub_hash_table, make_branch_to_a8_stub,
+			 &data);
+    }
+
   if (mapcount == 0)
     return FALSE;
 
--- .pc/cortex-a8-fix-3/ld/emultempl/armelf.em	2009-05-01 03:22:19.000000000 -0700
+++ ld/emultempl/armelf.em	2009-05-01 03:45:22.000000000 -0700
@@ -37,6 +37,7 @@ static char *target2_type = "${TARGET2_T
 static int fix_v4bx = 0;
 static int use_blx = 0;
 static bfd_arm_vfp11_fix vfp11_denorm_fix = BFD_ARM_VFP11_FIX_DEFAULT;
+static int fix_cortex_a8 = -1;
 static int no_enum_size_warning = 0;
 static int no_wchar_size_warning = 0;
 static int pic_veneer = 0;
@@ -60,6 +61,9 @@ arm_elf_before_allocation (void)
      due to architecture version.  */
   bfd_elf32_arm_set_vfp11_fix (link_info.output_bfd, &link_info);
 
+  /* Auto-select Cortex-A8 erratum fix if it wasn't explicitly specified.  */
+  bfd_elf32_arm_set_cortex_a8_fix (link_info.output_bfd, &link_info);
+
   /* We should be able to set the size of the interworking stub section.  We
      can't do it until later if we have dynamic sections, though.  */
   if (! elf_hash_table (&link_info)->dynamic_sections_created)
@@ -390,7 +394,7 @@ arm_elf_create_output_section_statements
 				   target2_type, fix_v4bx, use_blx,
 				   vfp11_denorm_fix, no_enum_size_warning,
 				   no_wchar_size_warning,
-				   pic_veneer);
+				   pic_veneer, fix_cortex_a8);
 
   stub_file = lang_add_input_file ("linker stubs",
  				   lang_input_file_is_fake_enum,
@@ -452,6 +456,8 @@ PARSE_AND_LIST_PROLOGUE='
 #define OPTION_FIX_V4BX_INTERWORKING	311
 #define OPTION_STUBGROUP_SIZE           312
 #define OPTION_NO_WCHAR_SIZE_WARNING	313
+#define OPTION_FIX_CORTEX_A8		314
+#define OPTION_NO_FIX_CORTEX_A8		315
 '
 
 PARSE_AND_LIST_SHORTOPTS=p
@@ -471,6 +477,8 @@ PARSE_AND_LIST_LONGOPTS='
   { "pic-veneer", no_argument, NULL, OPTION_PIC_VENEER},
   { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
   { "no-wchar-size-warning", no_argument, NULL, OPTION_NO_WCHAR_SIZE_WARNING},
+  { "fix-cortex-a8", no_argument, NULL, OPTION_FIX_CORTEX_A8 },
+  { "no-fix-cortex-a8", no_argument, NULL, OPTION_NO_FIX_CORTEX_A8 },
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -497,6 +505,7 @@ PARSE_AND_LIST_OPTIONS='
                            after each stub section.  Values of +/-1 indicate\n\
                            the linker should choose suitable defaults.\n"
  		   ));
+  fprintf (file, _("  --[no-]fix-cortex-a8        Disable/enable Cortex-A8 Thumb-2 branch erratum fix\n"));
 '
 
 PARSE_AND_LIST_ARGS_CASES='
@@ -568,6 +577,14 @@ PARSE_AND_LIST_ARGS_CASES='
 	  einfo (_("%P%F: invalid number `%s'\''\n"), optarg);
       }
       break;
+
+    case OPTION_FIX_CORTEX_A8:
+      fix_cortex_a8 = 1;
+      break;
+
+    case OPTION_NO_FIX_CORTEX_A8:
+      fix_cortex_a8 = 0;
+      break;
 '
 
 # We have our own before_allocation etc. functions, but they call
--- .pc/cortex-a8-fix-3/ld/testsuite/ld-arm/arm-elf.exp	2009-05-01 03:22:19.000000000 -0700
+++ ld/testsuite/ld-arm/arm-elf.exp	2009-05-01 03:45:22.000000000 -0700
@@ -161,6 +161,50 @@ set armelftests {
      "-EL --vfp11-denorm-fix=scalar -Ttext=0x8000" "-EL -mfpu=vfpxd" {vfp11-fix-none.s}
      {{objdump -dr vfp11-fix-none.d}}
      "vfp11-fix-none"}
+    {"Cortex-A8 erratum fix, b.w"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-fix-b.s}
+     {{objdump -dr cortex-a8-fix-b.d}}
+     "cortex-a8-fix-b"}
+    {"Cortex-A8 erratum fix, bl.w"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-fix-bl.s}
+     {{objdump -dr cortex-a8-fix-bl.d}}
+     "cortex-a8-fix-bl"}
+    {"Cortex-A8 erratum fix, bcc.w"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-fix-bcc.s}
+     {{objdump -dr cortex-a8-fix-bcc.d}}
+     "cortex-a8-fix-bcc"}
+    {"Cortex-A8 erratum fix, blx.w"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-fix-blx.s}
+     {{objdump -dr cortex-a8-fix-blx.d}}
+     "cortex-a8-fix-blx"}
+    {"Cortex-A8 erratum fix, relocate b.w to ARM"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-arm-target.s cortex-a8-fix-b-rel.s}
+     {{objdump -dr cortex-a8-fix-b-rel-arm.d}}
+     "cortex-a8-fix-b-rel-arm"}
+    {"Cortex-A8 erratum fix, relocate b.w to Thumb"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-thumb-target.s cortex-a8-fix-b-rel.s}
+     {{objdump -dr cortex-a8-fix-b-rel-thumb.d}}
+     "cortex-a8-fix-b-rel-thumb"}
+    {"Cortex-A8 erratum fix, relocate bl.w to ARM"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-arm-target.s cortex-a8-fix-bl-rel.s}
+     {{objdump -dr cortex-a8-fix-bl-rel-arm.d}}
+     "cortex-a8-fix-bl-rel-arm"}
+    {"Cortex-A8 erratum fix, relocate bl.w to Thumb"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-thumb-target.s cortex-a8-fix-bl-rel.s}
+     {{objdump -dr cortex-a8-fix-bl-rel-thumb.d}}
+     "cortex-a8-fix-bl-rel-thumb"}
+    {"Cortex-A8 erratum fix, relocate b<cond>.w to Thumb"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-thumb-target.s cortex-a8-fix-bcc-rel.s}
+     {{objdump -dr cortex-a8-fix-bcc-rel-thumb.d}}
+     "cortex-a8-fix-bcc-rel-thumb"}
+    {"Cortex-A8 erratum fix, relocate blx.w to ARM"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-arm-target.s cortex-a8-fix-blx-rel.s}
+     {{objdump -dr cortex-a8-fix-blx-rel-arm.d}}
+     "cortex-a8-fix-blx-rel-arm"}
+    {"Cortex-A8 erratum fix, relocate blx.w to Thumb"
+     "-EL -Ttext=0x8f00 --fix-cortex-a8" "-EL" {cortex-a8-thumb-target.s cortex-a8-fix-blx-rel.s}
+     {{objdump -dr cortex-a8-fix-blx-rel-thumb.d}}
+     "cortex-a8-fix-blx-rel-thumb"}
     {"Unwinding and -gc-sections" "-gc-sections" "" {gc-unwind.s}
      {{objdump -sj.data gc-unwind.d}}
      "gc-unwind"}
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-b.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,75 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <_start>:
+    8f00:	bf00      	nop
+    8f02:	eb01 0002 	add\.w	r0, r1, r2
+    8f06:	f7ff bffc 	b\.w	8f02 <_start\+0x2>
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff bff8 	b\.w	8f02 <_start\+0x2>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff bff4 	b\.w	8f02 <_start\+0x2>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff bff0 	b\.w	8f02 <_start\+0x2>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff bffc 	b\.w	8f22 <_start\+0x22>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff bff8 	b\.w	8f22 <_start\+0x22>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff bff4 	b\.w	8f22 <_start\+0x22>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff bff0 	b\.w	8f22 <_start\+0x22>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff bffc 	b\.w	8f42 <_start\+0x42>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff bff8 	b\.w	8f42 <_start\+0x42>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff bff4 	b\.w	8f42 <_start\+0x42>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff bff0 	b\.w	8f42 <_start\+0x42>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff bffc 	b\.w	8f62 <_start\+0x62>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff bff8 	b\.w	8f62 <_start\+0x62>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff bff4 	b\.w	8f62 <_start\+0x62>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff bff0 	b\.w	8f62 <_start\+0x62>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff bffc 	b\.w	8f82 <_start\+0x82>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff bff8 	b\.w	8f82 <_start\+0x82>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff bff4 	b\.w	8f82 <_start\+0x82>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff bff0 	b\.w	8f82 <_start\+0x82>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff bffc 	b\.w	8fa2 <_start\+0xa2>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff bff8 	b\.w	8fa2 <_start\+0xa2>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff bff4 	b\.w	8fa2 <_start\+0xa2>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff bff0 	b\.w	8fa2 <_start\+0xa2>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff bffc 	b\.w	8fc2 <_start\+0xc2>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff bff8 	b\.w	8fc2 <_start\+0xc2>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff bff4 	b\.w	8fc2 <_start\+0xc2>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff bff0 	b\.w	8fc2 <_start\+0xc2>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff bffc 	b\.w	8fe2 <_start\+0xe2>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff bff8 	b\.w	8fe2 <_start\+0xe2>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff bff4 	b\.w	8fe2 <_start\+0xe2>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 b803 	b\.w	9008 <_start\+0x108>
+    9002:	4770      	bx	lr
+    9004:	f3af 8000 	nop\.w
+    9008:	f7ff bfeb 	b\.w	8fe2 <_start\+0xe2>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-b.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,39 @@
+	.syntax unified
+	.cpu cortex-a8
+	.thumb
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+1:
+        add.w r0, r1, r2
+        b.w 1b
+        add.w r0, r1, r2
+        b.w 1b
+        add.w r0, r1, r2
+        b.w 1b
+        add.w r0, r1, r2
+        b.w 1b
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+        .align  3
+        .global _start
+        .thumb
+        .thumb_func
+        .type   _start, %function
+_start:
+        nop
+
+	@ Trigger Cortex-A8 erratum workaround with b instructions.
+        bw2
+        bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bcc.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,77 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <_start>:
+    8f00:	bf00      	nop
+    8f02:	eb01 0002 	add\.w	r0, r1, r2
+    8f06:	f4ff affc 	bcc\.w	8f02 <_start\+0x2>
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f4ff aff8 	bcc\.w	8f02 <_start\+0x2>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f4ff aff4 	bcc\.w	8f02 <_start\+0x2>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f4ff aff0 	bcc\.w	8f02 <_start\+0x2>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f4ff affc 	bcc\.w	8f22 <_start\+0x22>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f4ff aff8 	bcc\.w	8f22 <_start\+0x22>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f4ff aff4 	bcc\.w	8f22 <_start\+0x22>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f4ff aff0 	bcc\.w	8f22 <_start\+0x22>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f4ff affc 	bcc\.w	8f42 <_start\+0x42>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f4ff aff8 	bcc\.w	8f42 <_start\+0x42>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f4ff aff4 	bcc\.w	8f42 <_start\+0x42>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f4ff aff0 	bcc\.w	8f42 <_start\+0x42>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f4ff affc 	bcc\.w	8f62 <_start\+0x62>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f4ff aff8 	bcc\.w	8f62 <_start\+0x62>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f4ff aff4 	bcc\.w	8f62 <_start\+0x62>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f4ff aff0 	bcc\.w	8f62 <_start\+0x62>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f4ff affc 	bcc\.w	8f82 <_start\+0x82>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f4ff aff8 	bcc\.w	8f82 <_start\+0x82>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f4ff aff4 	bcc\.w	8f82 <_start\+0x82>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f4ff aff0 	bcc\.w	8f82 <_start\+0x82>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f4ff affc 	bcc\.w	8fa2 <_start\+0xa2>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f4ff aff8 	bcc\.w	8fa2 <_start\+0xa2>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f4ff aff4 	bcc\.w	8fa2 <_start\+0xa2>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f4ff aff0 	bcc\.w	8fa2 <_start\+0xa2>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f4ff affc 	bcc\.w	8fc2 <_start\+0xc2>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f4ff aff8 	bcc\.w	8fc2 <_start\+0xc2>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f4ff aff4 	bcc\.w	8fc2 <_start\+0xc2>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f4ff aff0 	bcc\.w	8fc2 <_start\+0xc2>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f4ff affc 	bcc\.w	8fe2 <_start\+0xe2>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f4ff aff8 	bcc\.w	8fe2 <_start\+0xe2>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f4ff aff4 	bcc\.w	8fe2 <_start\+0xe2>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 b803 	b\.w	9008 <_start\+0x108>
+    9002:	4770      	bx	lr
+    9004:	f3af 8000 	nop\.w
+    9008:	d301      	bcc\.n	900e <_start\+0x10e>
+    900a:	f7ff bffa 	b\.w	9002 <_start\+0x102>
+    900e:	f7ff bfe8 	b\.w	8fe2 <_start\+0xe2>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bcc.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,39 @@
+	.syntax unified
+	.cpu cortex-a8
+	.thumb
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+1:
+        add.w r0, r1, r2
+        bcc.w 1b
+        add.w r0, r1, r2
+        bcc.w 1b
+        add.w r0, r1, r2
+        bcc.w 1b
+        add.w r0, r1, r2
+        bcc.w 1b
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+        .align  3
+        .global _start
+        .thumb
+        .thumb_func
+        .type   _start, %function
+_start:
+        nop
+
+	@ Trigger Cortex-A8 erratum workaround with conditional branches.
+        bw2
+        bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bl.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,75 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <_start>:
+    8f00:	bf00      	nop
+    8f02:	eb01 0002 	add\.w	r0, r1, r2
+    8f06:	f7ff fffc 	bl	8f02 <_start\+0x2>
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff fff8 	bl	8f02 <_start\+0x2>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff fff4 	bl	8f02 <_start\+0x2>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff fff0 	bl	8f02 <_start\+0x2>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff fffc 	bl	8f22 <_start\+0x22>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff fff8 	bl	8f22 <_start\+0x22>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff fff4 	bl	8f22 <_start\+0x22>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff fff0 	bl	8f22 <_start\+0x22>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff fffc 	bl	8f42 <_start\+0x42>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff fff8 	bl	8f42 <_start\+0x42>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff fff4 	bl	8f42 <_start\+0x42>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff fff0 	bl	8f42 <_start\+0x42>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff fffc 	bl	8f62 <_start\+0x62>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff fff8 	bl	8f62 <_start\+0x62>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff fff4 	bl	8f62 <_start\+0x62>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff fff0 	bl	8f62 <_start\+0x62>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff fffc 	bl	8f82 <_start\+0x82>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff fff8 	bl	8f82 <_start\+0x82>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff fff4 	bl	8f82 <_start\+0x82>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff fff0 	bl	8f82 <_start\+0x82>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff fffc 	bl	8fa2 <_start\+0xa2>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff fff8 	bl	8fa2 <_start\+0xa2>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff fff4 	bl	8fa2 <_start\+0xa2>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff fff0 	bl	8fa2 <_start\+0xa2>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff fffc 	bl	8fc2 <_start\+0xc2>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff fff8 	bl	8fc2 <_start\+0xc2>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff fff4 	bl	8fc2 <_start\+0xc2>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff fff0 	bl	8fc2 <_start\+0xc2>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff fffc 	bl	8fe2 <_start\+0xe2>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff fff8 	bl	8fe2 <_start\+0xe2>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff fff4 	bl	8fe2 <_start\+0xe2>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 f803 	bl	9008 <_start\+0x108>
+    9002:	4770      	bx	lr
+    9004:	f3af 8000 	nop\.w
+    9008:	f7ff bfeb 	b\.w	8fe2 <_start\+0xe2>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bl.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,39 @@
+	.syntax unified
+	.cpu cortex-a8
+	.thumb
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+1:
+        add.w r0, r1, r2
+        bl.w 1b
+        add.w r0, r1, r2
+        bl.w 1b
+        add.w r0, r1, r2
+        bl.w 1b
+        add.w r0, r1, r2
+        bl.w 1b
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+        .align  3
+        .global _start
+        .thumb
+        .thumb_func
+        .type   _start, %function
+_start:
+        nop
+
+	@ Trigger Cortex-A8 erratum workaround with bl instructions.
+        bw2
+        bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-blx.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,79 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <armfn>:
+    8f00:	e1a02413 	lsl	r2, r3, r4
+    8f04:	e12fff1e 	bx	lr
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff eff8 	blx	8f00 <armfn>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff eff4 	blx	8f00 <armfn>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff eff0 	blx	8f00 <armfn>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff efec 	blx	8f00 <armfn>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff efe8 	blx	8f00 <armfn>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff efe4 	blx	8f00 <armfn>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff efe0 	blx	8f00 <armfn>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff efdc 	blx	8f00 <armfn>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff efd8 	blx	8f00 <armfn>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff efd4 	blx	8f00 <armfn>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff efd0 	blx	8f00 <armfn>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff efcc 	blx	8f00 <armfn>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff efc8 	blx	8f00 <armfn>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff efc4 	blx	8f00 <armfn>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff efc0 	blx	8f00 <armfn>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff efbc 	blx	8f00 <armfn>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff efb8 	blx	8f00 <armfn>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff efb4 	blx	8f00 <armfn>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff efb0 	blx	8f00 <armfn>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff efac 	blx	8f00 <armfn>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff efa8 	blx	8f00 <armfn>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff efa4 	blx	8f00 <armfn>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff efa0 	blx	8f00 <armfn>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff ef9c 	blx	8f00 <armfn>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff ef98 	blx	8f00 <armfn>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff ef94 	blx	8f00 <armfn>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff ef90 	blx	8f00 <armfn>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff ef8c 	blx	8f00 <armfn>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff ef88 	blx	8f00 <armfn>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff ef84 	blx	8f00 <armfn>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 e808 	blx	9010 <_start\+0x108>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f7ff ef7c 	blx	8f00 <armfn>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+    9010:	eaffffba 	b	8f00 <armfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-blx.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,44 @@
+	.syntax unified
+	.cpu cortex-a8
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+        add.w r0, r1, r2
+        blx.w armfn
+        add.w r0, r1, r2
+        blx.w armfn
+        add.w r0, r1, r2
+        blx.w armfn
+        add.w r0, r1, r2
+        blx.w armfn
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+	.arm
+        .align  2
+armfn:
+	mov	r2, r3, asl r4
+	bx	lr
+
+        .global _start
+
+	.thumb
+        .thumb_func
+	.align 3
+        .type   _start, %function
+_start:
+        nop
+
+	@ Trigger Cortex-A8 erratum workaround with blx instructions.
+        bw2
+        bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-arm-target.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,9 @@
+	.syntax unified
+	.cpu cortex-a8
+	.text
+	.arm
+	.align 3
+	.global targetfn
+	.type targetfn, %function
+targetfn:
+	bx lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-b-rel-arm.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,83 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <targetfn>:
+    8f00:	e12fff1e 	bx	lr
+    8f04:	e320f000 	nop	\{0\}
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f000 b87f 	b\.w	9010 <__targetfn_from_thumb>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f000 b87b 	b\.w	9010 <__targetfn_from_thumb>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f000 b877 	b\.w	9010 <__targetfn_from_thumb>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f000 b873 	b\.w	9010 <__targetfn_from_thumb>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f000 b86f 	b\.w	9010 <__targetfn_from_thumb>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f000 b86b 	b\.w	9010 <__targetfn_from_thumb>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f000 b867 	b\.w	9010 <__targetfn_from_thumb>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f000 b863 	b\.w	9010 <__targetfn_from_thumb>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f000 b85f 	b\.w	9010 <__targetfn_from_thumb>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f000 b85b 	b\.w	9010 <__targetfn_from_thumb>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f000 b857 	b\.w	9010 <__targetfn_from_thumb>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f000 b853 	b\.w	9010 <__targetfn_from_thumb>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f000 b84f 	b\.w	9010 <__targetfn_from_thumb>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f000 b84b 	b\.w	9010 <__targetfn_from_thumb>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f000 b847 	b\.w	9010 <__targetfn_from_thumb>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f000 b843 	b\.w	9010 <__targetfn_from_thumb>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f000 b83f 	b\.w	9010 <__targetfn_from_thumb>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f000 b83b 	b\.w	9010 <__targetfn_from_thumb>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f000 b837 	b\.w	9010 <__targetfn_from_thumb>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f000 b833 	b\.w	9010 <__targetfn_from_thumb>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f000 b82f 	b\.w	9010 <__targetfn_from_thumb>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f000 b82b 	b\.w	9010 <__targetfn_from_thumb>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f000 b827 	b\.w	9010 <__targetfn_from_thumb>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f000 b823 	b\.w	9010 <__targetfn_from_thumb>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f000 b81f 	b\.w	9010 <__targetfn_from_thumb>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f000 b81b 	b\.w	9010 <__targetfn_from_thumb>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f000 b817 	b\.w	9010 <__targetfn_from_thumb>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f000 b813 	b\.w	9010 <__targetfn_from_thumb>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f000 b80f 	b\.w	9010 <__targetfn_from_thumb>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f000 b80b 	b\.w	9010 <__targetfn_from_thumb>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 b807 	b\.w	9010 <__targetfn_from_thumb>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f000 b803 	b\.w	9010 <__targetfn_from_thumb>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+
+00009010 <__targetfn_from_thumb>:
+    9010:	4778      	bx	pc
+    9012:	46c0      	nop			\(mov r8, r8\)
+    9014:	eaffffb9 	b	8f00 <targetfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-b-rel-thumb.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,80 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <targetfn>:
+    8f00:	4770      	bx	lr
+    8f02:	bf00      	nop
+    8f04:	f3af 8000 	nop\.w
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff bff7 	b\.w	8f00 <targetfn>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff bff3 	b\.w	8f00 <targetfn>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff bfef 	b\.w	8f00 <targetfn>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff bfeb 	b\.w	8f00 <targetfn>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff bfe7 	b\.w	8f00 <targetfn>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff bfe3 	b\.w	8f00 <targetfn>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff bfdf 	b\.w	8f00 <targetfn>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff bfdb 	b\.w	8f00 <targetfn>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff bfd7 	b\.w	8f00 <targetfn>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff bfd3 	b\.w	8f00 <targetfn>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff bfcf 	b\.w	8f00 <targetfn>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff bfcb 	b\.w	8f00 <targetfn>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff bfc7 	b\.w	8f00 <targetfn>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff bfc3 	b\.w	8f00 <targetfn>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff bfbf 	b\.w	8f00 <targetfn>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff bfbb 	b\.w	8f00 <targetfn>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff bfb7 	b\.w	8f00 <targetfn>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff bfb3 	b\.w	8f00 <targetfn>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff bfaf 	b\.w	8f00 <targetfn>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff bfab 	b\.w	8f00 <targetfn>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff bfa7 	b\.w	8f00 <targetfn>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff bfa3 	b\.w	8f00 <targetfn>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff bf9f 	b\.w	8f00 <targetfn>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff bf9b 	b\.w	8f00 <targetfn>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff bf97 	b\.w	8f00 <targetfn>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff bf93 	b\.w	8f00 <targetfn>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff bf8f 	b\.w	8f00 <targetfn>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff bf8b 	b\.w	8f00 <targetfn>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff bf87 	b\.w	8f00 <targetfn>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff bf83 	b\.w	8f00 <targetfn>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 b807 	b\.w	9010 <_start\+0x108>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f7ff bf7b 	b\.w	8f00 <targetfn>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+    9010:	f7ff bf76 	b\.w	8f00 <targetfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-b-rel.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,41 @@
+	.syntax unified
+	.cpu cortex-a8
+	.thumb
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+1:
+        add.w r0, r1, r2
+        b.w targetfn
+        add.w r0, r1, r2
+        b.w targetfn
+        add.w r0, r1, r2
+        b.w targetfn
+        add.w r0, r1, r2
+        b.w targetfn
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+        .align  3
+        .global _start
+        .thumb
+        .thumb_func
+        .type   _start, %function
+_start:
+	nop
+
+	@ If branching to an ARM destination, we *don't* want to create a
+	@ Cortex-A8 stub: the Thumb-to-ARM stub will suffice (and we need it
+	@ to change mode).
+	bw2
+	bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel-thumb.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,82 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <targetfn>:
+    8f00:	4770      	bx	lr
+    8f02:	bf00      	nop
+    8f04:	f3af 8000 	nop\.w
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f53f aff7 	bmi\.w	8f00 <targetfn>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f53f aff3 	bmi\.w	8f00 <targetfn>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f53f afef 	bmi\.w	8f00 <targetfn>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f53f afeb 	bmi\.w	8f00 <targetfn>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f53f afe7 	bmi\.w	8f00 <targetfn>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f53f afe3 	bmi\.w	8f00 <targetfn>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f53f afdf 	bmi\.w	8f00 <targetfn>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f53f afdb 	bmi\.w	8f00 <targetfn>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f53f afd7 	bmi\.w	8f00 <targetfn>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f53f afd3 	bmi\.w	8f00 <targetfn>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f53f afcf 	bmi\.w	8f00 <targetfn>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f53f afcb 	bmi\.w	8f00 <targetfn>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f53f afc7 	bmi\.w	8f00 <targetfn>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f53f afc3 	bmi\.w	8f00 <targetfn>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f53f afbf 	bmi\.w	8f00 <targetfn>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f53f afbb 	bmi\.w	8f00 <targetfn>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f53f afb7 	bmi\.w	8f00 <targetfn>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f53f afb3 	bmi\.w	8f00 <targetfn>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f53f afaf 	bmi\.w	8f00 <targetfn>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f53f afab 	bmi\.w	8f00 <targetfn>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f53f afa7 	bmi\.w	8f00 <targetfn>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f53f afa3 	bmi\.w	8f00 <targetfn>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f53f af9f 	bmi\.w	8f00 <targetfn>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f53f af9b 	bmi\.w	8f00 <targetfn>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f53f af97 	bmi\.w	8f00 <targetfn>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f53f af93 	bmi\.w	8f00 <targetfn>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f53f af8f 	bmi\.w	8f00 <targetfn>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f53f af8b 	bmi\.w	8f00 <targetfn>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f53f af87 	bmi\.w	8f00 <targetfn>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f53f af83 	bmi\.w	8f00 <targetfn>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 b807 	b\.w	9010 <_start\+0x108>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f53f af7b 	bmi\.w	8f00 <targetfn>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+    9010:	d401      	bmi\.n	9016 <_start\+0x10e>
+    9012:	f7ff bff6 	b\.w	9002 <_start\+0xfa>
+    9016:	f7ff bf73 	b\.w	8f00 <targetfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,38 @@
+	.syntax unified
+	.cpu cortex-a8
+	.thumb
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+1:
+        add.w r0, r1, r2
+        bmi.w targetfn
+        add.w r0, r1, r2
+        bmi.w targetfn
+        add.w r0, r1, r2
+        bmi.w targetfn
+        add.w r0, r1, r2
+        bmi.w targetfn
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+        .align  3
+        .global _start
+        .thumb
+        .thumb_func
+        .type   _start, %function
+_start:
+	nop
+
+	bw2
+	bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-arm.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,79 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <targetfn>:
+    8f00:	e12fff1e 	bx	lr
+    8f04:	e320f000 	nop	\{0\}
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff eff8 	blx	8f00 <targetfn>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff eff4 	blx	8f00 <targetfn>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff eff0 	blx	8f00 <targetfn>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff efec 	blx	8f00 <targetfn>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff efe8 	blx	8f00 <targetfn>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff efe4 	blx	8f00 <targetfn>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff efe0 	blx	8f00 <targetfn>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff efdc 	blx	8f00 <targetfn>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff efd8 	blx	8f00 <targetfn>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff efd4 	blx	8f00 <targetfn>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff efd0 	blx	8f00 <targetfn>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff efcc 	blx	8f00 <targetfn>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff efc8 	blx	8f00 <targetfn>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff efc4 	blx	8f00 <targetfn>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff efc0 	blx	8f00 <targetfn>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff efbc 	blx	8f00 <targetfn>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff efb8 	blx	8f00 <targetfn>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff efb4 	blx	8f00 <targetfn>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff efb0 	blx	8f00 <targetfn>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff efac 	blx	8f00 <targetfn>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff efa8 	blx	8f00 <targetfn>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff efa4 	blx	8f00 <targetfn>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff efa0 	blx	8f00 <targetfn>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff ef9c 	blx	8f00 <targetfn>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff ef98 	blx	8f00 <targetfn>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff ef94 	blx	8f00 <targetfn>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff ef90 	blx	8f00 <targetfn>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff ef8c 	blx	8f00 <targetfn>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff ef88 	blx	8f00 <targetfn>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff ef84 	blx	8f00 <targetfn>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 e808 	blx	9010 <_start\+0x108>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f7ff ef7c 	blx	8f00 <targetfn>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+    9010:	eaffffba 	b	8f00 <targetfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-thumb.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,80 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <targetfn>:
+    8f00:	4770      	bx	lr
+    8f02:	bf00      	nop
+    8f04:	f3af 8000 	nop\.w
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff fff7 	bl	8f00 <targetfn>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff fff3 	bl	8f00 <targetfn>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff ffef 	bl	8f00 <targetfn>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff ffeb 	bl	8f00 <targetfn>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff ffe7 	bl	8f00 <targetfn>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff ffe3 	bl	8f00 <targetfn>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff ffdf 	bl	8f00 <targetfn>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff ffdb 	bl	8f00 <targetfn>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff ffd7 	bl	8f00 <targetfn>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff ffd3 	bl	8f00 <targetfn>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff ffcf 	bl	8f00 <targetfn>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff ffcb 	bl	8f00 <targetfn>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff ffc7 	bl	8f00 <targetfn>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff ffc3 	bl	8f00 <targetfn>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff ffbf 	bl	8f00 <targetfn>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff ffbb 	bl	8f00 <targetfn>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff ffb7 	bl	8f00 <targetfn>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff ffb3 	bl	8f00 <targetfn>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff ffaf 	bl	8f00 <targetfn>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff ffab 	bl	8f00 <targetfn>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff ffa7 	bl	8f00 <targetfn>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff ffa3 	bl	8f00 <targetfn>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff ff9f 	bl	8f00 <targetfn>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff ff9b 	bl	8f00 <targetfn>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff ff97 	bl	8f00 <targetfn>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff ff93 	bl	8f00 <targetfn>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff ff8f 	bl	8f00 <targetfn>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff ff8b 	bl	8f00 <targetfn>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff ff87 	bl	8f00 <targetfn>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff ff83 	bl	8f00 <targetfn>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 f807 	bl	9010 <_start\+0x108>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f7ff ff7b 	bl	8f00 <targetfn>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+    9010:	f7ff bf76 	b\.w	8f00 <targetfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-bl-rel.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,40 @@
+	.syntax unified
+	.cpu cortex-a8
+	.thumb
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+1:
+        add.w r0, r1, r2
+        bl.w targetfn
+        add.w r0, r1, r2
+        bl.w targetfn
+        add.w r0, r1, r2
+        bl.w targetfn
+        add.w r0, r1, r2
+        bl.w targetfn
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+        .align  3
+        .global _start
+        .thumb
+        .thumb_func
+        .type   _start, %function
+_start:
+	nop
+
+	@ If calling an ARM destination, we *don't* want to create a
+	@ Cortex-A8 stub: the Thumb-to-ARM stub will suffice.
+	bw2
+	bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-arm.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,79 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <targetfn>:
+    8f00:	e12fff1e 	bx	lr
+    8f04:	e320f000 	nop	\{0\}
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff eff8 	blx	8f00 <targetfn>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff eff4 	blx	8f00 <targetfn>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff eff0 	blx	8f00 <targetfn>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff efec 	blx	8f00 <targetfn>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff efe8 	blx	8f00 <targetfn>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff efe4 	blx	8f00 <targetfn>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff efe0 	blx	8f00 <targetfn>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff efdc 	blx	8f00 <targetfn>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff efd8 	blx	8f00 <targetfn>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff efd4 	blx	8f00 <targetfn>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff efd0 	blx	8f00 <targetfn>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff efcc 	blx	8f00 <targetfn>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff efc8 	blx	8f00 <targetfn>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff efc4 	blx	8f00 <targetfn>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff efc0 	blx	8f00 <targetfn>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff efbc 	blx	8f00 <targetfn>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff efb8 	blx	8f00 <targetfn>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff efb4 	blx	8f00 <targetfn>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff efb0 	blx	8f00 <targetfn>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff efac 	blx	8f00 <targetfn>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff efa8 	blx	8f00 <targetfn>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff efa4 	blx	8f00 <targetfn>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff efa0 	blx	8f00 <targetfn>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff ef9c 	blx	8f00 <targetfn>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff ef98 	blx	8f00 <targetfn>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff ef94 	blx	8f00 <targetfn>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff ef90 	blx	8f00 <targetfn>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff ef8c 	blx	8f00 <targetfn>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff ef88 	blx	8f00 <targetfn>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff ef84 	blx	8f00 <targetfn>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 e808 	blx	9010 <_start\+0x108>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f7ff ef7c 	blx	8f00 <targetfn>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+    9010:	eaffffba 	b	8f00 <targetfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-thumb.d	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,80 @@
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+00008f00 <targetfn>:
+    8f00:	4770      	bx	lr
+    8f02:	bf00      	nop
+    8f04:	f3af 8000 	nop\.w
+
+00008f08 <_start>:
+    8f08:	bf00      	nop
+    8f0a:	eb01 0002 	add\.w	r0, r1, r2
+    8f0e:	f7ff fff7 	bl	8f00 <targetfn>
+    8f12:	eb01 0002 	add\.w	r0, r1, r2
+    8f16:	f7ff fff3 	bl	8f00 <targetfn>
+    8f1a:	eb01 0002 	add\.w	r0, r1, r2
+    8f1e:	f7ff ffef 	bl	8f00 <targetfn>
+    8f22:	eb01 0002 	add\.w	r0, r1, r2
+    8f26:	f7ff ffeb 	bl	8f00 <targetfn>
+    8f2a:	eb01 0002 	add\.w	r0, r1, r2
+    8f2e:	f7ff ffe7 	bl	8f00 <targetfn>
+    8f32:	eb01 0002 	add\.w	r0, r1, r2
+    8f36:	f7ff ffe3 	bl	8f00 <targetfn>
+    8f3a:	eb01 0002 	add\.w	r0, r1, r2
+    8f3e:	f7ff ffdf 	bl	8f00 <targetfn>
+    8f42:	eb01 0002 	add\.w	r0, r1, r2
+    8f46:	f7ff ffdb 	bl	8f00 <targetfn>
+    8f4a:	eb01 0002 	add\.w	r0, r1, r2
+    8f4e:	f7ff ffd7 	bl	8f00 <targetfn>
+    8f52:	eb01 0002 	add\.w	r0, r1, r2
+    8f56:	f7ff ffd3 	bl	8f00 <targetfn>
+    8f5a:	eb01 0002 	add\.w	r0, r1, r2
+    8f5e:	f7ff ffcf 	bl	8f00 <targetfn>
+    8f62:	eb01 0002 	add\.w	r0, r1, r2
+    8f66:	f7ff ffcb 	bl	8f00 <targetfn>
+    8f6a:	eb01 0002 	add\.w	r0, r1, r2
+    8f6e:	f7ff ffc7 	bl	8f00 <targetfn>
+    8f72:	eb01 0002 	add\.w	r0, r1, r2
+    8f76:	f7ff ffc3 	bl	8f00 <targetfn>
+    8f7a:	eb01 0002 	add\.w	r0, r1, r2
+    8f7e:	f7ff ffbf 	bl	8f00 <targetfn>
+    8f82:	eb01 0002 	add\.w	r0, r1, r2
+    8f86:	f7ff ffbb 	bl	8f00 <targetfn>
+    8f8a:	eb01 0002 	add\.w	r0, r1, r2
+    8f8e:	f7ff ffb7 	bl	8f00 <targetfn>
+    8f92:	eb01 0002 	add\.w	r0, r1, r2
+    8f96:	f7ff ffb3 	bl	8f00 <targetfn>
+    8f9a:	eb01 0002 	add\.w	r0, r1, r2
+    8f9e:	f7ff ffaf 	bl	8f00 <targetfn>
+    8fa2:	eb01 0002 	add\.w	r0, r1, r2
+    8fa6:	f7ff ffab 	bl	8f00 <targetfn>
+    8faa:	eb01 0002 	add\.w	r0, r1, r2
+    8fae:	f7ff ffa7 	bl	8f00 <targetfn>
+    8fb2:	eb01 0002 	add\.w	r0, r1, r2
+    8fb6:	f7ff ffa3 	bl	8f00 <targetfn>
+    8fba:	eb01 0002 	add\.w	r0, r1, r2
+    8fbe:	f7ff ff9f 	bl	8f00 <targetfn>
+    8fc2:	eb01 0002 	add\.w	r0, r1, r2
+    8fc6:	f7ff ff9b 	bl	8f00 <targetfn>
+    8fca:	eb01 0002 	add\.w	r0, r1, r2
+    8fce:	f7ff ff97 	bl	8f00 <targetfn>
+    8fd2:	eb01 0002 	add\.w	r0, r1, r2
+    8fd6:	f7ff ff93 	bl	8f00 <targetfn>
+    8fda:	eb01 0002 	add\.w	r0, r1, r2
+    8fde:	f7ff ff8f 	bl	8f00 <targetfn>
+    8fe2:	eb01 0002 	add\.w	r0, r1, r2
+    8fe6:	f7ff ff8b 	bl	8f00 <targetfn>
+    8fea:	eb01 0002 	add\.w	r0, r1, r2
+    8fee:	f7ff ff87 	bl	8f00 <targetfn>
+    8ff2:	eb01 0002 	add\.w	r0, r1, r2
+    8ff6:	f7ff ff83 	bl	8f00 <targetfn>
+    8ffa:	eb01 0002 	add\.w	r0, r1, r2
+    8ffe:	f000 f807 	bl	9010 <_start\+0x108>
+    9002:	eb01 0002 	add\.w	r0, r1, r2
+    9006:	f7ff ff7b 	bl	8f00 <targetfn>
+    900a:	4770      	bx	lr
+    900c:	f3af 8000 	nop\.w
+    9010:	f7ff bf76 	b\.w	8f00 <targetfn>
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-fix-blx-rel.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,38 @@
+	.syntax unified
+	.cpu cortex-a8
+	.thumb
+	.text
+
+	@ expansion 32 bytes
+        .macro bw1
+1:
+        add.w r0, r1, r2
+        blx.w targetfn
+        add.w r0, r1, r2
+        blx.w targetfn
+        add.w r0, r1, r2
+        blx.w targetfn
+        add.w r0, r1, r2
+        blx.w targetfn
+        .endm
+
+        @ expansion 128 bytes
+        .macro bw2
+        bw1
+        bw1
+        bw1
+        bw1
+        .endm
+
+        .align  3
+        .global _start
+        .thumb
+        .thumb_func
+        .type   _start, %function
+_start:
+	nop
+
+	bw2
+	bw2
+
+        bx      lr
--- /dev/null	2007-05-10 18:31:20.000000000 -0700
+++ ld/testsuite/ld-arm/cortex-a8-thumb-target.s	2009-05-01 03:45:22.000000000 -0700
@@ -0,0 +1,10 @@
+	.syntax unified
+	.cpu cortex-a8
+	.text
+	.thumb
+	.thumb_func
+	.align 3
+	.global targetfn
+	.type targetfn, %function
+targetfn:
+	bx lr
--- .pc/cortex-a8-fix-3/ld/ld.texinfo	2009-05-01 03:22:19.000000000 -0700
+++ ld/ld.texinfo	2009-05-01 03:45:22.000000000 -0700
@@ -5858,6 +5858,13 @@ instructions into @code{bal} instruction
 target subroutine is a leaf routine (that is, the target subroutine does
 not itself call any subroutines).
 
+@cindex Cortex-A8 erratum workaround
+@kindex --fix-cortex-a8
+@kindex --no-fix-cortex-a8
+The @samp{--fix-cortex-a8} switch enables a link-time workaround for an erratum in certain Cortex-A8 processors.  The workaround is enabled by default if you are targeting the ARM v7-A architecture profile.  It can be enabled otherwise by specifying @samp{--fix-cortex-a8}, or disabled unconditionally by specifying @samp{--no-fix-cortex-a8}.
+
+The erratum only affects Thumb-2 code.  Please contact ARM for further details.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]