[gas][aarch64] Armv8.6-a option [1/X]
[deliverable/binutils-gdb.git] / gas / config / tc-aarch64.c
index 5d53064cf488dbf7e35607c20d5121c2f3508aba..fb1ec0bcc31116cb320fe2530bdc74995b0bf7dc 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-aarch64.c -- Assemble for the AArch64 ISA
 
-   Copyright (C) 2009-2016 Free Software Foundation, Inc.
+   Copyright (C) 2009-2019 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of GAS.
@@ -55,6 +55,9 @@ static const aarch64_feature_set *march_cpu_opt = NULL;
 /* Constants for known architecture features.  */
 static const aarch64_feature_set cpu_default = CPU_DEFAULT;
 
+/* Currently active instruction sequence.  */
+static aarch64_instr_sequence *insn_sequence = NULL;
+
 #ifdef OBJ_ELF
 /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 static symbolS *GOT_symbol;
@@ -62,12 +65,20 @@ static symbolS *GOT_symbol;
 /* Which ABI to use.  */
 enum aarch64_abi_type
 {
-  AARCH64_ABI_LP64 = 0,
-  AARCH64_ABI_ILP32 = 1
+  AARCH64_ABI_NONE = 0,
+  AARCH64_ABI_LP64 = 1,
+  AARCH64_ABI_ILP32 = 2
 };
 
+#ifndef DEFAULT_ARCH
+#define DEFAULT_ARCH "aarch64"
+#endif
+
+/* DEFAULT_ARCH is initialized in gas/configure.tgt.  */
+static const char *default_arch = DEFAULT_ARCH;
+
 /* AArch64 ABI for the output file.  */
-static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_LP64;
+static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_NONE;
 
 /* When non-zero, program to a 32-bit model, in which the C data types
    int, long and all pointer types are 32-bit objects (ILP32); or to a
@@ -138,9 +149,16 @@ static aarch64_instruction inst;
 static bfd_boolean parse_operands (char *, const aarch64_opcode *);
 static bfd_boolean programmer_friendly_fixup (aarch64_instruction *);
 
-/* Diagnostics inline function utilites.
+#ifdef OBJ_ELF
+#  define now_instr_sequence seg_info \
+               (now_seg)->tc_segment_info_data.insn_sequence
+#else
+static struct aarch64_instr_sequence now_instr_sequence;
+#endif
+
+/* Diagnostics inline function utilities.
 
-   These are lightweight utlities which should only be called by parse_operands
+   These are lightweight utilities which should only be called by parse_operands
    and other parsers.  GAS processes each assembly line by parsing it against
    instruction template(s), in the case of multiple templates (for the same
    mnemonic name), those templates are tried one by one until one succeeds or
@@ -151,7 +169,7 @@ static bfd_boolean programmer_friendly_fixup (aarch64_instruction *);
    the parsing; we don't want to slow down the whole parsing by recording
    non-user errors in detail.
 
-   Remember that the objective is to help GAS pick up the most approapriate
+   Remember that the objective is to help GAS pick up the most appropriate
    error message in the case of multiple templates, e.g. FMOV which has 8
    templates.  */
 
@@ -220,9 +238,6 @@ set_fatal_syntax_error (const char *error)
   set_error (AARCH64_OPDE_FATAL_SYNTAX_ERROR, error);
 }
 \f
-/* Number of littlenums required to hold an extended precision number.  */
-#define MAX_LITTLENUMS 6
-
 /* Return value for certain parsers when the parsing fails; those parsers
    return the information of the parsed result, e.g. register number, on
    success.  */
@@ -266,7 +281,6 @@ struct reloc_entry
   BASIC_REG_TYPE(FP_S) /* s[0-31] */   \
   BASIC_REG_TYPE(FP_D) /* d[0-31] */   \
   BASIC_REG_TYPE(FP_Q) /* q[0-31] */   \
-  BASIC_REG_TYPE(CN)   /* c[0-7]  */   \
   BASIC_REG_TYPE(VN)   /* v[0-31] */   \
   BASIC_REG_TYPE(ZN)   /* z[0-31] */   \
   BASIC_REG_TYPE(PN)   /* p[0-15] */   \
@@ -297,10 +311,11 @@ struct reloc_entry
                 | REG_TYPE(Z_32) | REG_TYPE(Z_64) | REG_TYPE(VN)       \
                 | REG_TYPE(FP_B) | REG_TYPE(FP_H)                      \
                 | REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q))    \
-  /* Typecheck: as above, but also Zn and Pn.  This should only be     \
-     used for SVE instructions, since Zn and Pn are valid symbols      \
+  /* Typecheck: as above, but also Zn, Pn, and {W}SP.  This should only        \
+     be used for SVE instructions, since Zn and Pn are valid symbols   \
      in other contexts.  */                                            \
