[AArch64] Add ARMv8.3 combined pointer authentication load instructions

Message ID 5821A6D1.2060405@arm.com
State New
Headers show

Commit Message

Szabolcs Nagy Nov. 8, 2016, 10:20 a.m.
Add support for ARMv8.3 LDRAA and LDRAB combined pointer authentication and
load instructions.

These instructions authenticate the base register and load 8 byte from it plus
a scaled 10-bit offset with optional writeback to update the base register.

A new instruction class (ldst_imm10) and operand type (AARCH64_OPND_ADDR_SIMM10)
were introduced to handle the special addressing form.

include/
2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_ADDR_SIMM10.
	(enum aarch64_insn_class): Add ldst_imm10.

opcodes/
2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	* aarch64-tbl.h (QL_X1NIL): New.
	(arch64_opcode_table): Add ldraa, ldrab.
	(AARCH64_OPERANDS): Add "ADDR_SIMM10".
	* aarch64-asm.h (aarch64_ins_addr_simm10): Declare.
	* aarch64-asm.c (aarch64_ins_addr_simm10): Define.
	* aarch64-dis.h (aarch64_ext_addr_simm10): Declare.
	* aarch64-dis.c (aarch64_ext_addr_simm10): Define.
	* aarch64-opc.h (enum aarch64_field_kind): Add FLD_S_simm10.
	* aarch64-opc.c (fields): Add data for FLD_S_simm10.
	(operand_general_constraint_met_p): Handle AARCH64_OPND_ADDR_SIMM10.
	(aarch64_print_operand): Likewise.
	* aarch64-asm-2.c: Regenerate.
	* aarch64-dis-2.c: Regenerate.
	* aarch64-opc-2.c: Regenerate.

gas/
2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_ADDR_SIMM10.
	(fix_insn): Likewise.
	(warn_unpredictable_ldst): Handle ldst_imm10.

gas/testsuite/
2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	* gas/aarch64/pac.s: Add ldraa and ldrab tests.
	* gas/aarch64/pac.d: Likewise.
	* gas/aarch64/illegal-ldraa.s: New.
	* gas/aarch64/illegal-ldraa.l: New.
	* gas/aarch64/illegal-ldraa.d: New.

Comments

Szabolcs Nagy Nov. 17, 2016, 9:58 a.m. | #1
On 08/11/16 10:20, Szabolcs Nagy wrote:
> Add support for ARMv8.3 LDRAA and LDRAB combined pointer authentication and

> load instructions.

> 

> These instructions authenticate the base register and load 8 byte from it plus

> a scaled 10-bit offset with optional writeback to update the base register.

> 

> A new instruction class (ldst_imm10) and operand type (AARCH64_OPND_ADDR_SIMM10)

> were introduced to handle the special addressing form.

> 


ping.

thanks for reviewing the other patches in the series,
this one got left out.

> include/

> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

> 

> 	* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_ADDR_SIMM10.

> 	(enum aarch64_insn_class): Add ldst_imm10.

> 

> opcodes/

> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

> 

> 	* aarch64-tbl.h (QL_X1NIL): New.

> 	(arch64_opcode_table): Add ldraa, ldrab.

> 	(AARCH64_OPERANDS): Add "ADDR_SIMM10".

> 	* aarch64-asm.h (aarch64_ins_addr_simm10): Declare.

> 	* aarch64-asm.c (aarch64_ins_addr_simm10): Define.

> 	* aarch64-dis.h (aarch64_ext_addr_simm10): Declare.

> 	* aarch64-dis.c (aarch64_ext_addr_simm10): Define.

> 	* aarch64-opc.h (enum aarch64_field_kind): Add FLD_S_simm10.

> 	* aarch64-opc.c (fields): Add data for FLD_S_simm10.

> 	(operand_general_constraint_met_p): Handle AARCH64_OPND_ADDR_SIMM10.

> 	(aarch64_print_operand): Likewise.

> 	* aarch64-asm-2.c: Regenerate.

