ld/
authorJulian Brown <julian@codesourcery.com>
Fri, 22 May 2009 11:58:45 +0000 (11:58 +0000)
committerJulian Brown <julian@codesourcery.com>
Fri, 22 May 2009 11:58:45 +0000 (11:58 +0000)
    * 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.

30 files changed:
bfd/ChangeLog
bfd/bfd-in.h
bfd/bfd-in2.h
bfd/elf32-arm.c
ld/ChangeLog
ld/emultempl/armelf.em
ld/ld.texinfo
ld/testsuite/ChangeLog
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/cortex-a8-arm-target.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-b-rel-arm.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-b-rel-thumb.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-b-rel.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-b.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-b.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel-thumb.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bcc.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bcc.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-arm.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-thumb.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bl-rel.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bl.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-bl.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-arm.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-thumb.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-blx-rel.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-blx.d [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-fix-blx.s [new file with mode: 0644]
ld/testsuite/ld-arm/cortex-a8-thumb-target.s [new file with mode: 0644]

index 1e2f99c..6e5652f 100644 (file)
@@ -1,3 +1,38 @@
+2009-05-22  Julian Brown  <julian@codesourcery.com>
+
+       * 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.
+
 2009-05-22  Alan Modra  <amodra@bigpond.net.au>
 
        * Makefile.am: Run "make dep-am".
index 34bd50e..9bd4e38 100644 (file)
@@ -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_before_allocation
 
 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 *);
index 9f0ff37..15135bd 100644 (file)
@@ -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_before_allocation
 
 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 *);
index 7c82966..2a2d461 100644 (file)
@@ -2026,11 +2026,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
 {
@@ -2164,6 +2168,39 @@ static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] =
     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.  */
+  };
+
+static const insn_sequence elf32_arm_stub_a8_veneer_bl[] =
+  {
+    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,7 +2218,11 @@ static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] =
   DEF_STUB(long_branch_v4t_thumb_thumb_pic) \
   DEF_STUB(long_branch_v4t_arm_thumb_pic) \
   DEF_STUB(long_branch_v4t_thumb_arm_pic) \
-  DEF_STUB(long_branch_thumb_only_pic)
+  DEF_STUB(long_branch_thumb_only_pic) \
+  DEF_STUB(a8_veneer_b_cond) \
+  DEF_STUB(a8_veneer_b) \
+  DEF_STUB(a8_veneer_bl) \
+  DEF_STUB(a8_veneer_blx)
 
 #define DEF_STUB(x) arm_stub_##x,
 enum elf32_arm_stub_type {
@@ -2218,6 +2259,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.  */
@@ -2337,6 +2385,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
 
@@ -2468,6 +2544,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;
 
@@ -2486,6 +2568,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;
 
@@ -2825,6 +2910,7 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   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;
@@ -3214,17 +3300,16 @@ elf32_arm_get_stub_entry (const asection *input_section,
   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;
@@ -3252,6 +3337,28 @@ elf32_arm_add_stub (const char *stub_name,
        }
       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,
@@ -3297,10 +3404,16 @@ put_thumb_insn (struct elf32_arm_link_hash_table * htab,
     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;
@@ -3314,8 +3427,9 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   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;
@@ -3350,26 +3464,50 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
       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;
 
@@ -3389,40 +3527,72 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   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;
 
-  BFD_ASSERT((stub_entry->stub_type > arm_stub_none)
-            && stub_entry->stub_type < ARRAY_SIZE(stub_definitions));
-
-  template = stub_definitions[stub_entry->stub_type].template;
-  template_size = stub_definitions[stub_entry->stub_type].template_size;
+  template = stub_definitions[stub_type].template;
+  template_size = stub_definitions[stub_type].template_size;
 
   size = 0;
   for (i = 0; i < template_size; i++)
@@ -3434,9 +3604,7 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry,
          break;
 
        case ARM_TYPE:
-         size += 4;
-         break;
-
+       case THUMB32_TYPE:
        case DATA_TYPE:
          size += 4;
          break;
@@ -3447,6 +3615,37 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry,
        }
     }
 
+  if (stub_template)
+    *stub_template = template;
+
+  if (stub_template_size)
+    *stub_template_size = template_size;
+
+  return size;
+}
+
+/* As above, 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, size;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
+  htab = (struct elf32_arm_link_hash_table *) in_arg;
+
+  BFD_ASSERT((stub_entry->stub_type > arm_stub_none)
+            && stub_entry->stub_type < ARRAY_SIZE(stub_definitions));
+
+  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;
@@ -3663,6 +3862,290 @@ group_sections (struct elf32_arm_link_hash_table *htab,
 #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
@@ -3681,6 +4164,18 @@ 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, 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.  */
@@ -3692,6 +4187,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
@@ -3719,6 +4221,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++)
@@ -3727,6 +4231,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)
@@ -3775,6 +4281,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);
@@ -3792,6 +4299,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
                  if ((r_type != (unsigned int) R_ARM_CALL)
                      && (r_type != (unsigned int) R_ARM_THM_CALL)
                      && (r_type != (unsigned int) R_ARM_JUMP24)
+                     && (r_type != (unsigned int) R_ARM_THM_JUMP19)
+                     && (r_type != (unsigned int) R_ARM_THM_XPC22)
                      && (r_type != (unsigned int) R_ARM_THM_JUMP24)
                      && (r_type != (unsigned int) R_ARM_PLT32))
                    continue;