-  MULTI_REG_TYPE(R_Z_BHSDQ_VZP, REG_TYPE(R_32) | REG_TYPE(R_64)                \
+  MULTI_REG_TYPE(R_Z_SP_BHSDQ_VZP, REG_TYPE(R_32) | REG_TYPE(R_64)     \
+                | REG_TYPE(SP_32) | REG_TYPE(SP_64)                    \
                 | REG_TYPE(Z_32) | REG_TYPE(Z_64) | REG_TYPE(VN)       \
                 | REG_TYPE(FP_B) | REG_TYPE(FP_H)                      \
                 | REG_TYPE(FP_S) | REG_TYPE(FP_D) | REG_TYPE(FP_Q)     \
@@ -407,11 +422,8 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
       msg = N_("128-bit SIMD scalar or floating-point quad precision "
               "register expected");
       break;
-    case REG_TYPE_CN:
-      msg = N_("C0 - C15 expected");
-      break;
     case REG_TYPE_R_Z_BHSDQ_V:
-    case REG_TYPE_R_Z_BHSDQ_VZP:
+    case REG_TYPE_R_Z_SP_BHSDQ_VZP:
       msg = N_("register expected");
       break;
     case REG_TYPE_BHSDQ:       /* any [BHSDQ]P FP  */
@@ -434,6 +446,7 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
 
 /* Some well known registers that we refer to directly elsewhere.  */
 #define REG_SP 31
+#define REG_ZR 31
 
 /* Instructions take 4 bytes in the object file.  */
 #define INSN_SIZE      4
@@ -447,6 +460,7 @@ static struct hash_control *aarch64_sys_regs_ic_hsh;
 static struct hash_control *aarch64_sys_regs_dc_hsh;
 static struct hash_control *aarch64_sys_regs_at_hsh;
 static struct hash_control *aarch64_sys_regs_tlbi_hsh;
+static struct hash_control *aarch64_sys_regs_sr_hsh;
 static struct hash_control *aarch64_reg_hsh;
 static struct hash_control *aarch64_barrier_opt_hsh;
 static struct hash_control *aarch64_nzcv_hsh;
@@ -515,7 +529,7 @@ const char EXP_CHARS[] = "eE";
 /* As in 0f12.456  */
 /* or   0d1.2345e12  */
 
-const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
+const char FLT_CHARS[] = "rRsSfFdDxXeEpPhH";
 
 /* Prefix character that indicates the start of an immediate value.  */
 #define is_immediate_prefix(C) ((C) == '#')
@@ -647,7 +661,7 @@ first_error (const char *error)
     set_syntax_error (error);
 }
 
-/* Similiar to first_error, but this function accepts formatted error
+/* Similar to first_error, but this function accepts formatted error
    message.  */
 static void
 first_error_fmt (const char *format, ...)
@@ -794,7 +808,7 @@ aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
    succeeds; otherwise return FALSE.
 
    Accept only one occurrence of:
-   8b 16b 2h 4h 8h 2s 4s 1d 2d
+   4b 8b 16b 2h 4h 8h 2s 4s 1d 2d
    b h s d q  */
 static bfd_boolean
 parse_vector_type_for_operand (aarch64_reg_type reg_type,
@@ -841,7 +855,7 @@ elt_size:
       element_size = 64;
       break;
     case 'q':
-      if (width == 1)
+      if (reg_type == REG_TYPE_ZN || width == 1)
        {
          type = NT_q;
          element_size = 128;
@@ -855,8 +869,10 @@ elt_size:
        first_error (_("missing element size"));
       return FALSE;
     }
-  if (width != 0 && width * element_size != 64 && width * element_size != 128
-      && !(width == 2 && element_size == 16))
+  if (width != 0 && width * element_size != 64
+      && width * element_size != 128
+      && !(width == 2 && element_size == 16)
+      && !(width == 4 && element_size == 8))
     {
       first_error_fmt (_
                       ("invalid element size %d and vector size combination %c"),
@@ -976,7 +992,7 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
        /* Expect index. In the new scheme we cannot have
           Vn.[bhsdq] represent a scalar. Therefore any
           Vn.[bhsdq] should have an index following it.
-          Except in reglists ofcourse.  */
+          Except in reglists of course.  */
        atype.defined |= NTA_HASINDEX;
       else
        atype.defined |= NTA_HASTYPE;
@@ -996,7 +1012,7 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
          return PARSE_FAIL;
        }
 
-      if (in_reg_list == TRUE)
+      if (in_reg_list)
        {
          first_error (_("index not allowed inside register list"));
          return PARSE_FAIL;
@@ -1748,7 +1764,7 @@ add_to_lit_pool (expressionS *exp, int size)
 }
 
 /* Can't use symbol_new here, so have to create a symbol and then at
-   a later date assign it a value. Thats what these functions do.  */
+   a later date assign it a value. That's what these functions do.  */
 
 static void
 symbol_locate (symbolS * symbolP,
@@ -1920,6 +1936,28 @@ s_aarch64_elf_cons (int nbytes)
   demand_empty_rest_of_line ();
 }
 
+/* Mark symbol that it follows a variant PCS convention.  */
+
+static void
+s_variant_pcs (int ignored ATTRIBUTE_UNUSED)
+{
+  char *name;
+  char c;
+  symbolS *sym;
+  asymbol *bfdsym;
+  elf_symbol_type *elfsym;
+
+  c = get_symbol_name (&name);
+  if (!*name)
+    as_bad (_("Missing symbol name in directive"));
+  sym = symbol_find_or_make (name);
+  restore_line_pointer (c);
+  demand_empty_rest_of_line ();
+  bfdsym = symbol_get_bfdsym (sym);
+  elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+  gas_assert (elfsym);
+  elfsym->internal_elf_sym.st_other |= STO_AARCH64_VARIANT_PCS;
+}
 #endif /* OBJ_ELF */
 
 /* Output a 32-bit word, but mark as an instruction.  */
@@ -1975,6 +2013,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.  */
 
@@ -2049,6 +2095,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},
@@ -2057,7 +2104,9 @@ const pseudo_typeS md_pseudo_table[] = {
   {"long", s_aarch64_elf_cons, 4},
   {"xword", s_aarch64_elf_cons, 8},
   {"dword", s_aarch64_elf_cons, 8},
+  {"variant_pcs", s_variant_pcs, 0},
 #endif
+  {"float16", float_cons, 'h'},
   {0, 0, 0}
 };
 \f
@@ -2272,7 +2321,6 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
   char *str = *ccp;
   char *fpnum;
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  int found_fpchar = 0;
   int64_t val = 0;
   unsigned fpword = 0;
   bfd_boolean hex_p = FALSE;
@@ -2302,26 +2350,10 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p,
 
       hex_p = TRUE;
     }
-  else
-    {
-      if (reg_name_p (str, reg_type))
-       {
-         set_recoverable_error (_("immediate operand required"));
-         return FALSE;
-       }
-
-      /* We must not accidentally parse an integer as a floating-point number.
-        Make sure that the value we parse is not an integer by checking for
-        special characters '.' or 'e'.  */
-      for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
-       if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
-         {
-           found_fpchar = 1;
-           break;
-         }
-
-      if (!found_fpchar)
-       return FALSE;
+  else if (reg_name_p (str, reg_type))
+   {
+     set_recoverable_error (_("immediate operand required"));
+     return FALSE;
     }
 
   if (! hex_p)
@@ -2402,7 +2434,7 @@ aarch64_gas_internal_fixup_p (void)
   return inst.reloc.type == BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP;
 }
 
-/* Assign the immediate value to the relavant field in *OPERAND if
+/* Assign the immediate value to the relevant field in *OPERAND if
    RELOC->EXP is a constant expression; otherwise, flag that *OPERAND
    needs an internal fixup in a later stage.
    ADDR_OFF_P determines whether it is the field ADDR.OFFSET.IMM or
@@ -2570,6 +2602,69 @@ static struct reloc_table_entry reloc_table[] = {
    0,
    0},
 
+  /* Most significant bits 0-15 of signed/unsigned address/value: MOVZ */
+  {"prel_g0", 1,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_PREL_G0,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 0-15 of signed/unsigned address/value: MOVK */
+  {"prel_g0_nc", 1,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_PREL_G0_NC,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 16-31 of signed/unsigned address/value: MOVZ */
+  {"prel_g1", 1,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_PREL_G1,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 16-31 of signed/unsigned address/value: MOVK */
+  {"prel_g1_nc", 1,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_PREL_G1_NC,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 32-47 of signed/unsigned address/value: MOVZ */
+  {"prel_g2", 1,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_PREL_G2,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 32-47 of signed/unsigned address/value: MOVK */
+  {"prel_g2_nc", 1,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_PREL_G2_NC,
+   0,
+   0,
+   0},
+
+  /* Most significant bits 48-63 of signed/unsigned address/value: MOVZ */
+  {"prel_g3", 1,
+   0,                          /* adr_type */
+   0,
+   BFD_RELOC_AARCH64_MOVW_PREL_G3,
+   0,
+   0,
+   0},
+
   /* Get to the page containing GOT entry for a symbol.  */
   {"got", 1,
    0,                          /* adr_type */
@@ -2683,14 +2778,14 @@ static struct reloc_table_entry reloc_table[] = {
    0,                          /* adr_type */
    0,
    0,
-   BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC,
+   BFD_RELOC_AARCH64_TLSDESC_ADD_LO12,
    BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC,
    0},
 
   /* Get to the page containing GOT TLS entry for a symbol.
      The same as GD, we allocate two consecutive GOT slots
      for module index and module offset, the only difference
-     with GD is the module offset should be intialized to
+     with GD is the module offset should be initialized to
      zero without any outstanding runtime relocation. */
   {"tlsldm", 0,
    BFD_RELOC_AARCH64_TLSLD_ADR_PREL21, /* adr_type */
@@ -2832,7 +2927,7 @@ static struct reloc_table_entry reloc_table[] = {
    0,
    0,
    BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12,
-   0,
+   BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12,
    0},
 
   /* Get tp offset for a symbol.  */
@@ -2850,7 +2945,7 @@ static struct reloc_table_entry reloc_table[] = {
    0,
    0,
    BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC,
-   0,
+   BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC,
    0},
 
   /* Most significant bits 32-47 of address/value: MOVZ.  */
@@ -3005,7 +3100,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode)
   switch (mode)
     {
     case SHIFTED_LOGIC_IMM:
-      if (aarch64_extend_operator_p (kind) == TRUE)
+      if (aarch64_extend_operator_p (kind))
        {
          set_syntax_error (_("extending shift is not permitted"));
          return FALSE;
@@ -3096,7 +3191,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode)
     operand->shifter.amount = 1;
   else if (exp.X_op == O_absent)
     {
-      if (aarch64_extend_operator_p (kind) == FALSE || exp_has_prefix)
+      if (!aarch64_extend_operator_p (kind) || exp_has_prefix)
        {
          set_syntax_error (_("missing shift amount"));
          return FALSE;
@@ -3307,6 +3402,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
      [base,Xm,SXTX {#imm}]
      [base,Wm,(S|U)XTW {#imm}]
    Pre-indexed
+     [base]!                    // in ldraa/ldrab exclusive
      [base,#imm]!
    Post-indexed
      [base],#imm
@@ -3320,6 +3416,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
      [base,Zm.D,(S|U)XTW {#imm}] // ignores top 32 bits of Zm.D elements
      [Zn.S,#imm]
      [Zn.D,#imm]
+     [Zn.S{, Xm}]
      [Zn.S,Zm.S{,LSL #imm}]      // in ADR
      [Zn.D,Zm.D{,LSL #imm}]      // in ADR
      [Zn.D,Zm.D,(S|U)XTW {#imm}] // in ADR
@@ -3485,6 +3582,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
                return FALSE;
            }
          /* We only accept:
+            [base,Xm]  # For vector plus scalar SVE2 indexing.
             [base,Xm{,LSL #imm}]
             [base,Xm,SXTX {#imm}]
             [base,Wm,(S|U)XTW {#imm}]  */
@@ -3498,7 +3596,10 @@ parse_address_main (char **str, aarch64_opnd_info *operand,
                  return FALSE;
                }
              if (aarch64_get_qualifier_esize (*base_qualifier)
-                 != aarch64_get_qualifier_esize (*offset_qualifier))
+                 != aarch64_get_qualifier_esize (*offset_qualifier)
+                 && (operand->type != AARCH64_OPND_SVE_ADDR_ZX
+                     || *base_qualifier != AARCH64_OPND_QLF_S_S
+                     || *offset_qualifier != AARCH64_OPND_QLF_X))
                {
                  set_syntax_error (_("offset has different size from base"));
                  return FALSE;
@@ -3616,18 +3717,43 @@ 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]{!}; only accept [Rn]! as a shorthand for [Rn,#0]! for ldraa and
+     ldrab, accept [Rn] as a shorthand for [Rn,#0].
+     For SVE2 vector plus scalar offsets, allow [Zn.<T>] as shorthand for
+     [Zn.<T>, xzr].  */
   if (operand->addr.preind == 0 && operand->addr.postind == 0)
     {
       if (operand->addr.writeback)
        {
-         /* Reject [Rn]!   */
-         set_syntax_error (_("missing offset in the pre-indexed address"));
-         return FALSE;
+         if (operand->type == AARCH64_OPND_ADDR_SIMM10)
+            {
+              /* Accept [Rn]! as a shorthand for [Rn,#0]!   */
+              operand->addr.offset.is_reg = 0;
+              operand->addr.offset.imm = 0;
+              operand->addr.preind = 1;
+            }
+          else
+           {
+            /* Reject [Rn]!   */
+            set_syntax_error (_("missing offset in the pre-indexed address"));
+            return FALSE;
+          }
+       }
+       else
+       {
+          operand->addr.preind = 1;
+          if (operand->type == AARCH64_OPND_SVE_ADDR_ZX)
+          {
+            operand->addr.offset.is_reg = 1;
+            operand->addr.offset.regno = REG_ZR;
+            *offset_qualifier = AARCH64_OPND_QLF_X;
+          }
+          else
+          {
+            inst.reloc.exp.X_op = O_constant;
+            inst.reloc.exp.X_add_number = 0;
+          }
        }
-      operand->addr.preind = 1;
-      inst.reloc.exp.X_op = O_constant;
-      inst.reloc.exp.X_add_number = 0;
     }
 
   *str = p;
@@ -3868,6 +3994,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.
 
@@ -3880,7 +4047,8 @@ parse_barrier_psb (char **str,
 
 static int
 parse_sys_reg (char **str, struct hash_control *sys_regs,
-              int imple_defined_p, int pstatefield_p)
+              int imple_defined_p, int pstatefield_p,
+              uint32_t* flags)
 {
   char *p, *q;
   char buf[32];
@@ -3911,6 +4079,8 @@ parse_sys_reg (char **str, struct hash_control *sys_regs,
          if (op0 > 3 || op1 > 7 || cn > 15 || cm > 15 || op2 > 7)
            return PARSE_FAIL;
          value = (op0 << 14) | (op1 << 11) | (cn << 7) | (cm << 3) | op2;
+         if (flags)
+           *flags = 0;
        }
     }
   else
@@ -3925,6 +4095,8 @@ parse_sys_reg (char **str, struct hash_control *sys_regs,
        as_warn (_("system register name '%s' is deprecated and may be "
                   "removed in a future release"), buf);
       value = o->value;
+      if (flags)
+       *flags = o->flags;
     }
 
   *str = q;
@@ -4207,7 +4379,7 @@ reset_aarch64_instruction (aarch64_instruction *instruction)
   instruction->reloc.type = BFD_RELOC_UNUSED;
 }
 
-/* Data strutures storing one user error in the assembly code related to
+/* Data structures storing one user error in the assembly code related to
    operands.  */
 
 struct operand_error_record
@@ -4341,6 +4513,7 @@ record_operand_error (const aarch64_opcode *opcode, int idx,
   info.index = idx;
   info.kind = kind;
   info.error = error;
+  info.non_fatal = FALSE;
   record_operand_error_info (opcode, &info);
 }
 
@@ -4356,6 +4529,7 @@ record_operand_error_with_data (const aarch64_opcode *opcode, int idx,
   info.data[0] = extra_data[0];
   info.data[1] = extra_data[1];
   info.data[2] = extra_data[2];
+  info.non_fatal = FALSE;
   record_operand_error_info (opcode, &info);
 }
 
@@ -4417,7 +4591,7 @@ find_best_match (const aarch64_inst *instr,
       const aarch64_opnd_qualifier_t *qualifiers = *qualifiers_list;
 
       /* Most opcodes has much fewer patterns in the list.  */
-      if (empty_qualifier_sequence_p (qualifiers) == TRUE)
+      if (empty_qualifier_sequence_p (qualifiers))
        {
          DEBUG_TRACE_IF (i == 0, "empty list of qualifier sequence");
          break;
@@ -4438,7 +4612,7 @@ find_best_match (const aarch64_inst *instr,
   return idx;
 }
 
-/* Assign qualifiers in the qualifier seqence (headed by QUALIFIERS) to the
+/* Assign qualifiers in the qualifier sequence (headed by QUALIFIERS) to the
    corresponding operands in *INSTR.  */
 
 static inline void
@@ -4474,7 +4648,8 @@ print_operands (char *buf, const aarch64_opcode *opcode,
        break;
 
       /* Generate the operand string in STR.  */
-      aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL);
+      aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL,
+                            NULL);
 
       /* Delimiter.  */
       if (str[0] != '\0')
@@ -4520,12 +4695,14 @@ output_operand_error_record (const operand_error_record *record, char *str)
   enum aarch64_opnd opd_code = (idx >= 0 ? opcode->operands[idx]
                                : AARCH64_OPND_NIL);
 
+  typedef void (*handler_t)(const char *format, ...);
+  handler_t handler = detail->non_fatal ? as_warn : as_bad;
+
   switch (detail->kind)
     {
     case AARCH64_OPDE_NIL:
       gas_assert (0);
       break;
-
     case AARCH64_OPDE_SYNTAX_ERROR:
     case AARCH64_OPDE_RECOVERABLE:
     case AARCH64_OPDE_FATAL_SYNTAX_ERROR:
@@ -4535,21 +4712,21 @@ output_operand_error_record (const operand_error_record *record, char *str)
       if (detail->error != NULL)
        {
          if (idx < 0)
-           as_bad (_("%s -- `%s'"), detail->error, str);
+           handler (_("%s -- `%s'"), detail->error, str);
          else
-           as_bad (_("%s at operand %d -- `%s'"),
-                   detail->error, idx + 1, str);
+           handler (_("%s at operand %d -- `%s'"),
+                    detail->error, idx + 1, str);
        }
       else
        {
          gas_assert (idx >= 0);
-         as_bad (_("operand %d must be %s -- `%s'"), idx + 1,
-               aarch64_get_operand_desc (opd_code), str);
+         handler (_("operand %d must be %s -- `%s'"), idx + 1,
+                  aarch64_get_operand_desc (opd_code), str);
        }
       break;
 
     case AARCH64_OPDE_INVALID_VARIANT:
-      as_bad (_("operand mismatch -- `%s'"), str);
+      handler (_("operand mismatch -- `%s'"), str);
       if (verbose_error_p)
        {
          /* We will try to correct the erroneous instruction and also provide
@@ -4597,7 +4774,7 @@ output_operand_error_record (const operand_error_record *record, char *str)
            && programmer_friendly_fixup (&inst);
          gas_assert (result);
          result = aarch64_opcode_encode (opcode, inst_base, &inst_base->value,
-                                         NULL, NULL);
+                                         NULL, NULL, insn_sequence);
          gas_assert (!result);
 
          /* Find the most matched qualifier sequence.  */
@@ -4625,7 +4802,7 @@ output_operand_error_record (const operand_error_record *record, char *str)
            {
              /* Most opcodes has much fewer patterns in the list.
                 First NIL qualifier indicates the end in the list.   */
-             if (empty_qualifier_sequence_p (*qualifiers_list) == TRUE)
+             if (empty_qualifier_sequence_p (*qualifiers_list))
                break;
 
              if (i != qlf_idx)
@@ -4646,36 +4823,36 @@ output_operand_error_record (const operand_error_record *record, char *str)
       break;
 
     case AARCH64_OPDE_UNTIED_OPERAND:
-      as_bad (_("operand %d must be the same register as operand 1 -- `%s'"),
-             detail->index + 1, str);
+      handler (_("operand %d must be the same register as operand 1 -- `%s'"),
+              detail->index + 1, str);
       break;
 
     case AARCH64_OPDE_OUT_OF_RANGE:
       if (detail->data[0] != detail->data[1])
-       as_bad (_("%s out of range %d to %d at operand %d -- `%s'"),
-               detail->error ? detail->error : _("immediate value"),
-               detail->data[0], detail->data[1], idx + 1, str);
+       handler (_("%s out of range %d to %d at operand %d -- `%s'"),
+                detail->error ? detail->error : _("immediate value"),
+                detail->data[0], detail->data[1], idx + 1, str);
       else
-       as_bad (_("%s must be %d at operand %d -- `%s'"),
-               detail->error ? detail->error : _("immediate value"),
-               detail->data[0], idx + 1, str);
+       handler (_("%s must be %d at operand %d -- `%s'"),
+                detail->error ? detail->error : _("immediate value"),
+                detail->data[0], idx + 1, str);
       break;
 
     case AARCH64_OPDE_REG_LIST:
       if (detail->data[0] == 1)
-       as_bad (_("invalid number of registers in the list; "
-                 "only 1 register is expected at operand %d -- `%s'"),
-               idx + 1, str);
+       handler (_("invalid number of registers in the list; "
+                  "only 1 register is expected at operand %d -- `%s'"),
+                idx + 1, str);
       else
-       as_bad (_("invalid number of registers in the list; "
-                 "%d registers are expected at operand %d -- `%s'"),
-             detail->data[0], idx + 1, str);
+       handler (_("invalid number of registers in the list; "
+                  "%d registers are expected at operand %d -- `%s'"),
+              detail->data[0], idx + 1, str);
       break;
 
     case AARCH64_OPDE_UNALIGNED:
-      as_bad (_("immediate value must be a multiple of "
-               "%d at operand %d -- `%s'"),
-             detail->data[0], idx + 1, str);
+      handler (_("immediate value must be a multiple of "
+                "%d at operand %d -- `%s'"),
+              detail->data[0], idx + 1, str);
       break;
 
     default:
@@ -4688,11 +4865,16 @@ output_operand_error_record (const operand_error_record *record, char *str)
 
    When this function is called, the operand error information had
    been collected for an assembly line and there will be multiple
-   errors in the case of mulitple instruction templates; output the
-   error message that most closely describes the problem.  */
+   errors in the case of multiple instruction templates; output the
+   error message that most closely describes the problem.
+
+   The errors to be printed can be filtered on printing all errors
+   or only non-fatal errors.  This distinction has to be made because
+   the error buffer may already be filled with fatal errors we don't want to
+   print due to the different instruction templates.  */
 
 static void
-output_operand_error_report (char *str)
+output_operand_error_report (char *str, bfd_boolean non_fatal_only)
 {
   int largest_error_pos;
   const char *msg = NULL;
@@ -4710,29 +4892,39 @@ output_operand_error_report (char *str)
   /* Only one error.  */
   if (head == operand_error_report.tail)
     {
-      DEBUG_TRACE ("single opcode entry with error kind: %s",
-                  operand_mismatch_kind_names[head->detail.kind]);
-      output_operand_error_record (head, str);
+      /* If the only error is a non-fatal one and we don't want to print it,
+        just exit.  */
+      if (!non_fatal_only || head->detail.non_fatal)
+       {
+         DEBUG_TRACE ("single opcode entry with error kind: %s",
+                      operand_mismatch_kind_names[head->detail.kind]);
+         output_operand_error_record (head, str);
+       }
       return;
     }
 
   /* Find the error kind of the highest severity.  */
-  DEBUG_TRACE ("multiple opcode entres with error kind");
+  DEBUG_TRACE ("multiple opcode entries with error kind");
   kind = AARCH64_OPDE_NIL;
   for (curr = head; curr != NULL; curr = curr->next)
     {
       gas_assert (curr->detail.kind != AARCH64_OPDE_NIL);
       DEBUG_TRACE ("\t%s", operand_mismatch_kind_names[curr->detail.kind]);
-      if (operand_error_higher_severity_p (curr->detail.kind, kind))
+      if (operand_error_higher_severity_p (curr->detail.kind, kind)
+         && (!non_fatal_only || (non_fatal_only && curr->detail.non_fatal)))
        kind = curr->detail.kind;
     }
-  gas_assert (kind != AARCH64_OPDE_NIL);
+
+  gas_assert (kind != AARCH64_OPDE_NIL || non_fatal_only);
 
   /* Pick up one of errors of KIND to report.  */
   largest_error_pos = -2; /* Index can be -1 which means unknown index.  */
   for (curr = head; curr != NULL; curr = curr->next)
     {
-      if (curr->detail.kind != kind)
+      /* If we don't want to print non-fatal errors then don't consider them
+        at all.  */
+      if (curr->detail.kind != kind
+         || (non_fatal_only && !curr->detail.non_fatal))
        continue;
       /* If there are multiple errors, pick up the one with the highest
         mismatching operand index.  In the case of multiple errors with
@@ -4748,6 +4940,17 @@ output_operand_error_report (char *str)
        }
     }
 
+  /* The way errors are collected in the back-end is a bit non-intuitive.  But
+     essentially, because each operand template is tried recursively you may
+     always have errors collected from the previous tried OPND.  These are
+     usually skipped if there is one successful match.  However now with the
+     non-fatal errors we have to ignore those previously collected hard errors
+     when we're only interested in printing the non-fatal ones.  This condition
+     prevents us from printing errors that are not appropriate, since we did
+     match a condition, but it also has warnings that it wants to print.  */
+  if (non_fatal_only && !record)
+    return;
+
   gas_assert (largest_error_pos != -2 && record != NULL);
   DEBUG_TRACE ("Pick up error kind %s to report",
               operand_mismatch_kind_names[record->detail.kind]);
@@ -4904,7 +5107,7 @@ vectype_to_qualifier (const struct vector_type_el *vectype)
     = {1, 2, 4, 8, 16};
   const unsigned int ele_base [5] =
     {
-      AARCH64_OPND_QLF_V_8B,
+      AARCH64_OPND_QLF_V_4B,
       AARCH64_OPND_QLF_V_2H,
       AARCH64_OPND_QLF_V_2S,
       AARCH64_OPND_QLF_V_1D,
@@ -4922,8 +5125,14 @@ vectype_to_qualifier (const struct vector_type_el *vectype)
   gas_assert (vectype->type >= NT_b && vectype->type <= NT_q);
 
   if (vectype->defined & (NTA_HASINDEX | NTA_HASVARWIDTH))
-    /* Vector element register.  */
-    return AARCH64_OPND_QLF_S_B + vectype->type;
+    {
+      /* Special case S_4B.  */
+      if (vectype->type == NT_b && vectype->width == 4)
+       return AARCH64_OPND_QLF_S_4B;
+
+      /* Vector element register.  */
+      return AARCH64_OPND_QLF_S_B + vectype->type;
+    }
   else
     {
       /* Vector register.  */
@@ -4939,7 +5148,7 @@ vectype_to_qualifier (const struct vector_type_el *vectype)
         a vector-type dependent amount.  */
       shift = 0;
       if (vectype->type == NT_b)
-       shift = 4;
+       shift = 3;
       else if (vectype->type == NT_h || vectype->type == NT_s)
        shift = 2;
       else if (vectype->type >= NT_d)
@@ -4948,7 +5157,7 @@ vectype_to_qualifier (const struct vector_type_el *vectype)
        gas_assert (0);
 
       offset = ele_base [vectype->type] + (vectype->width >> shift);
-      gas_assert (AARCH64_OPND_QLF_V_8B <= offset
+      gas_assert (AARCH64_OPND_QLF_V_4B <= offset
                  && offset <= AARCH64_OPND_QLF_V_1Q);
       return offset;
     }
@@ -4978,11 +5187,13 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
     case AARCH64_OPND_Rm:
     case AARCH64_OPND_Rt:
     case AARCH64_OPND_Rt2:
+    case AARCH64_OPND_Rt_SP:
     case AARCH64_OPND_Rs:
     case AARCH64_OPND_Ra:
     case AARCH64_OPND_Rt_SYS:
     case AARCH64_OPND_Rd_SP:
     case AARCH64_OPND_Rn_SP:
+    case AARCH64_OPND_Rm_SP:
     case AARCH64_OPND_Fd:
     case AARCH64_OPND_Fn:
     case AARCH64_OPND_Fm:
@@ -4992,6 +5203,7 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
     case AARCH64_OPND_Sd:
     case AARCH64_OPND_Sn:
     case AARCH64_OPND_Sm:
+    case AARCH64_OPND_Va:
     case AARCH64_OPND_Vd:
     case AARCH64_OPND_Vn:
     case AARCH64_OPND_Vm:
@@ -5003,6 +5215,8 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
     case AARCH64_OPND_Ed:
     case AARCH64_OPND_En:
     case AARCH64_OPND_Em:
+    case AARCH64_OPND_Em16:
+    case AARCH64_OPND_SM3_IMM2:
       operand->reglane.regno = default_value;
       break;
 
@@ -5019,6 +5233,7 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
     case AARCH64_OPND_UIMM3_OP1:
     case AARCH64_OPND_UIMM3_OP2:
     case AARCH64_OPND_IMM:
+    case AARCH64_OPND_IMM_2:
     case AARCH64_OPND_WIDTH:
     case AARCH64_OPND_UIMM7:
     case AARCH64_OPND_NZCV:
@@ -5039,6 +5254,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;
@@ -5062,6 +5282,10 @@ process_movw_reloc_info (void)
       case BFD_RELOC_AARCH64_MOVW_G0_S:
       case BFD_RELOC_AARCH64_MOVW_G1_S:
       case BFD_RELOC_AARCH64_MOVW_G2_S:
+      case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+      case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+      case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+      case BFD_RELOC_AARCH64_MOVW_PREL_G3:
       case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
@@ -5079,6 +5303,8 @@ process_movw_reloc_info (void)
     case BFD_RELOC_AARCH64_MOVW_G0_NC:
     case BFD_RELOC_AARCH64_MOVW_G0_S:
     case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC:
     case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
     case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
     case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
@@ -5092,6 +5318,8 @@ process_movw_reloc_info (void)
     case BFD_RELOC_AARCH64_MOVW_G1_NC:
     case BFD_RELOC_AARCH64_MOVW_G1_S:
     case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC:
     case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
     case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
     case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
@@ -5104,6 +5332,8 @@ process_movw_reloc_info (void)
     case BFD_RELOC_AARCH64_MOVW_G2:
     case BFD_RELOC_AARCH64_MOVW_G2_NC:
     case BFD_RELOC_AARCH64_MOVW_G2_S:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC:
     case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
       if (is32)
@@ -5116,6 +5346,7 @@ process_movw_reloc_info (void)
       shift = 32;
       break;
     case BFD_RELOC_AARCH64_MOVW_G3:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G3:
       if (is32)
        {
          set_fatal_syntax_error
@@ -5136,7 +5367,7 @@ process_movw_reloc_info (void)
   return TRUE;
 }
 
-/* A primitive log caculator.  */
+/* A primitive log calculator.  */
 
 static inline unsigned int
 get_logsz (unsigned int size)
@@ -5162,7 +5393,7 @@ ldst_lo12_determine_real_reloc_type (void)
   enum aarch64_opnd_qualifier opd0_qlf = inst.base.operands[0].qualifier;
   enum aarch64_opnd_qualifier opd1_qlf = inst.base.operands[1].qualifier;
 
-  const bfd_reloc_code_real_type reloc_ldst_lo12[3][5] = {
+  const bfd_reloc_code_real_type reloc_ldst_lo12[5][5] = {
     {
       BFD_RELOC_AARCH64_LDST8_LO12,
       BFD_RELOC_AARCH64_LDST16_LO12,
@@ -5183,13 +5414,31 @@ ldst_lo12_determine_real_reloc_type (void)
       BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,
       BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,
       BFD_RELOC_AARCH64_NONE
+    },
+    {
+      BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12,
+      BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12,
+      BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12,
+      BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12,
+      BFD_RELOC_AARCH64_NONE
+    },
+    {
+      BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC,
+      BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC,
+      BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC,
+      BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC,
+      BFD_RELOC_AARCH64_NONE
     }
   };
 
   gas_assert (inst.reloc.type == BFD_RELOC_AARCH64_LDST_LO12
              || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
              || (inst.reloc.type
-                 == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC));
+                 == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC)
+             || (inst.reloc.type
+                 == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12)
+             || (inst.reloc.type
+                 == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC));
   gas_assert (inst.base.opcode->operands[1] == AARCH64_OPND_ADDR_UIMM12);
 
   if (opd1_qlf == AARCH64_OPND_QLF_NIL)
@@ -5200,13 +5449,15 @@ ldst_lo12_determine_real_reloc_type (void)
 
   logsz = get_logsz (aarch64_get_qualifier_esize (opd1_qlf));
   if (inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
-      || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC)
+      || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC
+      || inst.reloc.type == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12
+      || inst.reloc.type == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC)
     gas_assert (logsz <= 3);
   else
     gas_assert (logsz <= 4);
 
   /* In reloc.c, these pseudo relocation types should be defined in similar
-     order as above reloc_ldst_lo12 array. Because the array index calcuation
+     order as above reloc_ldst_lo12 array. Because the array index calculation
      below relies on this.  */
   return reloc_ldst_lo12[inst.reloc.type - BFD_RELOC_AARCH64_LDST_LO12][logsz];
 }
@@ -5259,7 +5510,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
   skip_whitespace (str);
 
   if (AARCH64_CPU_HAS_FEATURE (AARCH64_FEATURE_SVE, *opcode->avariant))
-    imm_reg_type = REG_TYPE_R_Z_BHSDQ_VZP;
+    imm_reg_type = REG_TYPE_R_Z_SP_BHSDQ_VZP;
   else
     imm_reg_type = REG_TYPE_R_Z_BHSDQ_V;
 
@@ -5286,7 +5537,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          backtrack_pos = str;
        }
 
-      /* Expect comma between operands; the backtrack mechanizm will take
+      /* Expect comma between operands; the backtrack mechanism will take
         care of cases of omitted optional operand.  */
       if (i > 0 && ! skip_past_char (&str, ','))
        {
@@ -5313,7 +5564,9 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 
        case AARCH64_OPND_Rd_SP:
        case AARCH64_OPND_Rn_SP:
+       case AARCH64_OPND_Rt_SP:
        case AARCH64_OPND_SVE_Rn_SP:
+       case AARCH64_OPND_Rm_SP:
          po_int_reg_or_fail (REG_TYPE_R_SP);
          break;
 
@@ -5382,6 +5635,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          reg_type = REG_TYPE_ZN;
          goto vector_reg;
 
+       case AARCH64_OPND_Va:
        case AARCH64_OPND_Vd:
        case AARCH64_OPND_Vn:
        case AARCH64_OPND_Vm:
@@ -5433,6 +5687,11 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          info->qualifier = AARCH64_OPND_QLF_S_D;
          break;
 
+       case AARCH64_OPND_SVE_Zm3_INDEX:
+       case AARCH64_OPND_SVE_Zm3_22_INDEX:
+       case AARCH64_OPND_SVE_Zm3_11_INDEX:
+       case AARCH64_OPND_SVE_Zm4_11_INDEX:
+       case AARCH64_OPND_SVE_Zm4_INDEX:
        case AARCH64_OPND_SVE_Zn_INDEX:
          reg_type = REG_TYPE_ZN;
          goto vector_reg_index;
@@ -5440,6 +5699,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_Ed:
        case AARCH64_OPND_En:
        case AARCH64_OPND_Em:
+       case AARCH64_OPND_Em16:
+       case AARCH64_OPND_SM3_IMM2:
          reg_type = REG_TYPE_VN;
        vector_reg_index:
          val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
@@ -5487,11 +5748,20 @@ parse_operands (char *str, const aarch64_opcode *opcode)
              val = parse_vector_reg_list (&str, reg_type, &vectype);
              if (val == PARSE_FAIL)
                goto failure;
+
              if (! reg_list_valid_p (val, /* accept_alternate */ 0))
                {
                  set_fatal_syntax_error (_("invalid register list"));
                  goto failure;
                }
+
+             if (vectype.width != 0 && *str != ',')
+               {
+                 set_fatal_syntax_error
+                   (_("expected element type rather than vector type"));
+                 goto failure;
+               }
+
              info->reglist.first_regno = (val >> 2) & 0x1f;
              info->reglist.num_regs = (val & 0x3) + 1;
            }
@@ -5518,16 +5788,23 @@ parse_operands (char *str, const aarch64_opcode *opcode)
            goto failure;
          break;
 
-       case AARCH64_OPND_Cn:
-       case AARCH64_OPND_Cm:
-         po_reg_or_fail (REG_TYPE_CN);
-         if (val > 15)
+       case AARCH64_OPND_CRn:
+       case AARCH64_OPND_CRm:
            {
-             set_fatal_syntax_error (_(get_reg_expected_msg (REG_TYPE_CN)));
-             goto failure;
+             char prefix = *(str++);
+             if (prefix != 'c' && prefix != 'C')
+               goto failure;
+
+             po_imm_nc_or_fail ();
+             if (val > 15)
+               {
+                 set_fatal_syntax_error (_(N_ ("C0 - C15 expected")));
+                 goto failure;
+               }
+             info->qualifier = AARCH64_OPND_QLF_CR;
+             info->imm.value = val;
+             break;
            }
-         inst.base.operands[i].reg.regno = val;
-         break;
 
        case AARCH64_OPND_SHLL_IMM:
        case AARCH64_OPND_IMM_VLSR:
@@ -5538,19 +5815,25 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_CCMP_IMM:
        case AARCH64_OPND_SIMM5:
        case AARCH64_OPND_FBITS:
+       case AARCH64_OPND_TME_UIMM16:
        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:
        case AARCH64_OPND_IMM:
+       case AARCH64_OPND_IMM_2:
        case AARCH64_OPND_WIDTH:
        case AARCH64_OPND_SVE_INV_LIMM:
        case AARCH64_OPND_SVE_LIMM:
        case AARCH64_OPND_SVE_LIMM_MOV:
        case AARCH64_OPND_SVE_SHLIMM_PRED:
        case AARCH64_OPND_SVE_SHLIMM_UNPRED:
+       case AARCH64_OPND_SVE_SHLIMM_UNPRED_22:
        case AARCH64_OPND_SVE_SHRIMM_PRED:
        case AARCH64_OPND_SVE_SHRIMM_UNPRED:
+       case AARCH64_OPND_SVE_SHRIMM_UNPRED_22:
        case AARCH64_OPND_SVE_SIMM5:
        case AARCH64_OPND_SVE_SIMM5B:
        case AARCH64_OPND_SVE_SIMM6:
@@ -5559,6 +5842,12 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_SVE_UIMM7:
        case AARCH64_OPND_SVE_UIMM8:
        case AARCH64_OPND_SVE_UIMM8_53:
+       case AARCH64_OPND_IMM_ROT1:
+       case AARCH64_OPND_IMM_ROT2:
+       case AARCH64_OPND_IMM_ROT3:
+       case AARCH64_OPND_SVE_IMM_ROT1:
+       case AARCH64_OPND_SVE_IMM_ROT2:
+       case AARCH64_OPND_SVE_IMM_ROT3:
          po_imm_nc_or_fail ();
          info->imm.value = val;
          break;
@@ -5604,6 +5893,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_IDX:
+       case AARCH64_OPND_MASK:
        case AARCH64_OPND_BIT_NUM:
        case AARCH64_OPND_IMMR:
        case AARCH64_OPND_IMMS:
@@ -6002,6 +6292,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)
@@ -6022,6 +6314,26 @@ parse_operands (char *str, const aarch64_opcode *opcode)
                                              /* skip_p */ 0);
          break;
 
+       case AARCH64_OPND_ADDR_SIMM10:
+       case AARCH64_OPND_ADDR_OFFSET:
+         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
@@ -6036,7 +6348,11 @@ parse_operands (char *str, const aarch64_opcode *opcode)
                   || (inst.reloc.type
                       == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12)
                   || (inst.reloc.type
-                      == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC))
+                      == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC)
+                  || (inst.reloc.type
+                      == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12)
+                  || (inst.reloc.type
+                      == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC))
            inst.reloc.type = ldst_lo12_determine_real_reloc_type ();
          /* Leave qualifier to be determined by libopcodes.  */
          break;
@@ -6063,6 +6379,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          /* No qualifier.  */
          break;
 
+       case AARCH64_OPND_SVE_ADDR_RI_S4x16:
        case AARCH64_OPND_SVE_ADDR_RI_S4xVL:
        case AARCH64_OPND_SVE_ADDR_RI_S4x2xVL:
        case AARCH64_OPND_SVE_ADDR_RI_S4x3xVL:
@@ -6101,6 +6418,25 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          info->addr.offset.imm = inst.reloc.exp.X_add_number;
          break;
 
+       case AARCH64_OPND_SVE_ADDR_R:
+         /* [<Xn|SP>{, <R><m>}]
+            but recognizing SVE registers.  */
+         po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+                                             &offset_qualifier));
+         if (offset_qualifier == AARCH64_OPND_QLF_NIL)
+           {
+             offset_qualifier = AARCH64_OPND_QLF_X;
+             info->addr.offset.is_reg = 1;
+             info->addr.offset.regno = 31;
+           }
+         else if (base_qualifier != AARCH64_OPND_QLF_X
+             || offset_qualifier != AARCH64_OPND_QLF_X)
+           {
+             set_syntax_error (_("invalid addressing mode"));
+             goto failure;
+           }
+         goto regoff_addr;
+         
        case AARCH64_OPND_SVE_ADDR_RR:
        case AARCH64_OPND_SVE_ADDR_RR_LSL1:
        case AARCH64_OPND_SVE_ADDR_RR_LSL2:
@@ -6147,6 +6483,33 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          info->qualifier = offset_qualifier;
          goto regoff_addr;
 
+       case AARCH64_OPND_SVE_ADDR_ZX:
+         /* [Zn.<T>{, <Xm>}].  */
+         po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+                                             &offset_qualifier));
+         /* Things to check:
+             base_qualifier either S_S or S_D
+             offset_qualifier must be X
+             */
+         if ((base_qualifier != AARCH64_OPND_QLF_S_S
+              && base_qualifier != AARCH64_OPND_QLF_S_D)
+             || offset_qualifier != AARCH64_OPND_QLF_X)
+           {
+             set_syntax_error (_("invalid addressing mode"));
+             goto failure;
+           }
+         info->qualifier = base_qualifier;
+         if (!info->addr.offset.is_reg || info->addr.pcrel
+             || !info->addr.preind || info->addr.writeback
+             || info->shifter.operator_present != 0)
+           {
+             set_syntax_error (_("invalid addressing mode"));
+             goto failure;
+           }
+         info->shifter.kind = AARCH64_MOD_LSL;
+         break;
+
+
        case AARCH64_OPND_SVE_ADDR_ZI_U5:
        case AARCH64_OPND_SVE_ADDR_ZI_U5x2:
        case AARCH64_OPND_SVE_ADDR_ZI_U5x4:
@@ -6188,17 +6551,21 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          goto regoff_addr;
 
        case AARCH64_OPND_SYSREG:
-         if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0))
-             == PARSE_FAIL)
-           {
-             set_syntax_error (_("unknown or missing system register name"));
-             goto failure;
-           }
-         inst.base.operands[i].sysreg = val;
-         break;
+         {
+           uint32_t sysreg_flags;
+           if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0,
+                                     &sysreg_flags)) == PARSE_FAIL)
+             {
+               set_syntax_error (_("unknown or missing system register name"));
+               goto failure;
+             }
+           inst.base.operands[i].sysreg.value = val;
+           inst.base.operands[i].sysreg.flags = sysreg_flags;
+           break;
+         }
 
        case AARCH64_OPND_PSTATEFIELD:
-         if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1))
+         if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1, NULL))
              == PARSE_FAIL)
            {
              set_syntax_error (_("unknown or missing PSTATE field name"));
@@ -6211,14 +6578,22 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          inst.base.operands[i].sysins_op =
            parse_sys_ins_reg (&str, aarch64_sys_regs_ic_hsh);
          goto sys_reg_ins;
+
        case AARCH64_OPND_SYSREG_DC:
          inst.base.operands[i].sysins_op =
            parse_sys_ins_reg (&str, aarch64_sys_regs_dc_hsh);
          goto sys_reg_ins;
+
        case AARCH64_OPND_SYSREG_AT:
          inst.base.operands[i].sysins_op =
            parse_sys_ins_reg (&str, aarch64_sys_regs_at_hsh);
          goto sys_reg_ins;
+
+       case AARCH64_OPND_SYSREG_SR:
+         inst.base.operands[i].sysins_op =
+           parse_sys_ins_reg (&str, aarch64_sys_regs_sr_hsh);
+         goto sys_reg_ins;
+
        case AARCH64_OPND_SYSREG_TLBI:
          inst.base.operands[i].sysins_op =
            parse_sys_ins_reg (&str, aarch64_sys_regs_tlbi_hsh);
@@ -6263,6 +6638,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]);
        }
@@ -6479,6 +6860,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.  */
@@ -6486,9 +6868,12 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
           == AARCH64_OPND_CLASS_INT_REG)
          && opnds[0].reg.regno == opnds[1].addr.base_regno
          && opnds[1].addr.base_regno != REG_SP
+         /* Exempt STG/STZG/ST2G/STZ2G.  */
+         && !(opnds[1].type == AARCH64_OPND_ADDR_SIMM13)
          && opnds[1].addr.writeback)
        as_warn (_("unpredictable transfer with writeback -- `%s'"), str);
       break;
+
     case ldstpair_off:
     case ldstnapair_offs:
     case ldstpair_indexed:
@@ -6498,6 +6883,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.  */
@@ -6505,11 +6892,38 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
          && opnds[0].reg.regno == opnds[1].reg.regno)
            as_warn (_("unpredictable load of register pair -- `%s'"), str);
       break;
+
+    case ldstexcl:
+      /* It is unpredictable if the destination and status registers are the
+        same.  */
+      if ((aarch64_get_operand_class (opnds[0].type)
+          == AARCH64_OPND_CLASS_INT_REG)
+         && (aarch64_get_operand_class (opnds[1].type)
+             == AARCH64_OPND_CLASS_INT_REG)
+         && (opnds[0].reg.regno == opnds[1].reg.regno
+             || opnds[0].reg.regno == opnds[2].reg.regno))
+       as_warn (_("unpredictable: identical transfer and status registers"
+                  " --`%s'"),
+                str);
+
+      break;
+
     default:
       break;
     }
 }
 
+static void
+force_automatic_sequence_close (void)
+{
+  if (now_instr_sequence.instr)
+    {
+      as_warn (_("previous `%s' sequence has not been closed"),
+              now_instr_sequence.instr->opcode->name);
+      init_insn_sequence (NULL, &now_instr_sequence);
+    }
+}
+
 /* A wrapper function to interface with libopcodes on encoding and
    record the error message if there is any.
 
@@ -6520,15 +6934,15 @@ do_encode (const aarch64_opcode *opcode, aarch64_inst *instr,
           aarch64_insn *code)
 {
   aarch64_operand_error error_info;
+  memset (&error_info, '\0', sizeof (error_info));
   error_info.kind = AARCH64_OPDE_NIL;
-  if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info))
+  if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info, insn_sequence)
+      && !error_info.non_fatal)
     return TRUE;
-  else
-    {
-      gas_assert (error_info.kind != AARCH64_OPDE_NIL);
-      record_operand_error_info (opcode, &error_info);
-      return FALSE;
-    }
+
+  gas_assert (error_info.kind != AARCH64_OPDE_NIL);
+  record_operand_error_info (opcode, &error_info);
+  return error_info.non_fatal;
 }
 
 #ifdef DEBUG_AARCH64
@@ -6568,6 +6982,9 @@ md_assemble (char *str)
       S_SET_SEGMENT (last_label_seen, now_seg);
     }
 
+  /* Update the current insn_sequence from the segment.  */
+  insn_sequence = &seg_info (now_seg)->tc_segment_info_data.insn_sequence;
+
   inst.reloc.type = BFD_RELOC_UNUSED;
 
   DEBUG_TRACE ("\n\n");
@@ -6665,6 +7082,9 @@ md_assemble (char *str)
              memcpy (copy, &inst.base, sizeof (struct aarch64_inst));
              output_inst (copy);
            }