> 	* aarch64-dis-2.c: Regenerate.

> 	* aarch64-opc-2.c: Regenerate.

> 

> gas/

> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

> 

> 	* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_ADDR_SIMM10.

> 	(fix_insn): Likewise.

> 	(warn_unpredictable_ldst): Handle ldst_imm10.

> 

> gas/testsuite/

> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

> 

> 	* gas/aarch64/pac.s: Add ldraa and ldrab tests.

> 	* gas/aarch64/pac.d: Likewise.

> 	* gas/aarch64/illegal-ldraa.s: New.

> 	* gas/aarch64/illegal-ldraa.l: New.

> 	* gas/aarch64/illegal-ldraa.d: New.

>
Nick Clifton Nov. 17, 2016, 3:10 p.m. | #2
Hi Szabolcs,

> ping.

> 

> thanks for reviewing the other patches in the series,

> this one got left out.


Doh - sorry!

>> include/

>> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>> 	* opcode/aarch64.h (enum aarch64_opnd): Add AARCH64_OPND_ADDR_SIMM10.

>> 	(enum aarch64_insn_class): Add ldst_imm10.

>>

>> opcodes/

>> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>> 	* aarch64-tbl.h (QL_X1NIL): New.

>> 	(arch64_opcode_table): Add ldraa, ldrab.

>> 	(AARCH64_OPERANDS): Add "ADDR_SIMM10".

>> 	* aarch64-asm.h (aarch64_ins_addr_simm10): Declare.

>> 	* aarch64-asm.c (aarch64_ins_addr_simm10): Define.

>> 	* aarch64-dis.h (aarch64_ext_addr_simm10): Declare.

>> 	* aarch64-dis.c (aarch64_ext_addr_simm10): Define.

>> 	* aarch64-opc.h (enum aarch64_field_kind): Add FLD_S_simm10.

>> 	* aarch64-opc.c (fields): Add data for FLD_S_simm10.

>> 	(operand_general_constraint_met_p): Handle AARCH64_OPND_ADDR_SIMM10.

>> 	(aarch64_print_operand): Likewise.

>> 	* aarch64-asm-2.c: Regenerate.

>> 	* aarch64-dis-2.c: Regenerate.

>> 	* aarch64-opc-2.c: Regenerate.

>>

>> gas/

>> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>> 	* config/tc-aarch64.c (parse_operands): Handle AARCH64_OPND_ADDR_SIMM10.

>> 	(fix_insn): Likewise.

>> 	(warn_unpredictable_ldst): Handle ldst_imm10.

>>

>> gas/testsuite/

>> 2016-11-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>

>>

>> 	* gas/aarch64/pac.s: Add ldraa and ldrab tests.

>> 	* gas/aarch64/pac.d: Likewise.

>> 	* gas/aarch64/illegal-ldraa.s: New.

>> 	* gas/aarch64/illegal-ldraa.l: New.

>> 	* gas/aarch64/illegal-ldraa.d: New.


Approved - please apply.

Cheers
  Nick

Patch

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index e56d068..a9cee79 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -6024,6 +6024,25 @@  parse_operands (char *str, const aarch64_opcode *opcode)
 					      /* skip_p */ 0);
 	  break;
 