@@ -3892,81 +4401,146 @@ 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;
-
-                 /* 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;
-
-                 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;
-                   }
-
-                 stub_entry = elf32_arm_add_stub (stub_name, section, htab);
-                 if (stub_entry == 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;
-
-                 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)
+                 do
                    {
-                     free (stub_name);
-                     goto error_ret_free_internal;
-                   }
+                     /* 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;
+
+                     /* 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;
+
+                     /* We've either created a stub for this reloc already,
+                        or we are about to.  */
+                     created_stub = TRUE;
+
+                     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;
+                       }
 
-                 /* 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_entry = elf32_arm_add_stub (stub_name, section,
+                                                      htab);
+                     if (stub_entry == NULL)
+                       {
+                         free (stub_name);
+                         goto error_ret_free_internal;
+                       }
 
-                 stub_changed = TRUE;
+                      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;
+
+                      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;
+                       }
+
+                      /* 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;
 
@@ -3985,11 +4559,80 @@ 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;
 
  error_ret_free_local:
@@ -4807,6 +5450,28 @@ 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)
 {
@@ -5416,7 +6081,7 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
                                 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;
 
@@ -5438,6 +6103,7 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
   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;
@@ -12172,13 +12838,14 @@ arm_map_one_stub (struct bfd_hash_entry * gen_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;
       break;
     default:
       BFD_FAIL ();
-      return FALSE;
+      return 0;
     }
 
   prev_type = DATA_TYPE;
@@ -12192,6 +12859,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
          break;
 
        case THUMB16_TYPE:
+       case THUMB32_TYPE:
          sym_type = ARM_MAP_THUMB;
          break;
 
@@ -12214,6 +12882,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
       switch (template[i].type)
        {
        case ARM_TYPE:
+       case THUMB32_TYPE:
          size += 4;
          break;
 
@@ -12440,6 +13109,120 @@ copy_exidx_entry (bfd *output_bfd, bfd_byte *to, bfd_byte *from, bfd_vma offset)
   bfd_put_32 (output_bfd, second_word, to + 4);
 }
 
+/* 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.  */
 
@@ -12449,7 +13232,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;
@@ -12458,7 +13241,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.  */
@@ -12633,6 +13416,18 @@ elf32_arm_write_section (bfd *output_bfd,
       return TRUE;
     }
 