+
+         /* Issue non-fatal messages if any.  */
+         output_operand_error_report (str, TRUE);
          return;
        }
 
@@ -6678,7 +7098,7 @@ md_assemble (char *str)
   while (template != NULL);
 
   /* Issue the error messages if any.  */
-  output_operand_error_report (str);
+  output_operand_error_report (str, FALSE);
 }
 
 /* Various frobbings of labels and their addresses.  */
@@ -6697,6 +7117,13 @@ aarch64_frob_label (symbolS * sym)
   dwarf2_emit_label (sym);
 }
 
+void
+aarch64_frob_section (asection *sec ATTRIBUTE_UNUSED)
+{
+  /* Check to see if we have a block to close.  */
+  force_automatic_sequence_close ();
+}
+
 int
 aarch64_data_in_code (void)
 {
@@ -6728,6 +7155,7 @@ aarch64_canonicalize_symbol_name (char *name)
    also have mixed-case names. */
 
 #define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE }
+#define REGDEF_ALIAS(s, n, t) { #s, n, REG_TYPE_##t, FALSE}
 #define REGNUM(p,n,t) REGDEF(p##n, n, t)
 #define REGSET16(p,t) \
   REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
@@ -6749,15 +7177,16 @@ static const reg_entry reg_names[] = {
   REGSET31 (x, R_64), REGSET31 (X, R_64),
   REGSET31 (w, R_32), REGSET31 (W, R_32),
 
+  REGDEF_ALIAS (ip0, 16, R_64), REGDEF_ALIAS (IP0, 16, R_64),
+  REGDEF_ALIAS (ip1, 17, R_64), REGDEF_ALIAS (IP1, 17, R_64),
+  REGDEF_ALIAS (fp, 29, R_64), REGDEF_ALIAS (FP, 29, R_64),
+  REGDEF_ALIAS (lr, 30, R_64), REGDEF_ALIAS (LR, 30, R_64),
   REGDEF (wsp, 31, SP_32), REGDEF (WSP, 31, SP_32),
   REGDEF (sp, 31, SP_64), REGDEF (SP, 31, SP_64),
 
   REGDEF (wzr, 31, Z_32), REGDEF (WZR, 31, Z_32),
   REGDEF (xzr, 31, Z_64), REGDEF (XZR, 31, Z_64),
 
-  /* Coprocessor register numbers.  */
-  REGSET (c, CN), REGSET (C, CN),
-
   /* Floating-point single precision registers.  */
   REGSET (s, FP_S), REGSET (S, FP_S),
 
@@ -6784,6 +7213,7 @@ static const reg_entry reg_names[] = {
 };
 
 #undef REGDEF
+#undef REGDEF_ALIAS
 #undef REGNUM
 #undef REGSET16
 #undef REGSET31
@@ -6927,7 +7357,7 @@ aarch64_handle_align (fragS * fragP)
    Note - despite the name this initialisation is not done when the frag
    is created, but only when its type is assigned.  A frag can be created
    and used a long time before its type is set, so beware of assuming that
-   this initialisationis performed first.  */
+   this initialisation is performed first.  */
 
 #ifndef OBJ_ELF
 void
@@ -6945,6 +7375,11 @@ aarch64_init_frag (fragS * fragP, int max_chars)
   if (!fragP->tc_frag_data.recorded)
     fragP->tc_frag_data.recorded = 1;
 
+  /* PR 21809: Do not set a mapping state for debug sections
+     - it just confuses other tools.  */
+  if (bfd_section_flags (now_seg) & SEC_DEBUGGING)
+    return;
+
   switch (fragP->fr_type)
     {
     case rs_align_test:
@@ -7149,7 +7584,8 @@ try_to_encode_as_unscaled_ldst (aarch64_inst *instr)
 
   DEBUG_TRACE ("Found LDURB entry to encode programmer-friendly LDRB");
 
-  if (!aarch64_opcode_encode (instr->opcode, instr, &instr->value, NULL, NULL))
+  if (!aarch64_opcode_encode (instr->opcode, instr, &instr->value, NULL, NULL,
+                             insn_sequence))
     return FALSE;
 
   return TRUE;
@@ -7183,7 +7619,7 @@ fix_mov_imm_insn (fixS *fixP, char *buf, aarch64_inst *instr, offsetT value)
       opcode = aarch64_get_opcode (OP_MOV_IMM_WIDE);
       aarch64_replace_opcode (instr, opcode);
       if (aarch64_opcode_encode (instr->opcode, instr,
-                                &instr->value, NULL, NULL))
+                                &instr->value, NULL, NULL, insn_sequence))
        {
          put_aarch64_insn (buf, instr->value);
          return;
@@ -7192,7 +7628,7 @@ fix_mov_imm_insn (fixS *fixP, char *buf, aarch64_inst *instr, offsetT value)
       opcode = aarch64_get_opcode (OP_MOV_IMM_WIDEN);
       aarch64_replace_opcode (instr, opcode);
       if (aarch64_opcode_encode (instr->opcode, instr,
-                                &instr->value, NULL, NULL))
+                                &instr->value, NULL, NULL, insn_sequence))
        {
          put_aarch64_insn (buf, instr->value);
          return;
@@ -7205,7 +7641,7 @@ fix_mov_imm_insn (fixS *fixP, char *buf, aarch64_inst *instr, offsetT value)
       opcode = aarch64_get_opcode (OP_MOV_IMM_LOG);
       aarch64_replace_opcode (instr, opcode);
       if (aarch64_opcode_encode (instr->opcode, instr,
-                                &instr->value, NULL, NULL))
+                                &instr->value, NULL, NULL, insn_sequence))
        {
          put_aarch64_insn (buf, instr->value);
          return;
@@ -7316,7 +7752,7 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value)
       idx = aarch64_operand_index (new_inst->opcode->operands, opnd);
       new_inst->operands[idx].imm.value = value;
       if (aarch64_opcode_encode (new_inst->opcode, new_inst,
-                                &new_inst->value, NULL, NULL))
+                                &new_inst->value, NULL, NULL, insn_sequence))
        put_aarch64_insn (buf, new_inst->value);
       else
        as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -7348,7 +7784,10 @@ 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:
+    case AARCH64_OPND_ADDR_SIMM11:
+    case AARCH64_OPND_ADDR_SIMM13:
       /* Immediate offset in an address.  */
       insn = get_aarch64_insn (buf);
 
@@ -7369,7 +7808,7 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value)
 
       /* Encode/fix-up.  */
       if (aarch64_opcode_encode (new_inst->opcode, new_inst,
-                                &new_inst->value, NULL, NULL))
+                                &new_inst->value, NULL, NULL, insn_sequence))
        {
          put_aarch64_insn (buf, new_inst->value);
          break;
@@ -7540,12 +7979,16 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_AARCH64_MOVW_G0_NC:
     case BFD_RELOC_AARCH64_MOVW_G0_S:
     case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC:
       scale = 0;
       goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G1:
     case BFD_RELOC_AARCH64_MOVW_G1_NC:
     case BFD_RELOC_AARCH64_MOVW_G1_S:
     case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC:
       scale = 16;
       goto movw_common;
     case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
@@ -7567,9 +8010,12 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_AARCH64_MOVW_G2:
     case BFD_RELOC_AARCH64_MOVW_G2_NC:
     case BFD_RELOC_AARCH64_MOVW_G2_S:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC:
       scale = 32;
       goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G3:
+    case BFD_RELOC_AARCH64_MOVW_PREL_G3:
       scale = 48;
     movw_common:
       if (fixP->fx_done || !seg->use_rela_p)
@@ -7601,6 +8047,9 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
                case BFD_RELOC_AARCH64_MOVW_G0_S:
                case BFD_RELOC_AARCH64_MOVW_G1_S:
                case BFD_RELOC_AARCH64_MOVW_G2_S:
+               case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+               case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+               case BFD_RELOC_AARCH64_MOVW_PREL_G2:
                  /* NOTE: We can only come here with movz or movn. */
                  if (signed_overflow (value, scale + 16))
                    as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -7645,7 +8094,7 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC:
       fixP->fx_r_type = (ilp32_p
                         ? BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC
-                        : BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC);
+                        : BFD_RELOC_AARCH64_TLSDESC_LD64_LO12);
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* Should always be exported to object file, see
         aarch64_force_relocation().  */
