[PATCH 6/7] aarch64: add PAuth_LR instructions with imm16 operand

Muhammad Kamran <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
From: Matthieu Longo <[email protected]>

Add the immediate PC-relative forms of the FEAT_PAuth_LR
instructions:

	* AUTIA<k>SPPC
	* RETA<k>SPPC

These instructions use an unsigned 16-bit offset field, scaled by 4,
to identify a PC-relative instruction address.  Add ADDR_UPCREL16 for
this operand form and handle it as an assembler-internal fixup, since
the offset must be fully resolved by gas and no object-file relocation
is emitted.

Also update operand printing so disassembly computes the target address
using the unsigned backwards PC-relative offset semantics, and add gas
tests for valid encodings and diagnostics.

Co-authored-by: Muhammad Kamran <[email protected]>

CI-tag:skip
---
 gas/config/tc-aarch64.c                  | 41 ++++++++++++++++++++++++
 gas/testsuite/gas/aarch64/pauth_lr-bad.l |  8 +++++
 gas/testsuite/gas/aarch64/pauth_lr-bad.s | 15 +++++++++
 gas/testsuite/gas/aarch64/pauth_lr.d     | 13 ++++++++
 gas/testsuite/gas/aarch64/pauth_lr.s     | 17 ++++++++++
 include/opcode/aarch64.h                 |  1 +
 opcodes/aarch64-opc.c                    |  7 +++-
 opcodes/aarch64-tbl.h                    | 12 +++++++
 8 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index f5d57b1d094..d7963b66817 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -5241,6 +5241,12 @@ encode_addsub_imm_shift_amount (uint32_t cnt)
   return cnt << 22;
 }
 
+/* Encode the imm16 field of RETA<k>SPPC instruction.  */
+static inline uint32_t
+encode_pauthauti_imm16 (uint32_t imm)
+{
+  return imm << 5;
+}
 
 /* encode the imm field of Adr instruction */
 static inline uint32_t
@@ -7626,6 +7632,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
 	case AARCH64_OPND_ADDR_PCREL9:
 	case AARCH64_OPND_ADDR_PCREL14:
+	case AARCH64_OPND_ADDR_UPCREL16:
 	case AARCH64_OPND_ADDR_PCREL19:
 	case AARCH64_OPND_ADDR_PCREL21:
 	case AARCH64_OPND_ADDR_PCREL26:
@@ -7680,6 +7687,11 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 		      (opcode->op == OP_BL) ? BFD_RELOC_AARCH64_CALL26
 			 : BFD_RELOC_AARCH64_JUMP26;
 		    break;
+		  case pauth_lr:
+		    /* e.g. AUTI<k>SPPC or RETA<k>SPPC  */
+		    gas_assert (operands[i] == AARCH64_OPND_ADDR_UPCREL16);
+		    aarch64_set_gas_internal_fixup (&inst.reloc, info, 0);
+		    break;
 		  case loadlit:
 		    gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL19);
 		    inst.reloc.type = BFD_RELOC_AARCH64_LD_LO19_PCREL;
@@ -9725,6 +9737,7 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value)
 {
   int idx;
   uint32_t insn;
+  offsetT offset;
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   enum aarch64_opnd opnd = fixP->tc_fix_data.opnd;
   aarch64_inst *new_inst = fixP->tc_fix_data.inst;
@@ -9877,6 +9890,34 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value)
 		    _("immediate offset out of range"));
       break;
 
+    case AARCH64_OPND_ADDR_UPCREL16:
+      /* immediate offset from a label.  */
+      if (value > 0)
+	{
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			 _("negative pc-relative address offset not allowed"\
+			   " in this context: %ld"), -value);
+	  break;
+	}
+      offset = -value;
+      if (unsigned_overflow (offset, 18))
+	{
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			  _("pc-relative address offset out of range: %#lx"),
+			  offset);
+	  break;
+	}
+      if (offset & 3)
+	{
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			 _("pc-relative address offset not word aligned"));
+	  break;
+	}
+      insn = get_aarch64_insn (buf);
+      insn |= encode_pauthauti_imm16 (offset >> 2);
+      put_aarch64_insn (buf, insn);
+      break;
+
     default:
       gas_assert (0);
       as_fatal (_("unhandled operand code %d"), opnd);
