aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog35
-rw-r--r--bfd/bfd-in.h5
-rw-r--r--bfd/bfd-in2.h5
-rw-r--r--bfd/elf32-arm.c1037
-rw-r--r--ld/ChangeLog12
-rw-r--r--ld/emultempl/armelf.em19
-rw-r--r--ld/ld.texinfo7
-rw-r--r--ld/testsuite/ChangeLog25
-rw-r--r--ld/testsuite/ld-arm/arm-elf.exp44
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-arm-target.s9
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-b-rel-arm.d83
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-b-rel-thumb.d80
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-b-rel.s41
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-b.d75
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-b.s39
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel-thumb.d82
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel.s38
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bcc.d77
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bcc.s39
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-arm.d79
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-thumb.d80
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bl-rel.s40
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bl.d75
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-bl.s39
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-arm.d79
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-thumb.d80
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-blx-rel.s38
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-blx.d79
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-fix-blx.s44
-rw-r--r--ld/testsuite/ld-arm/cortex-a8-thumb-target.s10
30 files changed, 2271 insertions, 124 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 1e2f99c..6e5652f 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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".
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 34bd50e..9bd4e38 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -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 *);
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 9f0ff37..15135bd 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -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 *);
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 7c82966..2a2d461 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -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;
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 7e99916..0671b7f 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 2d63a63..de7fe68 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -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
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 2121725..fbda265 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -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
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 0df5dbc..1613b29 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -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.
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 4e8a933..de3628e 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -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
index 0000000..d5174c4
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-arm-target.s
@@ -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
index 0000000..0a2b0bd
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-b-rel-arm.d
@@ -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
index 0000000..60a254b
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-b-rel-thumb.d
@@ -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
index 0000000..3ec95ab
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-b-rel.s
@@ -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
index 0000000..b2d4481
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-b.d
@@ -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
index 0000000..c0f21ac
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-b.s
@@ -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
index 0000000..27a7fd4
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel-thumb.d
@@ -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
index 0000000..b7b9451
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bcc-rel.s
@@ -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
index 0000000..44b8110
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bcc.d
@@ -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
index 0000000..8a667a3
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bcc.s
@@ -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
index 0000000..fcb3bab
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-arm.d
@@ -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
index 0000000..8cbd3e0
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel-thumb.d
@@ -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
index 0000000..2d21bbf
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bl-rel.s
@@ -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
index 0000000..50dcd4f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bl.d
@@ -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
index 0000000..6e40fb8
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-bl.s
@@ -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
index 0000000..fcb3bab
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-arm.d
@@ -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
index 0000000..8cbd3e0
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel-thumb.d
@@ -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
index 0000000..efbfb4b
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-blx-rel.s
@@ -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
index 0000000..4805256
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-blx.d
@@ -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
index 0000000..5d74024
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-fix-blx.s
@@ -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
index 0000000..96c180f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cortex-a8-thumb-target.s
@@ -0,0 +1,10 @@
+ .syntax unified
+ .cpu cortex-a8
+ .text
+ .thumb
+ .thumb_func
+ .align 3
+ .global targetfn
+ .type targetfn, %function
+targetfn:
+ bx lr