@@ -7653,11 +8102,11 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       gas_assert (seg->use_rela_p);
       break;
 
-    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
     case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
     case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
     case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
-    case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
     case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
     case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
     case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
@@ -7689,6 +8138,14 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
     case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
     case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
     case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
+    case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
@@ -7885,11 +8342,11 @@ aarch64_force_relocation (struct fix *fixp)
     case BFD_RELOC_AARCH64_LDST32_LO12:
     case BFD_RELOC_AARCH64_LDST64_LO12:
     case BFD_RELOC_AARCH64_LDST8_LO12:
-    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
     case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
     case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
     case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
-    case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
     case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
     case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
     case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
@@ -7923,6 +8380,14 @@ aarch64_force_relocation (struct fix *fixp)
     case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
     case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
     case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
+    case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
@@ -7943,18 +8408,37 @@ aarch64_force_relocation (struct fix *fixp)
 
 #ifdef OBJ_ELF
 
+/* Implement md_after_parse_args.  This is the earliest time we need to decide
+   ABI.  If no -mabi specified, the ABI will be decided by target triplet.  */
+
+void
+aarch64_after_parse_args (void)
+{
+  if (aarch64_abi != AARCH64_ABI_NONE)
+    return;
+
+  /* DEFAULT_ARCH will have ":32" extension if it's configured for ILP32.  */
+  if (strlen (default_arch) > 7 && strcmp (default_arch + 7, ":32") == 0)
+    aarch64_abi = AARCH64_ABI_ILP32;
+  else
+    aarch64_abi = AARCH64_ABI_LP64;
+}
+
 const char *
 elf64_aarch64_target_format (void)
 {
-  if (strcmp (TARGET_OS, "cloudabi") == 0)
-    {
-      /* FIXME: What to do for ilp32_p ?  */
-      return target_big_endian ? "elf64-bigaarch64-cloudabi" : "elf64-littleaarch64-cloudabi";
-    }
+#ifdef TE_CLOUDABI
+  /* FIXME: What to do for ilp32_p ?  */
+  if (target_big_endian)
+    return "elf64-bigaarch64-cloudabi";
+  else
+    return "elf64-littleaarch64-cloudabi";
+#else
   if (target_big_endian)
     return ilp32_p ? "elf32-bigaarch64" : "elf64-bigaarch64";
   else
     return ilp32_p ? "elf32-littleaarch64" : "elf64-littleaarch64";
+#endif
 }
 
 void
