[aarch64] Add support for pointer authentication B key
[binutils-gdb.git] / gas / config / tc-aarch64.c
index 8621a3356796df098042da5a6237a9d8b4430d82..4c97703f22ea9825b80e36f78a4864fcd0d5caf7 100644 (file)
@@ -1993,6 +1993,14 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+static void
+s_aarch64_cfi_b_key_frame (int ignored ATTRIBUTE_UNUSED)
+{
+  demand_empty_rest_of_line ();
+  struct fde_entry *fde = frchain_now->frch_cfi_data->cur_fde_data;
+  fde->pauth_key = AARCH64_PAUTH_KEY_B;
+}
+
 #ifdef OBJ_ELF
 /* Emit BFD_RELOC_AARCH64_TLSDESC_ADD on the next ADD instruction.  */
 
@@ -2067,6 +2075,7 @@ const pseudo_typeS md_pseudo_table[] = {
   {"arch", s_aarch64_arch, 0},
   {"arch_extension", s_aarch64_arch_extension, 0},
   {"inst", s_aarch64_inst, 0},
+  {"cfi_b_key_frame", s_aarch64_cfi_b_key_frame, 0},
 #ifdef OBJ_ELF
   {"tlsdescadd", s_tlsdescadd, 0},
   {"tlsdesccall", s_tlsdesccall, 0},
@@ -3372,6 +3381,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
      [base,Wm,(S|U)XTW {#imm}]
    Pre-indexed
      [base,#imm]!
+     [base]!                   // in ld/stgv
    Post-indexed
      [base],#imm
      [base],Xm                  // in SIMD ld/st structure
@@ -3680,10 +3690,11 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
     }
 
   /* If at this point neither .preind nor .postind is set, we have a
-     bare [Rn]{!}; reject [Rn]! but accept [Rn] as a shorthand for [Rn,#0].  */
+     bare [Rn]{!}; reject [Rn]! except for ld/stgv but accept [Rn]
+     as a shorthand for [Rn,#0].  */
   if (operand->addr.preind == 0 && operand->addr.postind == 0)
     {
-      if (operand->addr.writeback)
+      if (operand->type != AARCH64_OPND_ADDR_SIMPLE_2 && operand->addr.writeback)
        {
          /* Reject [Rn]!   */
          set_syntax_error (_("missing offset in the pre-indexed address"));
@@ -3933,6 +3944,47 @@ parse_barrier_psb (char **str,
   return 0;
 }
 
+/* Parse an operand for BTI.  Set *HINT_OPT to the hint-option record
+   return 0 if successful.  Otherwise return PARSE_FAIL.  */
+
+static int
+parse_bti_operand (char **str,
+                  const struct aarch64_name_value_pair ** hint_opt)
+{
+  char *p, *q;
+  const struct aarch64_name_value_pair *o;
+
+  p = q = *str;
+  while (ISALPHA (*q))
+    q++;
+
+  o = hash_find_n (aarch64_hint_opt_hsh, p, q - p);
+  if (!o)
+    {
+      set_fatal_syntax_error
+       ( _("unknown option to BTI"));
+      return PARSE_FAIL;
+    }
+
+  switch (o->value)
+    {
+    /* Valid BTI operands.  */
+    case HINT_OPD_C:
+    case HINT_OPD_J:
+    case HINT_OPD_JC:
+      break;
+
+    default:
+      set_syntax_error
+       (_("unknown option to BTI"));
+      return PARSE_FAIL;
+    }
+
+  *str = q;
+  *hint_opt = o;
+  return 0;
+}
+
 /* Parse a system register or a PSTATE field name for an MSR/MRS instruction.
    Returns the encoding for the option, or PARSE_FAIL.
 
@@ -5151,6 +5203,11 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
 
     case AARCH64_OPND_BARRIER_ISB:
       operand->barrier = aarch64_barrier_options + default_value;
+      break;
+
+    case AARCH64_OPND_BTI_TARGET:
+      operand->hint_option = aarch64_hint_options + default_value;
+      break;
 
     default:
       break;
@@ -5696,6 +5753,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SIMM5:
        case AARCH64_OPND_FBITS:
        case AARCH64_OPND_UIMM4:
+       case AARCH64_OPND_UIMM4_ADDG:
+       case AARCH64_OPND_UIMM10:
        case AARCH64_OPND_UIMM3_OP1:
        case AARCH64_OPND_UIMM3_OP2:
        case AARCH64_OPND_IMM_VLSL:
@@ -6089,6 +6148,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_ADDR_SIMPLE:
+       case AARCH64_OPND_ADDR_SIMPLE_2:
        case AARCH64_OPND_SIMD_ADDR_SIMPLE:
          {
            /* [<Xn|SP>{, #<simm>}]  */
@@ -6098,7 +6158,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            po_misc_or_fail (parse_address (&str, info));
            if (info->addr.pcrel || info->addr.offset.is_reg
                || !info->addr.preind || info->addr.postind
-               || info->addr.writeback)
+               || (info->addr.writeback
+                  && operands[i] != AARCH64_OPND_ADDR_SIMPLE_2))
              {
                set_syntax_error (_("invalid addressing mode"));
                goto failure;
@@ -6121,6 +6182,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
                  }
              }
            po_char_or_fail (']');
+           if (operands[i] == AARCH64_OPND_ADDR_SIMPLE_2)
+             po_char_or_fail ('!');
            break;
          }
 
@@ -6166,6 +6229,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_ADDR_SIMM9:
        case AARCH64_OPND_ADDR_SIMM9_2:
+       case AARCH64_OPND_ADDR_SIMM11:
+       case AARCH64_OPND_ADDR_SIMM13:
          po_misc_or_fail (parse_address (&str, info));
          if (info->addr.pcrel || info->addr.offset.is_reg
              || (!info->addr.preind && !info->addr.postind)
@@ -6483,6 +6548,12 @@ sys_reg_ins:
            goto failure;
          break;
 
+       case AARCH64_OPND_BTI_TARGET:
+         val = parse_bti_operand (&str, &(info->hint_option));
+         if (val == PARSE_FAIL)
+           goto failure;
+         break;
+
        default:
          as_fatal (_("unhandled operand code %d"), operands[i]);
        }
@@ -6710,6 +6781,14 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
          && opnds[1].addr.writeback)
        as_warn (_("unpredictable transfer with writeback -- `%s'"), str);
       break;
+
+    case ldstgv_indexed:
+      /* Load operations must load different registers.  */
+      if ((opcode->opcode & (1 << 22))
+         && opnds[0].reg.regno == opnds[1].addr.base_regno)
+           as_warn (_("unpredictable load of register -- `%s'"), str);
+      break;
+
     case ldstpair_off:
     case ldstnapair_offs:
     case ldstpair_indexed:
@@ -6719,6 +6798,8 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
          && (opnds[0].reg.regno == opnds[2].addr.base_regno
            || opnds[1].reg.regno == opnds[2].addr.base_regno)
          && opnds[2].addr.base_regno != REG_SP
+         /* Exempt STGP.  */
+         && !(opnds[2].type == AARCH64_OPND_ADDR_SIMM11)
          && opnds[2].addr.writeback)
            as_warn (_("unpredictable transfer with writeback -- `%s'"), str);
       /* Load operations must load different registers.  */
@@ -7620,6 +7701,8 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value)
     case AARCH64_OPND_ADDR_SIMM9_2:
     case AARCH64_OPND_ADDR_SIMM10:
     case AARCH64_OPND_ADDR_UIMM12:
+    case AARCH64_OPND_ADDR_SIMM11:
+    case AARCH64_OPND_ADDR_SIMM13:
       /* Immediate offset in an address.  */
       insn = get_aarch64_insn (buf);
 
@@ -8773,6 +8856,12 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"sha3",             AARCH64_FEATURE (AARCH64_FEATURE_SHA2
                                         | AARCH64_FEATURE_SHA3, 0),
                        AARCH64_ARCH_NONE},
+  {"rng",              AARCH64_FEATURE (AARCH64_FEATURE_RNG, 0),
+                       AARCH64_ARCH_NONE},
+  {"ssbs",             AARCH64_FEATURE (AARCH64_FEATURE_SSBS, 0),
+                       AARCH64_ARCH_NONE},
+  {"memtag",           AARCH64_FEATURE (AARCH64_FEATURE_MEMTAG, 0),
+                       AARCH64_ARCH_NONE},
   {NULL,               AARCH64_ARCH_NONE, AARCH64_ARCH_NONE},
 };