[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