@@ -8135,6 +8619,7 @@ md_begin (void)
       || (aarch64_sys_regs_dc_hsh = hash_new ()) == NULL
       || (aarch64_sys_regs_at_hsh = hash_new ()) == NULL
       || (aarch64_sys_regs_tlbi_hsh = hash_new ()) == NULL
+      || (aarch64_sys_regs_sr_hsh = hash_new ()) == NULL
       || (aarch64_reg_hsh = hash_new ()) == NULL
       || (aarch64_barrier_opt_hsh = hash_new ()) == NULL
       || (aarch64_nzcv_hsh = hash_new ()) == NULL
@@ -8173,6 +8658,11 @@ md_begin (void)
                         aarch64_sys_regs_tlbi[i].name,
                         (void *) (aarch64_sys_regs_tlbi + i));
 
+  for (i = 0; aarch64_sys_regs_sr[i].name != NULL; i++)
+    checked_hash_insert (aarch64_sys_regs_sr_hsh,
+                        aarch64_sys_regs_sr[i].name,
+                        (void *) (aarch64_sys_regs_sr + i));
+
   for (i = 0; i < ARRAY_SIZE (reg_names); i++)
     checked_hash_insert (aarch64_reg_hsh, reg_names[i].name,
                         (void *) (reg_names + i));