diff --git a/gas/testsuite/gas/aarch64/pauth_lr-bad.l b/gas/testsuite/gas/aarch64/pauth_lr-bad.l
index befd2c566d1..3afad8e4327 100644
--- a/gas/testsuite/gas/aarch64/pauth_lr-bad.l
+++ b/gas/testsuite/gas/aarch64/pauth_lr-bad.l
@@ -8,3 +8,11 @@
 .*: Info:    	retaasppcr x0
 .*: Error: unexpected register type at operand 1 -- `retaasppcr sp'
 .*: Error: unexpected register type at operand 1 -- `retaasppcr xzr'
+.*: Error: immediate value must be a multiple of 4 at operand 1 -- `retaasppc 0xff'
+.*: Error: immediate value must be a multiple of 4 at operand 1 -- `retaasppc 0x3fffd'
+.*: Error: immediate value out of range 0 to 65535 at operand 1 -- `retaasppc 0x4fffc'
+.*: Error: immediate value out of range 0 to 65535 at operand 1 -- `retaasppc -0x4'
+.*: Error: negative pc-relative address offset not allowed in this context: -12
+.*: Error: undefined symbol external_symbol used as an immediate value
+.*: Error: pc-relative address offset out of range: 0x40000
+.*: Error: negative pc-relative address offset not allowed in this context: -12
diff --git a/gas/testsuite/gas/aarch64/pauth_lr-bad.s b/gas/testsuite/gas/aarch64/pauth_lr-bad.s
index 4b4539a9354..25661e4a1d2 100644
--- a/gas/testsuite/gas/aarch64/pauth_lr-bad.s
+++ b/gas/testsuite/gas/aarch64/pauth_lr-bad.s
@@ -9,3 +9,18 @@ lr_signing:
 	retaasppcr w0 // 32-bit registers not allowed
 	retaasppcr sp // SP not allowed
 	retaasppcr xzr // zero register not allowed
+
+	// Invalid values
+	retaasppc 0xff // not multiple of 4
+	retaasppc 0x3fffd // max value overflowed but might not be detected due to bit shift
+	retaasppc 0x4fffc // aligned overflow: not possible to represent the value on 16 bits
+
+	retaasppc -0x4  // unsupported negative offset
+	retaasppc .+0xc // future PC target is invalid: encoded offset would be negative
+	retaasppc external_symbol
+
+	.balign 0x40000 // NOP filling
+
+	retaasppc lr_signing // the distance between the label and the reta<k>sppc instruction
+			     // is above the limit that can be encoded (=0x3fffc).
+	retaasppc .+0xc // future PC target is invalid: encoded offset would be negative
diff --git a/gas/testsuite/gas/aarch64/pauth_lr.d b/gas/testsuite/gas/aarch64/pauth_lr.d
index 93ccfd7ee26..cd224169ea4 100644
--- a/gas/testsuite/gas/aarch64/pauth_lr.d
+++ b/gas/testsuite/gas/aarch64/pauth_lr.d
@@ -23,3 +23,16 @@ Disassembly of section \.text:
 .*:	d65f0be0 	retaasppcr	x0
 .*:	d65f0bfe 	retaasppcr	x30
 .*:	d65f0fe0 	retabsppcr	x0