+  /* 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;
 
index 7e99916..0671b7f 100644 (file)
@@ -1,3 +1,15 @@
+2009-05-22  Julian Brown  <julian@codesourcery.com>
+
+       * 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.
+
 2009-05-22  Nathan Sidwell  <nathan@codesourcery.com>
 
        * ldlang.c (lang_check_section_addresses): Ignore non-loadable
index 2d63a63..de7fe68 100644 (file)
@@ -37,6 +37,7 @@ static char *target2_type = "${TARGET2_TYPE}";
 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)
@@ -458,7 +462,7 @@ arm_elf_create_output_section_statements (void)
                                   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,
@@ -520,6 +524,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
@@ -539,6 +545,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='
@@ -565,6 +573,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='
@@ -636,6 +645,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
index 2121725..fbda265 100644 (file)
@@ -5865,6 +5865,13 @@ instructions into @code{bal} instructions when it determines that the
 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 0df5dbc..1613b29 100644 (file)
@@ -1,3 +1,28 @@
+2009-05-22  Julian Brown  <julian@codesourcery.com>
+
+       * 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.
+
 2009-05-22  Nathan Sidwell  <nathan@codesourcery.com>
 
        * ld-scripts/rgn-at4.t: New.
index 4e8a933..de3628e 100644 (file)
@@ -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"}
diff --git a/ld/testsuite/ld-arm/cortex-a8-arm-target.s b/ld/testsuite/ld-arm/cortex-a8-arm-target.s
new file mode 100644 (file)
index 0000000..d5174c4
--- /dev/null
@@ -0,0 +1,9 @@
+       .syntax unified
+       .cpu cortex-a8
+       .text
+       .arm
+       .align 3
+       .global targetfn
+       .type targetfn, %function
+targetfn:
+       bx lr
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-b-rel-arm.d b/ld/testsuite/ld-arm/cortex-a8-fix-b-rel-arm.d
new file mode 100644 (file)
index 0000000..0a2b0bd
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-b-rel-thumb.d b/ld/testsuite/ld-arm/cortex-a8-fix-b-rel-thumb.d
new file mode 100644 (file)
index 0000000..60a254b
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-b-rel.s b/ld/testsuite/ld-arm/cortex-a8-fix-b-rel.s
new file mode 100644 (file)
index 0000000..3ec95ab
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-b.d b/ld/testsuite/ld-arm/cortex-a8-fix-b.d
new file mode 100644 (file)
index 0000000..b2d4481
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-b.s b/ld/testsuite/ld-arm/cortex-a8-fix-b.s
new file mode 100644 (file)
index 0000000..c0f21ac
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel-thumb.d b/ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel-thumb.d
new file mode 100644 (file)
index 0000000..27a7fd4
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel.s b/ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel.s
new file mode 100644 (file)
index 0000000..b7b9451
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bcc.d b/ld/testsuite/ld-arm/cortex-a8-fix-bcc.d
new file mode 100644 (file)
index 0000000..44b8110
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bcc.s b/ld/testsuite/ld-arm/cortex-a8-fix-bcc.s
new file mode 100644 (file)
index 0000000..8a667a3
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-arm.d b/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-arm.d
new file mode 100644 (file)
index 0000000..fcb3bab
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-thumb.d b/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-thumb.d
new file mode 100644 (file)
index 0000000..8cbd3e0
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel.s b/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel.s
new file mode 100644 (file)
index 0000000..2d21bbf
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bl.d b/ld/testsuite/ld-arm/cortex-a8-fix-bl.d
new file mode 100644 (file)
index 0000000..50dcd4f
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-bl.s b/ld/testsuite/ld-arm/cortex-a8-fix-bl.s
new file mode 100644 (file)
index 0000000..6e40fb8
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-arm.d b/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-arm.d
new file mode 100644 (file)
index 0000000..fcb3bab
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-thumb.d b/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-thumb.d
new file mode 100644 (file)
index 0000000..8cbd3e0
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel.s b/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel.s
new file mode 100644 (file)
index 0000000..efbfb4b
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-blx.d b/ld/testsuite/ld-arm/cortex-a8-fix-blx.d
new file mode 100644 (file)
index 0000000..4805256
--- /dev/null
@@ -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>
diff --git a/ld/testsuite/ld-arm/cortex-a8-fix-blx.s b/ld/testsuite/ld-arm/cortex-a8-fix-blx.s
new file mode 100644 (file)
index 0000000..5d74024
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/cortex-a8-thumb-target.s b/ld/testsuite/ld-arm/cortex-a8-thumb-target.s
new file mode 100644 (file)
index 0000000..96c180f
--- /dev/null
@@ -0,0 +1,10 @@
+       .syntax unified
+       .cpu cortex-a8
+       .text
+       .thumb
+       .thumb_func
+       .align 3
+       .global targetfn
+       .type targetfn, %function
+targetfn:
+       bx lr