@@ -8324,6 +8814,8 @@ struct aarch64_cpu_option_table
    recognized by GCC.  */
 static const struct aarch64_cpu_option_table aarch64_cpus[] = {
   {"all", AARCH64_ANY, NULL},
+  {"cortex-a34", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                                 AARCH64_FEATURE_CRC), "Cortex-A34"},
   {"cortex-a35", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                  AARCH64_FEATURE_CRC), "Cortex-A35"},
   {"cortex-a53", AARCH64_FEATURE (AARCH64_ARCH_V8,
@@ -8334,12 +8826,64 @@ static const struct aarch64_cpu_option_table aarch64_cpus[] = {
                                  AARCH64_FEATURE_CRC), "Cortex-A72"},
   {"cortex-a73", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                  AARCH64_FEATURE_CRC), "Cortex-A73"},
+  {"cortex-a55", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16 | AARCH64_FEATURE_DOTPROD),
+                                 "Cortex-A55"},
+  {"cortex-a75", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16 | AARCH64_FEATURE_DOTPROD),
+                                 "Cortex-A75"},
+  {"cortex-a76", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16 | AARCH64_FEATURE_DOTPROD),
+                                 "Cortex-A76"},
+  {"cortex-a76ae", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                   AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC
+                                   | AARCH64_FEATURE_DOTPROD
+                                   | AARCH64_FEATURE_SSBS),
+                                   "Cortex-A76AE"},
+  {"cortex-a77", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC
+                                 | AARCH64_FEATURE_DOTPROD
+                                 | AARCH64_FEATURE_SSBS),
+                                 "Cortex-A77"},
+  {"cortex-a65", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC
+                                 | AARCH64_FEATURE_DOTPROD
+                                 | AARCH64_FEATURE_SSBS),
+                                 "Cortex-A65"},
+  {"cortex-a65ae", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                   AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC
+                                   | AARCH64_FEATURE_DOTPROD
+                                   | AARCH64_FEATURE_SSBS),
+                                   "Cortex-A65AE"},
+  {"ares", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16
+                                 | AARCH64_FEATURE_DOTPROD
+                                 | AARCH64_FEATURE_PROFILE),
+                                 "Ares"},
   {"exynos-m1", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                 AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
                                "Samsung Exynos M1"},