+	case AARCH64_OPND_ADDR_SIMM10:
+	  po_misc_or_fail (parse_address (&str, info));
+	  if (info->addr.pcrel || info->addr.offset.is_reg
+	      || !info->addr.preind || info->addr.postind)
+	    {
+	      set_syntax_error (_("invalid addressing mode"));
+	      goto failure;
+	    }
+	  if (inst.reloc.type != BFD_RELOC_UNUSED)
+	    {
+	      set_syntax_error (_("relocation not allowed"));
+	      goto failure;
+	    }
+	  assign_imm_if_const_or_fixup_later (&inst.reloc, info,
+					      /* addr_off_p */ 1,
+					      /* need_libopcodes_p */ 1,
+					      /* skip_p */ 0);
+	  break;
+
 	case AARCH64_OPND_ADDR_UIMM12:
 	  po_misc_or_fail (parse_address (&str, info));
 	  if (info->addr.pcrel || info->addr.offset.is_reg
@@ -6481,6 +6500,7 @@  warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
     {
     case ldst_pos:
     case ldst_imm9:
+    case ldst_imm10:
     case ldst_unscaled:
     case ldst_unpriv:
       /* Loading/storing the base register is unpredictable if writeback.  */
@@ -7350,6 +7370,7 @@  fix_insn (fixS *fixP, uint32_t flags, offsetT value)
     case AARCH64_OPND_ADDR_SIMM7:
     case AARCH64_OPND_ADDR_SIMM9:
     case AARCH64_OPND_ADDR_SIMM9_2:
+    case AARCH64_OPND_ADDR_SIMM10:
     case AARCH64_OPND_ADDR_UIMM12:
       /* Immediate offset in an address.  */
       insn = get_aarch64_insn (buf);
diff --git a/gas/testsuite/gas/aarch64/illegal-ldraa.d b/gas/testsuite/gas/aarch64/illegal-ldraa.d
new file mode 100644
index 0000000..ab2dc30
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/illegal-ldraa.d
@@ -0,0 +1,2 @@ 
+#as: -march=armv8.3-a -mno-verbose-error
+#error-output: illegal-ldraa.l
diff --git a/gas/testsuite/gas/aarch64/illegal-ldraa.l b/gas/testsuite/gas/aarch64/illegal-ldraa.l
new file mode 100644
index 0000000..e3f81c5
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/illegal-ldraa.l
@@ -0,0 +1,35 @@ 
+[^:]+: Assembler messages:
+[^:]+:9: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#1\]'
+[^:]+:10: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#4\]'
+[^:]+:11: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#-10\]'
+[^:]+:12: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#4096\]'
+[^:]+:13: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#5555\]'
+[^:]+:14: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#-4104\]'
+[^:]+:15: Error: 64-bit integer or SP register expected at operand 2 -- `ldraa x0,\[xz\]'
+[^:]+:16: Error: missing offset in the pre-indexed address at operand 2 -- `ldraa x0,\[x1\]!'
+[^:]+:17: Error: invalid expression in the address at operand 2 -- `ldraa x0,\[sp\],'
+[^:]+:18: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#1\]!'
+[^:]+:19: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#4\]!'
+[^:]+:20: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#-10\]!'
+[^:]+:21: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#4096\]!'
+[^:]+:22: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#5555\]!'
+[^:]+:23: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#-4104\]!'
+[^:]+:24: Error: 64-bit integer or SP register expected at operand 2 -- `ldraa x0,\[xz\]'
+[^:]+:25: Error: invalid addressing mode at operand 2 -- `ldraa x0,\[x1\],#8'
+[^:]+:28: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#1\]'
+[^:]+:29: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#4\]'
+[^:]+:30: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#-10\]'
+[^:]+:31: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#4096\]'
+[^:]+:32: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#5555\]'
+[^:]+:33: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#-4104\]'
+[^:]+:34: Error: 64-bit integer or SP register expected at operand 2 -- `ldrab x0,\[xz\]'
+[^:]+:35: Error: missing offset in the pre-indexed address at operand 2 -- `ldrab x0,\[x1\]!'
+[^:]+:36: Error: invalid expression in the address at operand 2 -- `ldrab x0,\[sp\],'
+[^:]+:37: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#1\]!'
+[^:]+:38: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#4\]!'
+[^:]+:39: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#-10\]!'
+[^:]+:40: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#4096\]!'
+[^:]+:41: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#5555\]!'
+[^:]+:42: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#-4104\]!'
+[^:]+:43: Error: 64-bit integer or SP register expected at operand 2 -- `ldrab x0,\[xz\]'
+[^:]+:44: Error: invalid addressing mode at operand 2 -- `ldrab x0,\[x1\],#8'
diff --git a/gas/testsuite/gas/aarch64/illegal-ldraa.s b/gas/testsuite/gas/aarch64/illegal-ldraa.s
new file mode 100644
index 0000000..93a8cf5
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/illegal-ldraa.s
@@ -0,0 +1,44 @@ 
+// Test illegal ARMv8.3 LDRAA and LDRAB instructions
+.text
+
+	// Good.
+	ldraa x0, [x1,#8]
+	ldrab x0, [x1,#8]
+
+
+	ldraa x0, [x1,#1]
+	ldraa x0, [x1,#4]
+	ldraa x0, [x1,#-10]
+	ldraa x0, [x1,#4096]
+	ldraa x0, [x1,#5555]
+	ldraa x0, [x1,#-4104]
+	ldraa x0, [xz]
+	ldraa x0, [x1]!
+	ldraa x0, [sp],
+	ldraa x0, [x1,#1]!
+	ldraa x0, [x1,#4]!
+	ldraa x0, [x1,#-10]!
+	ldraa x0, [x1,#4096]!
+	ldraa x0, [x1,#5555]!
+	ldraa x0, [x1,#-4104]!
+	ldraa x0, [xz]
+	ldraa x0, [x1], #8
+
+
+	ldrab x0, [x1,#1]
+	ldrab x0, [x1,#4]
+	ldrab x0, [x1,#-10]
+	ldrab x0, [x1,#4096]
+	ldrab x0, [x1,#5555]
+	ldrab x0, [x1,#-4104]
+	ldrab x0, [xz]
+	ldrab x0, [x1]!
+	ldrab x0, [sp],
+	ldrab x0, [x1,#1]!
+	ldrab x0, [x1,#4]!
+	ldrab x0, [x1,#-10]!
+	ldrab x0, [x1,#4096]!
+	ldrab x0, [x1,#5555]!
+	ldrab x0, [x1,#-4104]!
+	ldrab x0, [xz]
+	ldrab x0, [x1], #8
diff --git a/gas/testsuite/gas/aarch64/pac.d b/gas/testsuite/gas/aarch64/pac.d
index c242b2d..0028c44 100644
--- a/gas/testsuite/gas/aarch64/pac.d
+++ b/gas/testsuite/gas/aarch64/pac.d
@@ -50,3 +50,25 @@  Disassembly of section \.text:
   a4:	d65f0fff 	retab
   a8:	d69f0bff 	eretaa
   ac:	d69f0fff 	eretab
+  b0:	f8200441 	ldraa	x1, \[x2\]
+  b4:	f8200441 	ldraa	x1, \[x2\]
+  b8:	f87ff483 	ldraa	x3, \[x4, #-8\]
+  bc:	f82014c5 	ldraa	x5, \[x6, #8\]
+  c0:	f83ff507 	ldraa	x7, \[x8, #4088\]
+  c4:	f8600528 	ldraa	x8, \[x9, #-4096\]
+  c8:	f82007e2 	ldraa	x2, \[sp\]
+  cc:	f87067e4 	ldraa	x4, \[sp, #-2000\]
+  d0:	f8a00441 	ldrab	x1, \[x2\]
+  d4:	f8a00441 	ldrab	x1, \[x2\]
+  d8:	f8fff483 	ldrab	x3, \[x4, #-8\]
+  dc:	f8a014c5 	ldrab	x5, \[x6, #8\]
+  e0:	f8bff507 	ldrab	x7, \[x8, #4088\]
+  e4:	f8e00528 	ldrab	x8, \[x9, #-4096\]
+  e8:	f8a007e2 	ldrab	x2, \[sp\]
+  ec:	f8f067e4 	ldrab	x4, \[sp, #-2000\]
+  f0:	f8201c62 	ldraa	x2, \[x3, #8\]!
+  f4:	f87ffca4 	ldraa	x4, \[x5, #-8\]!
+  f8:	f83fffe6 	ldraa	x6, \[sp, #4088\]!
+  fc:	f8a01c62 	ldrab	x2, \[x3, #8\]!
+ 100:	f8fffca4 	ldrab	x4, \[x5, #-8\]!
+ 104:	f8bfffe6 	ldrab	x6, \[sp, #4088\]!
diff --git a/gas/testsuite/gas/aarch64/pac.s b/gas/testsuite/gas/aarch64/pac.s
index 59fa637..01ba545 100644
--- a/gas/testsuite/gas/aarch64/pac.s
+++ b/gas/testsuite/gas/aarch64/pac.s
@@ -54,3 +54,26 @@ 
 	retab
 	eretaa
 	eretab
+
+	ldraa x1, [x2]
+	ldraa x1, [x2,#0]
+	ldraa x3, [x4,#-8]
+	ldraa x5, [x6,#8]
+	ldraa x7, [x8,#4088]
+	ldraa x8, [x9,#-4096]
+	ldraa x2, [sp]
+	ldraa x4, [sp,#-2000]
+	ldrab x1, [x2]
+	ldrab x1, [x2,#0]
+	ldrab x3, [x4,#-8]
+	ldrab x5, [x6,#8]
+	ldrab x7, [x8,#4088]
+	ldrab x8, [x9,#-4096]
+	ldrab x2, [sp]
+	ldrab x4, [sp,#-2000]
+	ldraa x2, [x3, #8]!
+	ldraa x4, [x5, #-8]!
+	ldraa x6, [sp, #4088]!
+	ldrab x2, [x3, #8]!
+	ldrab x4, [x5, #-8]!
+	ldrab x6, [sp, #4088]!
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index a25b211..a35a813 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -225,6 +225,7 @@  enum aarch64_opnd
 				   friendly feature of using LDR/STR as the
 				   the mnemonic name for LDUR/STUR instructions
 				   wherever there is no ambiguity.  */
+  AARCH64_OPND_ADDR_SIMM10,	/* Address of signed 10-bit immediate.  */
   AARCH64_OPND_ADDR_UIMM12,	/* Address of unsigned 12-bit immediate.  */
   AARCH64_OPND_SIMD_ADDR_SIMPLE,/* Address of ld/st multiple structures.  */
   AARCH64_OPND_SIMD_ADDR_POST,	/* Address of ld/st multiple post-indexed.  */
@@ -465,6 +466,7 @@  enum aarch64_insn_class
   ldst_immpost,
   ldst_immpre,
   ldst_imm9,	/* immpost or immpre */
+  ldst_imm10,	/* LDRAA/LDRAB */
   ldst_pos,
   ldst_regoff,
   ldst_unpriv,
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index 34be794..64051a9 100644
--- a/opcodes/aarch64-asm.c
+++ b/opcodes/aarch64-asm.c
@@ -606,6 +606,30 @@  aarch64_ins_addr_simm (const aarch64_operand *self,
   return NULL;
 }
 
+/* Encode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}].  */
+const char *
+aarch64_ins_addr_simm10 (const aarch64_operand *self,
+			 const aarch64_opnd_info *info,
+			 aarch64_insn *code,
+			 const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int imm;
+
+  /* Rn */
+  insert_field (self->fields[0], code, info->addr.base_regno, 0);
+  /* simm10 */
+  imm = info->addr.offset.imm >> 3;
+  insert_field (self->fields[1], code, imm >> 9, 0);
+  insert_field (self->fields[2], code, imm, 0);
+  /* writeback */
+  if (info->addr.writeback)
+    {
+      assert (info->addr.preind == 1 && info->addr.postind == 0);
+      insert_field (self->fields[3], code, 1, 0);
+    }
+  return NULL;
+}
+
 /* Encode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>{, #<pimm>}].  */
 const char *
 aarch64_ins_addr_uimm12 (const aarch64_operand *self,
diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h
index 0cce71c..b49d3d5 100644
--- a/opcodes/aarch64-asm.h
+++ b/opcodes/aarch64-asm.h
@@ -59,6 +59,7 @@  AARCH64_DECL_OPD_INSERTER (ins_ft);
 AARCH64_DECL_OPD_INSERTER (ins_addr_simple);
 AARCH64_DECL_OPD_INSERTER (ins_addr_regoff);
 AARCH64_DECL_OPD_INSERTER (ins_addr_simm);
+AARCH64_DECL_OPD_INSERTER (ins_addr_simm10);
 AARCH64_DECL_OPD_INSERTER (ins_addr_uimm12);
 AARCH64_DECL_OPD_INSERTER (ins_simd_addr_post);
 AARCH64_DECL_OPD_INSERTER (ins_cond);
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index d8c5fa7..245749c 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -981,6 +981,27 @@  aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info,
   return 1;
 }
 
+/* Decode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}].  */
+int
+aarch64_ext_addr_simm10 (const aarch64_operand *self, aarch64_opnd_info *info,
+			 aarch64_insn code,
+			 const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  aarch64_insn imm;
+
+  info->qualifier = get_expected_qualifier (inst, info->idx);
+  /* Rn */
+  info->addr.base_regno = extract_field (self->fields[0], code, 0);
+  /* simm10 */
+  imm = extract_fields (code, 0, 2, self->fields[1], self->fields[2]);
+  info->addr.offset.imm = sign_extend (imm, 9) << 3;
+  if (extract_field (self->fields[3], code, 0) == 1) {
+    info->addr.writeback = 1;
+    info->addr.preind = 1;
+  }
+  return 1;
+}
+
 /* Decode the address operand for e.g.
      LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>], <Xm|#<amount>>.  */
 int
diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h
index 474bc45..48be5e4 100644
--- a/opcodes/aarch64-dis.h
+++ b/opcodes/aarch64-dis.h
@@ -81,6 +81,7 @@  AARCH64_DECL_OPD_EXTRACTOR (ext_ft);
 AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simple);
 AARCH64_DECL_OPD_EXTRACTOR (ext_addr_regoff);
 AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simm);
+AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simm10);
 AARCH64_DECL_OPD_EXTRACTOR (ext_addr_uimm12);
 AARCH64_DECL_OPD_EXTRACTOR (ext_simd_addr_post);
 AARCH64_DECL_OPD_EXTRACTOR (ext_cond);
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index f00549c..c85abc6 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -253,6 +253,7 @@  const aarch64_field fields[] =
     { 16,  6 },	/* immr: in bitfield and logical immediate instructions.  */
     { 16,  3 },	/* immb: in advsimd shift by immediate instructions.  */
     { 19,  4 },	/* immh: in advsimd shift by immediate instructions.  */
+    { 22,  1 },	/* S: in LDRAA and LDRAB instructions.  */
     { 22,  1 },	/* N: in logical (immediate) instructions.  */
     { 11,  1 },	/* index: in ld/st inst deciding the pre/post-index.  */
     { 24,  1 },	/* index2: in ld/st pair inst deciding the pre/post-index.  */
@@ -1528,6 +1529,14 @@  operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 	      return 0;
 	    }
 	  break;
+	case ldst_imm10:
+	  if (opnd->addr.writeback == 1 && opnd->addr.preind != 1)
+	    {
+	      set_syntax_error (mismatch_detail, idx,
+				_("unexpected address writeback"));
+	      return 0;
+	    }
+	  break;
 	case ldst_imm9:
 	case ldstpair_indexed:
 	case asisdlsep:
@@ -1584,6 +1593,20 @@  operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 			   _("negative or unaligned offset expected"));
 	  return 0;
 
+	case AARCH64_OPND_ADDR_SIMM10:
+	  /* Scaled signed 10 bits immediate offset.  */
+	  if (!value_in_range_p (opnd->addr.offset.imm, -4096, 4088))
+	    {
+	      set_offset_out_of_range_error (mismatch_detail, idx, -4096, 4088);
+	      return 0;
+	    }
+	  if (!value_aligned_p (opnd->addr.offset.imm, 8))
+	    {
+	      set_unaligned_error (mismatch_detail, idx, 8);
+	      return 0;
+	    }
+	  break;
+
 	case AARCH64_OPND_SIMD_ADDR_POST:
 	  /* AdvSIMD load/store multiple structures, post-index.  */
 	  assert (idx == 1);
@@ -3408,6 +3431,7 @@  aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
     case AARCH64_OPND_ADDR_SIMM7:
     case AARCH64_OPND_ADDR_SIMM9:
     case AARCH64_OPND_ADDR_SIMM9_2:
+    case AARCH64_OPND_ADDR_SIMM10:
     case AARCH64_OPND_SVE_ADDR_RI_S4xVL:
     case AARCH64_OPND_SVE_ADDR_RI_S4x2xVL:
     case AARCH64_OPND_SVE_ADDR_RI_S4x3xVL:
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index 91c78f4..7bb895a 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -80,6 +80,7 @@  enum aarch64_field_kind
   FLD_immr,
   FLD_immb,
   FLD_immh,
+  FLD_S_imm10,
   FLD_N,
   FLD_index,
   FLD_index2,
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index f5750a2..0aa8005 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -1094,6 +1094,12 @@ 
   QLF3(W, X, NIL),		\
 }
 
+/* e.g. LDRAA <Xt>, [<Xn|SP>{,#imm}].  */
+#define QL_X1NIL		\
+{				\
+  QLF2(X, NIL),			\
+}
+
 /* e.g. LDXP <Xt1>, <Xt2>, [<Xn|SP>{,#0}].  */
 #define QL_R2NIL		\
 {				\
@@ -2916,6 +2922,9 @@  struct aarch64_opcode aarch64_opcode_table[] =
   CORE_INSN ("ldur", 0xb8400000, 0xbfe00c00, ldst_unscaled, OP_LDUR, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_GPRSIZE_IN_Q),
   CORE_INSN ("ldursw", 0xb8800000, 0xffe00c00, ldst_unscaled, OP_LDURSW, OP2 (Rt, ADDR_SIMM9), QL_LDST_X32, 0),
   CORE_INSN ("prfum", 0xf8800000, 0xffe00c00, ldst_unscaled, OP_PRFUM, OP2 (PRFOP, ADDR_SIMM9), QL_LDST_PRFM, 0),
+  /* Load/store register (scaled signed immediate).  */
+  V8_3_INSN ("ldraa", 0xf8200400, 0xffa00400, ldst_imm10, OP2 (Rt, ADDR_SIMM10), QL_X1NIL, 0),
+  V8_3_INSN ("ldrab", 0xf8a00400, 0xffa00400, ldst_imm10, OP2 (Rt, ADDR_SIMM10), QL_X1NIL, 0),
   /* Load/store exclusive.  */
   CORE_INSN ("stxrb", 0x8007c00, 0xffe08000, ldstexcl, 0, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0),
   CORE_INSN ("stlxrb", 0x800fc00, 0xffe08000, ldstexcl, 0, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0),
@@ -4117,6 +4126,8 @@  struct aarch64_opcode aarch64_opcode_table[] =
       "an address with 9-bit signed immediate offset")			\
     Y(ADDRESS, addr_simm, "ADDR_SIMM9_2", 0, F(FLD_imm9,FLD_index),	\
       "an address with 9-bit negative or unaligned immediate offset")	\
+    Y(ADDRESS, addr_simm10, "ADDR_SIMM10", 0, F(FLD_Rn,FLD_S_imm10,FLD_imm9,FLD_index),\
+      "an address with 10-bit scaled, signed immediate offset")		\
     Y(ADDRESS, addr_uimm12, "ADDR_UIMM12", 0, F(FLD_Rn,FLD_imm12),	\
       "an address with scaled, unsigned immediate offset")		\
     Y(ADDRESS, addr_simple, "SIMD_ADDR_SIMPLE", 0, F(),			\