[AArch64] Workaround for cortex-a53 erratum 843419
Marcus Shawcroft
marcus.shawcroft@arm.com
Tue Apr 7 15:05:00 GMT 2015
On 30/03/15 15:40, Marcus Shawcroft wrote:
> On 30/03/15 15:23, Marcus Shawcroft wrote:
>> Hi,
>>
>> Some early revisions of the Cortex-A53 have an erratum (843419). The
>> details of the erratum are quite complex and involve dynamic conditions.
>> For the purposes of the workaround we have simplified the static
>> conditions to an ADRP in the last two instructions of a 4KByte page,
>> followed within four instructions by a load/store dependent on the ADRP.
>
> In order to apply this patch to a binutils-2.25 tree the following
> prerequisite patches from trunk are also required (git hash, title, mail
> link):
Hi,
This set of patches applies to 2.24 with some minor tweaking. In
response to an off list request I thought it would be useful to share
the runes for 2.24.
The following back ported patches are required, in order:
8ef229f [AArch64] Removing unused functions.
https://sourceware.org/ml/binutils/2015-03/msg00033.html
e2cdef4 Remove dead code.
https://sourceware.org/ml/binutils/2015-03/msg00294.html
4c77202 [AArch64] Drop unused argument to
elf_aarch64_create_or_find_stub_sec
https://sourceware.org/ml/binutils/2015-03/msg00296.html
2144188 [AArch64] Flip sense of erratum_835769_scan.
https://sourceware.org/ml/binutils/2015-03/msg00297.html
ef85752 [AArch64] Factor out common behaviour between
elf_aarch64_create_or_find_stub_sec and elfNN_aarch64_add_stub
https://sourceware.org/ml/binutils/2015-03/msg00298.html
6658567 [AArch64] Factor stub creation code into
_bfd_aarch64_create_stub_section.
https://sourceware.org/ml/binutils/2015-03/msg00299.html
13f622e [AArch64] Factor out _bfd_aarch64_resize_stubs()
https://sourceware.org/ml/binutils/2015-03/msg00300.html
35fee8b Factor out _bfd_aarch64_erratum_835769_stub_name
https://sourceware.org/ml/binutils/2015-03/msg00302.html
c53ed7c [OBV] Fix build -- missing ';'
https://sourceware.org/ml/binutils/2015-03/msg00304.html
e572930 [AArch64] Use _bfd_aarch64_add_stub_entry_in_group.
https://sourceware.org/ml/binutils/2015-03/msg00323.html
The follow patch is required but requires some minor adjustment to cope
with a change in the representation of section linked lists made between
2.24 and 2.25. A revised version of commit 5421cc5 is attached as
patch-1.txt.
5421cc6 [AArch64] Refactor generation of 835769 workaround stubs.
https://sourceware.org/ml/binutils/2015-03/msg00324.html
30068a6 [AArch64] Refactor section_group[] representation.
https://sourceware.org/ml/binutils/2015-03/msg00327.html
fc6d53b [AArch64] Factor out _bfd_aarch64_get_stub_for_link_section.
https://sourceware.org/ml/binutils/2015-03/msg00328.html
357d152 [AArch64] Adjust veneer count.
https://sourceware.org/ml/binutils/2015-03/msg00341.html
d9ced15 [AArch64] Remove padding before stub sections.
https://sourceware.org/ml/binutils/2015-03/msg00343.html
6186551 [AArch64] Implement branch over stub section.
https://sourceware.org/ml/binutils/2015-03/msg00344.html
The 843419 workaround patch itself requires some minor adjustment to
reflect the same linked list representation issue as above. A revised
version of the patch is attached as patch-2.txt.
The ChangeLog entries for the two revised patches remain unchanged from
the original submissions.
Cheers
/Marcus
-------------- next part --------------
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 6965926..3b7010f 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -1690,19 +1690,8 @@ _aarch64_elf_section_data;
#define elf_aarch64_section_data(sec) \
((_aarch64_elf_section_data *) elf_section_data (sec))
-/* A fix-descriptor for erratum 835769. */
-struct aarch64_erratum_835769_fix
-{
- bfd *input_bfd;
- asection *section;
- bfd_vma offset;
- uint32_t veneered_insn;
- char *stub_name;
- enum elf_aarch64_stub_type stub_type;
-};
-
-/* The size of the thread control block. */
-#define TCB_SIZE 16
+/* The size of the thread control block which is defined to be two pointers. */
+#define TCB_SIZE (ARCH_SIZE/8)*2
struct elf_aarch64_local_symbol
{
@@ -2999,17 +2988,13 @@ _bfd_aarch64_erratum_835769_stub_name (unsigned num_fixes)
Return TRUE else FALSE on abnormal termination. */
static bfd_boolean
-erratum_835769_scan (bfd *input_bfd,
- struct bfd_link_info *info,
- struct aarch64_erratum_835769_fix **fixes_p,
- unsigned int *num_fixes_p,
- unsigned int *fix_table_size_p)
+_bfd_aarch64_erratum_835769_scan (bfd *input_bfd,
+ struct bfd_link_info *info,
+ unsigned int *num_fixes_p)
{
asection *section;
struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
- struct aarch64_erratum_835769_fix *fixes = *fixes_p;
unsigned int num_fixes = *num_fixes_p;
- unsigned int fix_table_size = *fix_table_size_p;
if (htab == NULL)
return TRUE;
@@ -3058,28 +3043,22 @@ erratum_835769_scan (bfd *input_bfd,
if (aarch64_erratum_sequence (insn_1, insn_2))
{
+ struct elf_aarch64_stub_hash_entry *stub_entry;
char *stub_name = _bfd_aarch64_erratum_835769_stub_name (num_fixes);
if (! stub_name)
return FALSE;
- if (num_fixes == fix_table_size)
- {
- fix_table_size *= 2;
- fixes =
- (struct aarch64_erratum_835769_fix *)
- bfd_realloc (fixes,
- sizeof (struct aarch64_erratum_835769_fix)
- * fix_table_size);
- if (fixes == NULL)
- return FALSE;
- }
+ stub_entry = _bfd_aarch64_add_stub_entry_in_group (stub_name,
+ section,
+ htab);
+ if (! stub_entry)
+ return FALSE;
- fixes[num_fixes].input_bfd = input_bfd;
- fixes[num_fixes].section = section;
- fixes[num_fixes].offset = i + 4;
- fixes[num_fixes].veneered_insn = insn_2;
- fixes[num_fixes].stub_name = stub_name;
- fixes[num_fixes].stub_type = aarch64_stub_erratum_835769_veneer;
+ stub_entry->stub_type = aarch64_stub_erratum_835769_veneer;
+ stub_entry->target_section = section;
+ stub_entry->target_value = i + 4;
+ stub_entry->veneered_insn = insn_2;
+ stub_entry->output_name = stub_name;
num_fixes++;
}
}
@@ -3088,9 +3067,6 @@ erratum_835769_scan (bfd *input_bfd,
free (contents);
}
- *fixes_p = fixes;
- *num_fixes_p = num_fixes;
- *fix_table_size_p = fix_table_size;
return TRUE;
}
@@ -3134,23 +3110,9 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
{
bfd_size_type stub_group_size;
bfd_boolean stubs_always_before_branch;
- bfd_boolean stub_changed = 0;
+ bfd_boolean stub_changed = FALSE;
struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
- struct aarch64_erratum_835769_fix *erratum_835769_fixes = NULL;
unsigned int num_erratum_835769_fixes = 0;
- unsigned int erratum_835769_fix_table_size = 10;
- unsigned int i;
-
- if (htab->fix_erratum_835769)
- {
- erratum_835769_fixes
- = (struct aarch64_erratum_835769_fix *)
- bfd_zmalloc
- (sizeof (struct aarch64_erratum_835769_fix) *
- erratum_835769_fix_table_size);
- if (erratum_835769_fixes == NULL)
- goto error_ret_free_local;
- }
/* Propagate mach to stub bfd, because it may not have been
finalized when we created stub_bfd. */
@@ -3176,16 +3138,25 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
group_sections (htab, stub_group_size, stubs_always_before_branch);
+ if (htab->fix_erratum_835769)
+ {
+ bfd *input_bfd;
+
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL; input_bfd = input_bfd->link_next)
+ if (!_bfd_aarch64_erratum_835769_scan (input_bfd, info,
+ &num_erratum_835769_fixes))
+ return FALSE;
+
+ stub_changed = TRUE;
+ }
+
while (1)
{
bfd *input_bfd;
- unsigned int bfd_indx;
- asection *stub_sec;
- unsigned prev_num_erratum_835769_fixes = num_erratum_835769_fixes;
- num_erratum_835769_fixes = 0;
- for (input_bfd = info->input_bfds, bfd_indx = 0;
- input_bfd != NULL; input_bfd = input_bfd->link_next, bfd_indx++)
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL; input_bfd = input_bfd->link_next)
{
Elf_Internal_Shdr *symtab_hdr;
asection *section;
@@ -3436,66 +3407,18 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
if (elf_section_data (section)->relocs == NULL)
free (internal_relocs);
}
-
- if (htab->fix_erratum_835769)
- {
- /* Scan for sequences which might trigger erratum 835769. */
- if (!erratum_835769_scan (input_bfd, info, &erratum_835769_fixes,
- &num_erratum_835769_fixes,
- &erratum_835769_fix_table_size))
- goto error_ret_free_local;
- }
}
- if (prev_num_erratum_835769_fixes != num_erratum_835769_fixes)
- stub_changed = TRUE;
-
if (!stub_changed)
break;
_bfd_aarch64_resize_stubs (htab);
- /* Add erratum 835769 veneers to stub section sizes too. */
- if (htab->fix_erratum_835769)
- for (i = 0; i < num_erratum_835769_fixes; i++)
- {
- stub_sec = _bfd_aarch64_create_or_find_stub_sec
- (erratum_835769_fixes[i].section, htab);
-
- if (stub_sec == NULL)
- goto error_ret_free_local;
-
- stub_sec->size += 8;
- }
-
/* Ask the linker to do its stuff. */
(*htab->layout_sections_again) ();
stub_changed = FALSE;
}
- /* Add stubs for erratum 835769 fixes now. */
- if (htab->fix_erratum_835769)
- {
- for (i = 0; i < num_erratum_835769_fixes; i++)
- {
- struct elf_aarch64_stub_hash_entry *stub_entry;
- char *stub_name = erratum_835769_fixes[i].stub_name;
- asection *section = erratum_835769_fixes[i].section;
-
- stub_entry = _bfd_aarch64_add_stub_entry_in_group (stub_name,
- section,
- htab);
- if (! stub_entry)
- return FALSE;
-
- stub_entry->stub_type = erratum_835769_fixes[i].stub_type;
- stub_entry->target_section = section;
- stub_entry->target_value = erratum_835769_fixes[i].offset;
- stub_entry->veneered_insn = erratum_835769_fixes[i].veneered_insn;
- stub_entry->output_name = erratum_835769_fixes[i].stub_name;
- }
- }
-
return TRUE;
error_ret_free_local:
-------------- next part --------------
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 6a5c01c..1b67cb9 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -936,10 +936,10 @@ extern void bfd_elf32_aarch64_init_maps
(bfd *);
extern void bfd_elf64_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
extern void bfd_elf32_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
/* ELF AArch64 mapping symbol support. */
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0)
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index f83f6fd..6c6cbb2 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -943,10 +943,10 @@ extern void bfd_elf32_aarch64_init_maps
(bfd *);
extern void bfd_elf64_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
extern void bfd_elf32_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int);
/* ELF AArch64 mapping symbol support. */
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0)
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 5e469e0..89b5dc0 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -1617,6 +1617,12 @@ static const uint32_t aarch64_erratum_835769_stub[] =
0x14000000, /* b <label> */
};
+static const uint32_t aarch64_erratum_843419_stub[] =
+{
+ 0x00000000, /* Placeholder for LDR instruction. */
+ 0x14000000, /* b <label> */
+};
+
/* Section name for stubs is the associated section name plus this
string. */
#define STUB_SUFFIX ".stub"
@@ -1627,6 +1633,7 @@ enum elf_aarch64_stub_type
aarch64_stub_adrp_branch,
aarch64_stub_long_branch,
aarch64_stub_erratum_835769_veneer,
+ aarch64_stub_erratum_843419_veneer,
};
struct elf_aarch64_stub_hash_entry
@@ -1665,6 +1672,9 @@ struct elf_aarch64_stub_hash_entry
/* The instruction which caused this stub to be generated (only valid for
erratum 835769 workaround stubs at present). */
uint32_t veneered_insn;
+
+ /* In an erratum 843419 workaround stub, the ADRP instruction offset. */
+ bfd_vma adrp_offset;
};
/* Used to build a map of a section. This is required for mixed-endian
@@ -1813,6 +1823,12 @@ struct elf_aarch64_link_hash_table
/* Fix erratum 835769. */
int fix_erratum_835769;
+ /* Fix erratum 843419. */
+ int fix_erratum_843419;
+
+ /* Enable ADRP->ADR rewrite for erratum 843419 workaround. */
+ int fix_erratum_843419_adr;
+
/* The number of bytes in the initial entry in the PLT. */
bfd_size_type plt_header_size;
@@ -1934,6 +1950,7 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
/* Initialize the local fields. */
eh = (struct elf_aarch64_stub_hash_entry *) entry;
+ eh->adrp_offset = 0;
eh->stub_sec = NULL;
eh->stub_offset = 0;
eh->target_value = 0;
@@ -2375,6 +2392,34 @@ _bfd_aarch64_add_stub_entry_in_group (const char *stub_name,
return stub_entry;
}
+/* Add a new stub entry in the final stub section to the stub hash.
+ Not all fields of the new stub entry are initialised. */
+
+static struct elf_aarch64_stub_hash_entry *
+_bfd_aarch64_add_stub_entry_after (const char *stub_name,
+ asection *link_section,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ asection *stub_sec;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+
+ stub_sec = _bfd_aarch64_get_stub_for_link_section (link_section, htab);
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+ TRUE, FALSE);
+ if (stub_entry == NULL)
+ {
+ (*_bfd_error_handler) (_("cannot create stub entry %s"), stub_name);
+ return NULL;
+ }
+
+ stub_entry->stub_sec = stub_sec;
+ stub_entry->stub_offset = 0;
+ stub_entry->id_sec = link_section;
+
+ return stub_entry;
+}
+
+
static bfd_boolean
aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
void *in_arg ATTRIBUTE_UNUSED)
@@ -2431,6 +2476,10 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
template = aarch64_erratum_835769_stub;
template_size = sizeof (aarch64_erratum_835769_stub);
break;
+ case aarch64_stub_erratum_843419_veneer:
+ template = aarch64_erratum_843419_stub;
+ template_size = sizeof (aarch64_erratum_843419_stub);
+ break;
default:
BFD_FAIL ();
return FALSE;
@@ -2490,6 +2539,12 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
stub_sec->contents + stub_entry->stub_offset + 4);
break;
+ case aarch64_stub_erratum_843419_veneer:
+ if (aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value + 4))
+ BFD_FAIL ();
+ break;
+
default:
break;
}
@@ -2521,6 +2576,9 @@ aarch64_size_one_stub (struct bfd_hash_entry *gen_entry,
case aarch64_stub_erratum_835769_veneer:
size = sizeof (aarch64_erratum_835769_stub);
break;
+ case aarch64_stub_erratum_843419_veneer:
+ size = sizeof (aarch64_erratum_843419_stub);
+ break;
default:
BFD_FAIL ();
return FALSE;
@@ -2980,7 +3038,7 @@ _bfd_aarch64_erratum_835769_stub_name (unsigned num_fixes)
return stub_name;
}
-/* Scan for cortex-a53 erratum 835769 sequence.
+/* Scan for Cortex-A53 erratum 835769 sequence.
Return TRUE else FALSE on abnormal termination. */
@@ -3070,6 +3128,82 @@ _bfd_aarch64_erratum_835769_scan (bfd *input_bfd,
}
+/* Test if instruction INSN is ADRP. */
+
+static bfd_boolean
+_bfd_aarch64_adrp_p (uint32_t insn)
+{
+ return ((insn & 0x9f000000) == 0x90000000);
+}
+
+
+/* Helper predicate to look for cortex-a53 erratum 843419 sequence 1. */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_sequence_p (uint32_t insn_1, uint32_t insn_2,
+ uint32_t insn_3)
+{
+ uint32_t rt;
+ uint32_t rt2;
+ bfd_boolean pair;
+ bfd_boolean load;
+
+ return (aarch64_mem_op_p (insn_2, &rt, &rt2, &pair, &load)
+ && (!pair
+ || (pair && !load))
+ && AARCH64_LDST_UIMM (insn_3)
+ && AARCH64_RN (insn_3) == AARCH64_RD (insn_1));
+}
+
+
+/* Test for the presence of Cortex-A53 erratum 843419 instruction sequence.
+
+ Return TRUE if section CONTENTS at offset I contains one of the
+ erratum 843419 sequences, otherwise return FALSE. If a sequence is
+ seen set P_VENEER_I to the offset of the final LOAD/STORE
+ instruction in the sequence.
+ */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_p (bfd_byte *contents, bfd_vma vma,
+ bfd_vma i, bfd_vma span_end,
+ bfd_vma *p_veneer_i)
+{
+ uint32_t insn_1 = bfd_getl32 (contents + i);
+
+ if (!_bfd_aarch64_adrp_p (insn_1))
+ return FALSE;
+
+ if (span_end < i + 12)
+ return FALSE;
+
+ uint32_t insn_2 = bfd_getl32 (contents + i + 4);
+ uint32_t insn_3 = bfd_getl32 (contents + i + 8);
+
+ if ((vma & 0xfff) != 0xff8 && (vma & 0xfff) != 0xffc)
+ return FALSE;
+
+ if (_bfd_aarch64_erratum_843419_sequence_p (insn_1, insn_2, insn_3))
+ {
+ *p_veneer_i = i + 8;
+ return TRUE;
+ }
+
+ if (span_end < i + 16)
+ return FALSE;
+
+ uint32_t insn_4 = bfd_getl32 (contents + i + 12);
+
+ if (_bfd_aarch64_erratum_843419_sequence_p (insn_1, insn_2, insn_4))
+ {
+ *p_veneer_i = i + 12;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/* Resize all stub sections. */
static void
@@ -3098,9 +3232,174 @@ _bfd_aarch64_resize_stubs (struct elf_aarch64_link_hash_table *htab)
if (section->size)
section->size += 4;
+
+ /* Ensure all stub sections have a size which is a multiple of
+ 4096. This is important in order to ensure that the insertion
+ of stub sections does not in itself move existing code around
+ in such a way that new errata sequences are created. */
+ if (htab->fix_erratum_843419)
+ if (section->size)
+ section->size = BFD_ALIGN (section->size, 0x1000);
+ }
+}
+
+
+/* Construct an erratum 843419 workaround stub name.
+ */
+
+static char *
+_bfd_aarch64_erratum_843419_stub_name (asection *input_section,
+ bfd_vma offset)
+{
+ const bfd_size_type len = 8 + 4 + 1 + 8 + 1 + 16 + 1;
+ char *stub_name = bfd_malloc (len);
+
+ if (stub_name != NULL)
+ snprintf (stub_name, len, "e843419@%04x_%08x_%" BFD_VMA_FMT "x",
+ input_section->owner->id,
+ input_section->id,
+ offset);
+ return stub_name;
+}
+
+/* Build a stub_entry structure describing an 843419 fixup.
+
+ The stub_entry constructed is populated with the bit pattern INSN
+ of the instruction located at OFFSET within input SECTION.
+
+ Returns TRUE on success. */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_fixup (uint32_t insn,
+ bfd_vma adrp_offset,
+ bfd_vma ldst_offset,
+ asection *section,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+ char *stub_name;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+
+ stub_name = _bfd_aarch64_erratum_843419_stub_name (section, ldst_offset);
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+ FALSE, FALSE);
+ if (stub_entry)
+ {
+ free (stub_name);
+ return TRUE;
+ }
+
+ /* We always place an 843419 workaround veneer in the stub section
+ attached to the input section in which an erratum sequence has
+ been found. This ensures that later in the link process (in
+ elfNN_aarch64_write_section) when we copy the veneered
+ instruction from the input section into the stub section the
+ copied instruction will have had any relocations applied to it.
+ If we placed workaround veneers in any other stub section then we
+ could not assume that all relocations have been processed on the
+ corresponding input section at the point we output the stub
+ section.
+ */
+
+ stub_entry = _bfd_aarch64_add_stub_entry_after (stub_name, section, htab);
+ if (stub_entry == NULL)
+ {
+ free (stub_name);
+ return FALSE;
}
+
+ stub_entry->adrp_offset = adrp_offset;
+ stub_entry->target_value = ldst_offset;
+ stub_entry->target_section = section;
+ stub_entry->stub_type = aarch64_stub_erratum_843419_veneer;
+ stub_entry->veneered_insn = insn;
+ stub_entry->output_name = stub_name;
+
+ return TRUE;
}
+
+/* Scan an input section looking for the signature of erratum 843419.
+
+ Scans input SECTION in INPUT_BFD looking for erratum 843419
+ signatures, for each signature found a stub_entry is created
+ describing the location of the erratum for subsequent fixup.
+
+ Return TRUE on successful scan, FALSE on failure to scan.
+ */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_scan (bfd *input_bfd, asection *section,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+
+ if (htab == NULL)
+ return TRUE;
+
+ if (elf_section_type (section) != SHT_PROGBITS
+ || (elf_section_flags (section) & SHF_EXECINSTR) == 0
+ || (section->flags & SEC_EXCLUDE) != 0
+ || (section->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ || (section->output_section == bfd_abs_section_ptr))
+ return TRUE;
+
+ do
+ {
+ bfd_byte *contents = NULL;
+ struct _aarch64_elf_section_data *sec_data;
+ unsigned int span;
+
+ 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 FALSE;
+
+ sec_data = elf_aarch64_section_data (section);
+
+ qsort (sec_data->map, sec_data->mapcount,
+ sizeof (elf_aarch64_section_map), elf_aarch64_compare_mapping);
+
+ 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)
+ ? sec_data->map[0].vma + section->size
+ : sec_data->map[span + 1].vma);
+ unsigned int i;
+ char span_type = sec_data->map[span].type;
+
+ if (span_type == 'd')
+ continue;
+
+ for (i = span_start; i + 8 < span_end; i += 4)
+ {
+ bfd_vma vma = (section->output_section->vma
+ + section->output_offset
+ + i);
+ bfd_vma veneer_i;
+
+ if (_bfd_aarch64_erratum_843419_p
+ (contents, vma, i, span_end, &veneer_i))
+ {
+ uint32_t insn = bfd_getl32 (contents + veneer_i);
+
+ if (!_bfd_aarch64_erratum_843419_fixup (insn, i, veneer_i,
+ section, info))
+ return FALSE;
+ }
+ }
+ }
+
+ if (elf_section_data (section)->this_hdr.contents == NULL)
+ free (contents);
+ }
+ while (0);
+
+ return TRUE;
+}
+
+
/* 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
@@ -3146,6 +3445,8 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
group_sections (htab, stub_group_size, stubs_always_before_branch);
+ (*htab->layout_sections_again) ();
+
if (htab->fix_erratum_835769)
{
bfd *input_bfd;
@@ -3156,7 +3457,29 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
&num_erratum_835769_fixes))
return FALSE;
- stub_changed = TRUE;
+ _bfd_aarch64_resize_stubs (htab);
+ (*htab->layout_sections_again) ();
+ }
+
+ if (htab->fix_erratum_843419)
+ {
+ bfd *input_bfd;
+
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link_next)
+ {
+ asection *section;
+
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ if (!_bfd_aarch64_erratum_843419_scan (input_bfd, section, info))
+ return FALSE;
+ }
+
+ _bfd_aarch64_resize_stubs (htab);
+ (*htab->layout_sections_again) ();
}
while (1)
@@ -3561,13 +3884,16 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
struct bfd_link_info *link_info,
int no_enum_warn,
int no_wchar_warn, int pic_veneer,
- int fix_erratum_835769)
+ int fix_erratum_835769,
+ int fix_erratum_843419)
{
struct elf_aarch64_link_hash_table *globals;
globals = elf_aarch64_hash_table (link_info);
globals->pic_veneer = pic_veneer;
globals->fix_erratum_835769 = fix_erratum_835769;
+ globals->fix_erratum_843419 = fix_erratum_843419;
+ globals->fix_erratum_843419_adr = TRUE;
BFD_ASSERT (is_aarch64_elf (output_bfd));
elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
@@ -3882,6 +4208,7 @@ symbol_tlsdesc_got_offset (bfd *input_bfd, struct elf_link_hash_entry *h,
struct erratum_835769_branch_to_stub_data
{
+ struct bfd_link_info *info;
asection *output_section;
bfd_byte *contents;
};
@@ -3934,6 +4261,87 @@ make_branch_to_erratum_835769_stub (struct bfd_hash_entry *gen_entry,
return TRUE;
}
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry,
+ void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry
+ = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ struct erratum_835769_branch_to_stub_data *data
+ = (struct erratum_835769_branch_to_stub_data *) in_arg;
+ struct bfd_link_info *info;
+ struct elf_aarch64_link_hash_table *htab;
+ bfd_byte *contents;
+ asection *section;
+ bfd *abfd;
+ bfd_vma place;
+ uint32_t insn;
+
+ info = data->info;
+ contents = data->contents;
+ section = data->output_section;
+
+ htab = elf_aarch64_hash_table (info);
+
+ if (stub_entry->target_section != section
+ || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer)
+ return TRUE;
+
+ insn = bfd_getl32 (contents + stub_entry->target_value);
+ bfd_putl32 (insn,
+ stub_entry->stub_sec->contents + stub_entry->stub_offset);
+
+ place = (section->output_section->vma + section->output_offset
+ + stub_entry->adrp_offset);
+ insn = bfd_getl32 (contents + stub_entry->adrp_offset);
+
+ if ((insn & AARCH64_ADRP_OP_MASK) != AARCH64_ADRP_OP)
+ abort ();
+
+ bfd_signed_vma imm =
+ (_bfd_aarch64_sign_extend
+ ((bfd_vma) _bfd_aarch64_decode_adrp_imm (insn) << 12, 33)
+ - (place & 0xfff));
+
+ if (htab->fix_erratum_843419_adr
+ && (imm >= AARCH64_MIN_ADRP_IMM && imm <= AARCH64_MAX_ADRP_IMM))
+ {
+ insn = (_bfd_aarch64_reencode_adr_imm (AARCH64_ADR_OP, imm)
+ | AARCH64_RT (insn));
+ bfd_putl32 (insn, contents + stub_entry->adrp_offset);
+ }
+ else
+ {
+ bfd_vma veneered_insn_loc;
+ bfd_vma veneer_entry_loc;
+ bfd_signed_vma branch_offset;
+ uint32_t branch_insn;
+
+ 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;
+ branch_offset = veneer_entry_loc - veneered_insn_loc;
+
+ abfd = stub_entry->target_section->owner;
+ if (!aarch64_valid_branch_p (veneer_entry_loc, veneered_insn_loc))
+ (*_bfd_error_handler)
+ (_("%B: error: Erratum 843419 stub out "
+ "of range (input file too large)"), abfd);
+
+ branch_insn = 0x14000000;
+ branch_offset >>= 2;
+ branch_offset &= 0x3ffffff;
+ branch_insn |= branch_offset;
+ bfd_putl32 (branch_insn, contents + stub_entry->target_value);
+ }
+ return TRUE;
+}
+
+
static bfd_boolean
elfNN_aarch64_write_section (bfd *output_bfd ATTRIBUTE_UNUSED,
struct bfd_link_info *link_info,
@@ -3952,12 +4360,24 @@ elfNN_aarch64_write_section (bfd *output_bfd ATTRIBUTE_UNUSED,
{
struct erratum_835769_branch_to_stub_data data;
+ data.info = link_info;
data.output_section = sec;
data.contents = contents;
bfd_hash_traverse (&globals->stub_hash_table,
make_branch_to_erratum_835769_stub, &data);
}
+ if (globals->fix_erratum_843419)
+ {
+ struct erratum_835769_branch_to_stub_data data;
+
+ data.info = link_info;
+ data.output_section = sec;
+ data.contents = contents;
+ bfd_hash_traverse (&globals->stub_hash_table,
+ _bfd_aarch64_erratum_843419_branch_to_stub, &data);
+ }
+
return FALSE;
}
@@ -6341,6 +6761,14 @@ aarch64_map_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
return FALSE;
break;
+ case aarch64_stub_erratum_843419_veneer:
+ if (!elfNN_aarch64_output_stub_sym (osi, stub_name, addr,
+ sizeof (aarch64_erratum_843419_stub)))
+ return FALSE;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
+ return FALSE;
+ break;
+
default:
BFD_FAIL ();
}
@@ -7041,8 +7469,8 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
}
/* Init mapping symbols information to use later to distingush between
- code and data while scanning for erratam 835769. */
- if (htab->fix_erratum_835769)
+ code and data while scanning for errata. */
+ if (htab->fix_erratum_835769 || htab->fix_erratum_843419)
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
if (!is_aarch64_elf (ibfd))
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index d6e0332..7ea364f 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -23,6 +23,26 @@
#define MASK(n) ((1u << (n)) - 1)
+/* Sign-extend VALUE, which has the indicated number of BITS. */
+
+bfd_signed_vma
+_bfd_aarch64_sign_extend (bfd_vma value, int bits)
+{
+ if (value & ((bfd_vma) 1 << (bits - 1)))
+ /* VALUE is negative. */
+ value |= ((bfd_vma) - 1) << bits;
+
+ return value;
+}
+
+/* Decode the IMM field of ADRP. */
+
+uint32_t
+_bfd_aarch64_decode_adrp_imm (uint32_t insn)
+{
+ return (((insn >> 5) & MASK (19)) << 2) | ((insn >> 29) & MASK (2));
+}
+
/* Reencode the imm field of add immediate. */
static inline uint32_t
reencode_add_imm (uint32_t insn, uint32_t imm)
@@ -30,9 +50,10 @@ reencode_add_imm (uint32_t insn, uint32_t imm)
return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10);
}
-/* Reencode the imm field of adr. */
-static inline uint32_t
-reencode_adr_imm (uint32_t insn, uint32_t imm)
+/* Reencode the IMM field of ADR. */
+
+uint32_t
+_bfd_aarch64_reencode_adr_imm (uint32_t insn, uint32_t imm)
{
return (insn & ~((MASK (2) << 29) | (MASK (19) << 5)))
| ((imm & MASK (2)) << 29) | ((imm & (MASK (19) << 2)) << 3);
@@ -212,7 +233,7 @@ _bfd_aarch64_elf_put_addend (bfd *abfd,
case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
- contents = reencode_adr_imm (contents, addend);
+ contents = _bfd_aarch64_reencode_adr_imm (contents, addend);
break;
case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index dece641..6ac79d0 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -26,6 +26,19 @@
#define PG(x) ((x) & ~ (bfd_vma) 0xfff)
#define PG_OFFSET(x) ((x) & (bfd_vma) 0xfff)
+#define AARCH64_ADR_OP 0x10000000
+#define AARCH64_ADRP_OP 0x90000000
+#define AARCH64_ADRP_OP_MASK 0x9F000000
+
+extern bfd_signed_vma
+_bfd_aarch64_sign_extend (bfd_vma, int);
+
+extern uint32_t
+_bfd_aarch64_decode_adrp_imm (uint32_t);
+
+extern uint32_t
+_bfd_aarch64_reencode_adr_imm (uint32_t, uint32_t);
+
extern bfd_reloc_status_type
_bfd_aarch64_elf_put_addend (bfd *, bfd_byte *, bfd_reloc_code_real_type,
reloc_howto_type *, bfd_signed_vma);
diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index 6d201e3..759ee1f 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -31,6 +31,7 @@ static int no_enum_size_warning = 0;
static int no_wchar_size_warning = 0;
static int pic_veneer = 0;
static int fix_erratum_835769 = 0;
+static int fix_erratum_843419 = 0;
static void
gld${EMULATION_NAME}_before_parse (void)
@@ -298,7 +299,8 @@ aarch64_elf_create_output_section_statements (void)
bfd_elf${ELFSIZE}_aarch64_set_options (link_info.output_bfd, &link_info,
no_enum_size_warning,
no_wchar_size_warning,
- pic_veneer, fix_erratum_835769);
+ pic_veneer,
+ fix_erratum_835769, fix_erratum_843419);
stub_file = lang_add_input_file ("linker stubs",
lang_input_file_is_fake_enum,
@@ -348,6 +350,7 @@ PARSE_AND_LIST_PROLOGUE='
#define OPTION_STUBGROUP_SIZE 311
#define OPTION_NO_WCHAR_SIZE_WARNING 312
#define OPTION_FIX_ERRATUM_835769 313
+#define OPTION_FIX_ERRATUM_843419 314
'
PARSE_AND_LIST_SHORTOPTS=p
@@ -359,6 +362,7 @@ PARSE_AND_LIST_LONGOPTS='
{ "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
{ "no-wchar-size-warning", no_argument, NULL, OPTION_NO_WCHAR_SIZE_WARNING},
{ "fix-cortex-a53-835769", no_argument, NULL, OPTION_FIX_ERRATUM_835769},
+ { "fix-cortex-a53-843419", no_argument, NULL, OPTION_FIX_ERRATUM_843419},
'
PARSE_AND_LIST_OPTIONS='
@@ -377,6 +381,7 @@ PARSE_AND_LIST_OPTIONS='
the linker should choose suitable defaults.\n"
));
fprintf (file, _(" --fix-cortex-a53-835769 Fix erratum 835769\n"));
+ fprintf (file, _(" --fix-cortex-a53-843419 Fix erratum 843419\n"));
'
PARSE_AND_LIST_ARGS_CASES='
@@ -400,6 +405,10 @@ PARSE_AND_LIST_ARGS_CASES='
fix_erratum_835769 = 1;
break;
+ case OPTION_FIX_ERRATUM_843419:
+ fix_erratum_843419 = 1;
+ break;
+
case OPTION_STUBGROUP_SIZE:
{
const char *end;
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 19bcd13..8e2d254 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -46,6 +46,7 @@ set aarch64elftests {
}
run_ld_link_tests $aarch64elftests
+run_dump_test "erratum843419"
# Relocation Tests
run_dump_test "weak-undefined"
diff --git a/ld/testsuite/ld-aarch64/erratum843419.d b/ld/testsuite/ld-aarch64/erratum843419.d
new file mode 100644
index 0000000..4be8f9e
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/erratum843419.d
@@ -0,0 +1,69 @@
+#source: erratum843419.s
+#as:
+#ld: --fix-cortex-a53-835769 --fix-cortex-a53-843419 -e0 --section-start .e843419=0x20000000 --section-start .e835769=0x3000000 -Ttext=0x400000 -Tdata=0x40000000
+#objdump: -dr
+#...
+
+Disassembly of section .e843419:
+
+0000000020000000 <e843419>:
+ 20000000: d10043ff sub sp, sp, #0x10
+ 20000004: d28001a7 mov x7, #0xd // #13
+ 20000008: b9000fe7 str w7, \[sp,#12\]
+ 2000000c: 140003fb b 20000ff8 <e843419_1>
+ ...
+
+0000000020000ff8 <e843419_1>:
+ 20000ff8: 90100000 adrp x0, 40000000 <[_a-zA-z0-9]+>
+ 20000ffc: f800c007 stur x7, \[x0,#12\]
+ 20001000: d2800128 mov x8, #0x9 // #9
+ 20001004: 14000008 b 20001024 <e843419@0002_00000013_1004>
+ 20001008: 8b050020 add x0, x1, x5
+ 2000100c: b9400fe7 ldr w7, \[sp,#12\]
+ 20001010: 0b0700e0 add w0, w7, w7
+ 20001014: 910043ff add sp, sp, #0x10
+ 20001018: 14000005 b 2000102c <__e835769_veneer>
+ 2000101c: d65f03c0 ret
+ 20001020: 14000400 b 20002020 <__e835769_veneer\+0xff4>
+
+0000000020001024 <e843419@0002_00000013_1004>:
+ 20001024: f9000008 str x8, \[x0\]
+ 20001028: 17fffff8 b 20001008 <e843419_1\+0x10>
+
+000000002000102c <__e835769_veneer>:
+ 2000102c: f0f17ff0 adrp x16, 3000000 <e835769>
+ 20001030: 91000210 add x16, x16, #0x0
+ 20001034: d61f0200 br x16
+ ...
+
+Disassembly of section .e835769:
+
+0000000003000000 <e835769>:
+ 3000000: b8408c87 ldr w7, \[x4,#8\]!
+ 3000004: 1b017c06 mul w6, w0, w1
+ 3000008: f9400084 ldr x4, \[x4\]
+ 300000c: 14000004 b 300001c <__erratum_835769_veneer_0>
+ 3000010: aa0503e0 mov x0, x5
+ 3000014: d65f03c0 ret
+ 3000018: 14000400 b 3001018 <__erratum_835769_veneer_0\+0xffc>
+
+000000000300001c <__erratum_835769_veneer_0>:
+ 300001c: 9b031845 madd x5, x2, x3, x6
+ 3000020: 17fffffc b 3000010 <e835769\+0x10>
+ ...
+
+Disassembly of section .text:
+
+0000000000400000 <main>:
+ 400000: d10043ff sub sp, sp, #0x10
+ 400004: d28001a7 mov x7, #0xd // #13
+ 400008: b9000fe7 str w7, \[sp,#12\]
+ 40000c: 14000003 b 400018 <__e843419_veneer>
+ 400010: d65f03c0 ret
+ 400014: 14000400 b 401014 <__e843419_veneer\+0xffc>
+
+0000000000400018 <__e843419_veneer>:
+ 400018: 900fe010 adrp x16, 20000000 <e843419>
+ 40001c: 91000210 add x16, x16, #0x0
+ 400020: d61f0200 br x16
+ ...
diff --git a/ld/testsuite/ld-aarch64/erratum843419.s b/ld/testsuite/ld-aarch64/erratum843419.s
new file mode 100644
index 0000000..35c21ae
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/erratum843419.s
@@ -0,0 +1,84 @@
+
+ .comm data0,4,4
+ .text
+ .align 2
+ .global main
+ .type main, %function
+main:
+ sub sp, sp, #16
+ mov x7, 13
+ str w7, [sp,12]
+ b e843419
+ ret
+ .size main, .-main
+
+ .section .e843419, "xa"
+ .align 2
+ .global e843419
+ .type e843419, %function
+e843419:
+ sub sp, sp, #16
+ mov x7, 13
+ str w7, [sp,12]
+ b e843419_1
+ .fill 4072,1,0
+e843419_1:
+ adrp x0, data0
+ str x7, [x0,12]
+ mov x8, 9
+ str x8, [x0, :lo12:data0]
+
+ add x0, x1, x5
+ ldr w7, [sp,12]
+ add w0, w7, w7
+ add sp, sp, 16
+ b e835769
+ ret
+ .size e843419, .-e843419
+
+ .section .e835769, "xa"
+ .align 2
+ .global e835769
+ .type e835769, %function
+e835769:
+ ldr w7, [x4,8]!
+ mul w6, w0, w1
+ ldr x4, [x4]
+ madd x5, x2, x3, x6
+ mov x0, x5
+ ret
+ .size e835769, .-e835769
+
+# ---
+
+
+
+
+
+# ---
+
+ .data
+data0:
+ .fill 8,1,255
+ .balign 512
+ .fill 4,1,255
+ # double word access that crosses a 64 bit boundary
+data1:
+ .fill 2,1,255
+
+ # word access that crosses a 64 boundary
+data2:
+ .fill 2,1,255
+
+data5:
+ .fill 4,1,255
+
+ # double word access that crosses a 128 boundary
+data3:
+ .fill 2,1,255
+
+ # word access that crosses a 128 bit boundary
+data4:
+ .fill 2,1,255
+data6:
+ .fill 496,1,255
More information about the Binutils
mailing list