+  {"falkor", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                             AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO
+                             | AARCH64_FEATURE_RDMA),
+   "Qualcomm Falkor"},
+  {"neoverse-e1", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16
+                                 | AARCH64_FEATURE_DOTPROD
+                                 | AARCH64_FEATURE_SSBS),
+                                 "Neoverse E1"},
+  {"neoverse-n1", AARCH64_FEATURE (AARCH64_ARCH_V8_2,
+                                 AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16
+                                 | AARCH64_FEATURE_DOTPROD
+                                 | AARCH64_FEATURE_PROFILE),
+                                 "Neoverse N1"},
   {"qdf24xx", AARCH64_FEATURE (AARCH64_ARCH_V8,
-                              AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
+                              AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO
+                              | AARCH64_FEATURE_RDMA),
    "Qualcomm QDF24XX"},
+  {"saphira", AARCH64_FEATURE (AARCH64_ARCH_V8_4,
+                              AARCH64_FEATURE_CRYPTO | AARCH64_FEATURE_PROFILE),
+   "Qualcomm Saphira"},
   {"thunderx", AARCH64_FEATURE (AARCH64_ARCH_V8,
                                AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
    "Cavium ThunderX"},
@@ -8371,6 +8915,10 @@ static const struct aarch64_arch_option_table aarch64_archs[] = {
   {"armv8-a", AARCH64_ARCH_V8},
   {"armv8.1-a", AARCH64_ARCH_V8_1},
   {"armv8.2-a", AARCH64_ARCH_V8_2},
+  {"armv8.3-a", AARCH64_ARCH_V8_3},
+  {"armv8.4-a", AARCH64_ARCH_V8_4},
+  {"armv8.5-a", AARCH64_ARCH_V8_5},
+  {"armv8.6-a", AARCH64_ARCH_V8_6},
   {NULL, AARCH64_ARCH_NONE}
 };
 
@@ -8385,14 +8933,16 @@ struct aarch64_option_cpu_value_table
 static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"crc",              AARCH64_FEATURE (AARCH64_FEATURE_CRC, 0),
                        AARCH64_ARCH_NONE},
-  {"crypto",           AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0),
-                       AARCH64_ARCH_NONE},
+  {"crypto",           AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO
+                                        | AARCH64_FEATURE_AES
+                                        | AARCH64_FEATURE_SHA2, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
   {"fp",               AARCH64_FEATURE (AARCH64_FEATURE_FP, 0),
                        AARCH64_ARCH_NONE},
   {"lse",              AARCH64_FEATURE (AARCH64_FEATURE_LSE, 0),
                        AARCH64_ARCH_NONE},
   {"simd",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0),
-                       AARCH64_ARCH_NONE},
+                       AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
   {"pan",              AARCH64_FEATURE (AARCH64_FEATURE_PAN, 0),
                        AARCH64_ARCH_NONE},
   {"lor",              AARCH64_FEATURE (AARCH64_FEATURE_LOR, 0),
@@ -8403,11 +8953,56 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
                        AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
   {"fp16",             AARCH64_FEATURE (AARCH64_FEATURE_F16, 0),
                        AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
+  {"fp16fml",          AARCH64_FEATURE (AARCH64_FEATURE_F16_FML, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_FP
+                                        | AARCH64_FEATURE_F16, 0)},
   {"profile",          AARCH64_FEATURE (AARCH64_FEATURE_PROFILE, 0),
                        AARCH64_ARCH_NONE},
   {"sve",              AARCH64_FEATURE (AARCH64_FEATURE_SVE, 0),
-                       AARCH64_FEATURE (AARCH64_FEATURE_FP
+                       AARCH64_FEATURE (AARCH64_FEATURE_F16
+                                        | AARCH64_FEATURE_SIMD
+                                        | AARCH64_FEATURE_COMPNUM, 0)},
+  {"tme",              AARCH64_FEATURE (AARCH64_FEATURE_TME, 0),
+                       AARCH64_ARCH_NONE},
+  {"compnum",          AARCH64_FEATURE (AARCH64_FEATURE_COMPNUM, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_F16
                                         | AARCH64_FEATURE_SIMD, 0)},
+  {"rcpc",             AARCH64_FEATURE (AARCH64_FEATURE_RCPC, 0),
+                       AARCH64_ARCH_NONE},
+  {"dotprod",          AARCH64_FEATURE (AARCH64_FEATURE_DOTPROD, 0),
+                       AARCH64_ARCH_NONE},
+  {"sha2",             AARCH64_FEATURE (AARCH64_FEATURE_SHA2, 0),
+                       AARCH64_ARCH_NONE},
+  {"sb",               AARCH64_FEATURE (AARCH64_FEATURE_SB, 0),
+                       AARCH64_ARCH_NONE},
+  {"predres",          AARCH64_FEATURE (AARCH64_FEATURE_PREDRES, 0),
+                       AARCH64_ARCH_NONE},
+  {"aes",              AARCH64_FEATURE (AARCH64_FEATURE_AES, 0),
+                       AARCH64_ARCH_NONE},
+  {"sm4",              AARCH64_FEATURE (AARCH64_FEATURE_SM4, 0),
+                       AARCH64_ARCH_NONE},
+  {"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},
+  {"sve2",             AARCH64_FEATURE (AARCH64_FEATURE_SVE2, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SVE, 0)},
+  {"sve2-sm4",         AARCH64_FEATURE (AARCH64_FEATURE_SVE2_SM4, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SVE2
+                                        | AARCH64_FEATURE_SM4, 0)},
+  {"sve2-aes",         AARCH64_FEATURE (AARCH64_FEATURE_SVE2_AES, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SVE2
+                                        | AARCH64_FEATURE_AES, 0)},
+  {"sve2-sha3",                AARCH64_FEATURE (AARCH64_FEATURE_SVE2_SHA3, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SVE2
+                                        | AARCH64_FEATURE_SHA3, 0)},
+  {"sve2-bitperm",     AARCH64_FEATURE (AARCH64_FEATURE_SVE2_BITPERM, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SVE2, 0)},
   {NULL,               AARCH64_ARCH_NONE, AARCH64_ARCH_NONE},
 };
 
@@ -8872,3 +9467,35 @@ aarch64_copy_symbol_attributes (symbolS * dest, symbolS * src)
 {
   AARCH64_GET_FLAG (dest) = AARCH64_GET_FLAG (src);
 }
+
+#ifdef OBJ_ELF
+/* Same as elf_copy_symbol_attributes, but without copying st_other.
+   This is needed so AArch64 specific st_other values can be independently
+   specified for an IFUNC resolver (that is called by the dynamic linker)
+   and the symbol it resolves (aliased to the resolver).  In particular,
+   if a function symbol has special st_other value set via directives,
+   then attaching an IFUNC resolver to that symbol should not override
+   the st_other setting.  Requiring the directive on the IFUNC resolver
+   symbol would be unexpected and problematic in C code, where the two
+   symbols appear as two independent function declarations.  */
+
+void
+aarch64_elf_copy_symbol_attributes (symbolS *dest, symbolS *src)
+{
+  struct elf_obj_sy *srcelf = symbol_get_obj (src);
+  struct elf_obj_sy *destelf = symbol_get_obj (dest);
+  if (srcelf->size)
+    {
+      if (destelf->size == NULL)
+       destelf->size = XNEW (expressionS);
+      *destelf->size = *srcelf->size;
+    }
+  else
+    {
+      if (destelf->size != NULL)
+       free (destelf->size);
+      destelf->size = NULL;
+    }
+  S_SET_SIZE (dest, S_GET_SIZE (src));
+}
+#endif
This page took 0.054865 seconds and 4 git commands to generate.