+[^\s]+\s<lr_signing>:
+      40:	f380001f 	autiasppc	40 <lr_signing>
+      44:	f3a0003f 	autibsppc	40 <lr_signing>
+      48:	5500005f 	retaasppc	40 <lr_signing>
+      4c:	5520007f 	retabsppc	40 <lr_signing>
+      50:	5500001f 	retaasppc	50 <lr_signing\+0x10>
+      54:	5500001f 	retaasppc	54 <lr_signing\+0x14>
+      58:	5500003f 	retaasppc	54 <lr_signing\+0x14>
+      5c:	5500011f 	retaasppc	3c <lr_signing-0x4>
+      60:	550002df 	retaasppc	8 <lr_signing-0x38>
+#...
+   40000:	55091a7f 	retaasppc	2dcb4 <lr_signing\+0x2dc74>
+   40004:	551fffff 	retaasppc	8 <lr_signing-0x38>
diff --git a/gas/testsuite/gas/aarch64/pauth_lr.s b/gas/testsuite/gas/aarch64/pauth_lr.s
index 49585e50e6a..495446b52fb 100644
--- a/gas/testsuite/gas/aarch64/pauth_lr.s
+++ b/gas/testsuite/gas/aarch64/pauth_lr.s
@@ -29,3 +29,20 @@
 	retaasppcr x0
 	retaasppcr x30
 	retabsppcr x0
+
+lr_signing:
+	autiasppc lr_signing
+	autibsppc lr_signing
+	retaasppc lr_signing
+	retabsppc lr_signing
+
+	retaasppc 0x0 // min: reference to itself
+	retaasppc .+0x0 // min: current PC + 0
+	retaasppc 0x4 // first valid value after min: point to previous instruction
+	retaasppc 0x20
+	retaasppc .-0x58 // point to pacm
+
+	.balign 0x40000 // NOP filling
+
+	retaasppc 0x1234c // a random value in the valid range
+	retaasppc 0x3fffc // max
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 0248d86f3e4..f61af00aae7 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -732,6 +732,7 @@ enum aarch64_opnd
   AARCH64_OPND_ADDR_ADRP,	/* Memory address for ADRP */
   AARCH64_OPND_ADDR_PCREL9,	/* 9-bit PC-relative address for e.g. CB<cc>.  */
   AARCH64_OPND_ADDR_PCREL14,	/* 14-bit PC-relative address for e.g. TBZ.  */
+  AARCH64_OPND_ADDR_UPCREL16,	/* unsigned 16-bit PC-relative offset (imm16:'00') for e.g. RETA<k>... */
   AARCH64_OPND_ADDR_PCREL19,	/* 19-bit PC-relative address for e.g. LDR.  */
   AARCH64_OPND_ADDR_PCREL21,	/* 21-bit PC-relative address for e.g. ADR.  */
   AARCH64_OPND_ADDR_PCREL26,	/* 26-bit PC-relative address for e.g. BL.  */
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 41f38053275..8c6bfb98e6b 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -2132,6 +2132,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 
 	case AARCH64_OPND_ADDR_PCREL9:
 	case AARCH64_OPND_ADDR_PCREL14:
+	case AARCH64_OPND_ADDR_UPCREL16:
 	case AARCH64_OPND_ADDR_PCREL19:
 	case AARCH64_OPND_ADDR_PCREL21:
 	case AARCH64_OPND_ADDR_PCREL26:
@@ -4532,10 +4533,14 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
 
     case AARCH64_OPND_ADDR_PCREL9:
     case AARCH64_OPND_ADDR_PCREL14:
+    case AARCH64_OPND_ADDR_UPCREL16:
     case AARCH64_OPND_ADDR_PCREL19:
     case AARCH64_OPND_ADDR_PCREL21:
     case AARCH64_OPND_ADDR_PCREL26:
-      addr = pc + AARCH64_PCREL_OFFSET + opnd->imm.value;
+      if (opnd->type == AARCH64_OPND_ADDR_UPCREL16)
+	addr = pc + AARCH64_PCREL_OFFSET - opnd->imm.value;
+      else
+	addr = pc + AARCH64_PCREL_OFFSET + opnd->imm.value;
       if (pcrel_p)
 	*pcrel_p = 1;
       if (address)
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 78c4c4e60f7..d6e709f5817 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -1103,6 +1103,12 @@
   QLF4(V_16B, V_16B, V_16B, imm_0_15),	\
 }
 
+/* e.g. AUTI<k>SPPC <label_imm16:00>  */
+#define QL_PAUTH_IMM16		\
+{				\
+  QLF1(NIL),		\
+}
+
 /* e.g. AUTI<k>SPPCR Xn  */
 #define QL_PAUTH_REG		\
 {				\
@@ -4436,6 +4442,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
   PAUTH_INSN ("eretab", 0xd69f0fff, 0xffffffff, branch_reg, OP0 (), QL_0, F_BRANCH_RET),
   PAUTH_LR_INSN ("retaasppcr", 0xd65f0be0, 0xffffffe0, pauth_lr, OP1 (Rd), QL_PAUTH_REG, F_BRANCH_RET),
   PAUTH_LR_INSN ("retabsppcr", 0xd65f0fe0, 0xffffffe0, pauth_lr, OP1 (Rd), QL_PAUTH_REG, F_BRANCH_RET),
+  PAUTH_LR_INSN ("retaasppc", 0x5500001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_BRANCH_RET),
+  PAUTH_LR_INSN ("retabsppc", 0x5520001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_BRANCH_RET),
   /* Compare & branch (immediate).  */
   CORE_INSN ("cbz", 0x34000000, 0x7f000000, compbranch, 0, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF),
   CORE_INSN ("cbnz", 0x35000000, 0x7f000000, compbranch, 0, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF),
@@ -4543,6 +4551,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
   PAUTH_INSN ("autdb", 0xdac11c00, 0xfffffc00, dp_1src, OP2 (Rd, Rn_SP), QL_I2SAMEX, 0),
   PAUTH_LR_INSN ("autiasppcr", 0xdac1901e, 0xfffffc1f, pauth_lr, OP1 (Rn), QL_PAUTH_REG, F_SUBCLASS_OTHER),
   PAUTH_LR_INSN ("autibsppcr", 0xdac1941e, 0xfffffc1f, pauth_lr, OP1 (Rn), QL_PAUTH_REG, F_SUBCLASS_OTHER),
+  PAUTH_LR_INSN ("autiasppc", 0xf380001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_SUBCLASS_OTHER),
+  PAUTH_LR_INSN ("autibsppc", 0xf3a0001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_SUBCLASS_OTHER),
   PAUTH_LR_INSN ("autia171615", 0xdac1bbfe, 0xffffffff, pauth_lr, OP0 (), {}, F_SUBCLASS_OTHER),
   PAUTH_LR_INSN ("autib171615", 0xdac1bffe, 0xffffffff, pauth_lr, OP0 (), {}, F_SUBCLASS_OTHER),
   PAUTH_INSN ("paciza", 0xdac123e0, 0xffffffe0, dp_1src, OP1 (Rd), QL_I1X, 0),
@@ -8184,6 +8194,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
       F(FLD(5, 9)), "9-bit PC-relative address")			\
     Y(ADDRESS, imm, "ADDR_PCREL14", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\
       F(FLD(5, 14)), "14-bit PC-relative address")			\
+    Y(ADDRESS, imm, "ADDR_UPCREL16", OPD_F_SHIFT_BY_2 | OPD_F_UNSIGNED,	\
+      F(FLD(5, 16)), "unsigned 16-bit PC-relative offset (imm16:'00')")	\
     Y(ADDRESS, imm, "ADDR_PCREL19", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\
       F(FLD(5, 19)), "19-bit PC-relative address")			\
     Y(ADDRESS, imm, "ADDR_PCREL21", OPD_F_SEXT, F(FLD(5, 19), FLD(29, 2)),	\
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.