[AArch64][1/6] GAS support BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC
[deliverable/binutils-gdb.git] / gas / config / tc-aarch64.c
index 239b9eef6140257dd18ee501ba25ed28774cf6be..d55356f0a92cf3e00316db9621a815cb21393acf 100644 (file)
@@ -1,7 +1,6 @@
 /* tc-aarch64.c -- Assemble for the AArch64 ISA
 
-   Copyright 2009, 2010, 2011, 2012, 2013
-   Free Software Foundation, Inc.
+   Copyright (C) 2009-2015 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of GAS.
@@ -43,6 +42,8 @@
 
 #define streq(a, b)          (strcmp (a, b) == 0)
 
+#define END_OF_INSN '\0'
+
 static aarch64_feature_set cpu_variant;
 
 /* Variables that we set while parsing command-line options.  Once all
@@ -54,18 +55,25 @@ static const aarch64_feature_set *march_cpu_opt = NULL;
 /* Constants for known architecture features.  */
 static const aarch64_feature_set cpu_default = CPU_DEFAULT;
 
-static const aarch64_feature_set aarch64_arch_any = AARCH64_ANY;
-static const aarch64_feature_set aarch64_arch_none = AARCH64_ARCH_NONE;
-
 #ifdef OBJ_ELF
 /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 static symbolS *GOT_symbol;
 
+/* Which ABI to use.  */
+enum aarch64_abi_type
+{
+  AARCH64_ABI_LP64 = 0,
+  AARCH64_ABI_ILP32 = 1
+};
+
+/* AArch64 ABI for the output file.  */
+static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_LP64;
+
 /* 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
    64-bit model, in which the C int type is 32-bits but the C long type
    and all pointer types are 64-bit objects (LP64).  */
-static int ilp32_p = 0;
+#define ilp32_p                (aarch64_abi == AARCH64_ABI_ILP32)
 #endif
 
 enum neon_el_type
@@ -163,24 +171,12 @@ get_error_message (void)
   return inst.parsing_error.error;
 }
 
-static inline void
-set_error_message (const char *error)
-{
-  inst.parsing_error.error = error;
-}
-
 static inline enum aarch64_operand_error_kind
 get_error_kind (void)
 {
   return inst.parsing_error.kind;
 }
 
-static inline void
-set_error_kind (enum aarch64_operand_error_kind kind)
-{
-  inst.parsing_error.kind = kind;
-}
-
 static inline void
 set_error (enum aarch64_operand_error_kind kind, const char *error)
 {
@@ -426,9 +422,16 @@ static symbolS *last_label_seen;
    and per-sub-section basis.  */
 
 #define MAX_LITERAL_POOL_SIZE 1024
+typedef struct literal_expression
+{
+  expressionS exp;
+  /* If exp.op == O_big then this bignum holds a copy of the global bignum value.  */
+  LITTLENUM_TYPE * bignum;
+} literal_expression;
+
 typedef struct literal_pool
 {
-  expressionS literals[MAX_LITERAL_POOL_SIZE];
+  literal_expression literals[MAX_LITERAL_POOL_SIZE];
   unsigned int next_free_entry;
   unsigned int id;
   symbolS *symbol;
@@ -1457,21 +1460,28 @@ mapping_state (enum mstate state)
 {
   enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
 
-#define TRANSITION(from, to) (mapstate == (from) && state == (to))
+  if (state == MAP_INSN)
+    /* AArch64 instructions require 4-byte alignment.  When emitting
+       instructions into any section, record the appropriate section
+       alignment.  */
+    record_alignment (now_seg, 2);
 
   if (mapstate == state)
     /* The mapping symbol has already been emitted.
        There is nothing else to do.  */
     return;
-  else if (TRANSITION (MAP_UNDEFINED, MAP_DATA))
-    /* This case will be evaluated later in the next else.  */
+
+#define TRANSITION(from, to) (mapstate == (from) && state == (to))
+  if (TRANSITION (MAP_UNDEFINED, MAP_DATA) && !subseg_text_p (now_seg))
+    /* Emit MAP_DATA within executable section in order.  Otherwise, it will be
+       evaluated later in the next else.  */
     return;
   else if (TRANSITION (MAP_UNDEFINED, MAP_INSN))
     {
       /* Only add the symbol if the offset is > 0:
-         if we're at the first frag, check it's size > 0;
-         if we're not at the first frag, then for sure
-         the offset is > 0.  */
+        if we're at the first frag, check it's size > 0;
+        if we're not at the first frag, then for sure
+        the offset is > 0.  */
       struct frag *const frag_first = seg_info (now_seg)->frchainP->frch_root;
       const int add_symbol = (frag_now != frag_first)
        || (frag_now_fix () > 0);
@@ -1479,9 +1489,9 @@ mapping_state (enum mstate state)
       if (add_symbol)
        make_mapping_symbol (MAP_DATA, (valueT) 0, frag_first);
     }
+#undef TRANSITION
 
   mapping_state_2 (state, 0);
-#undef TRANSITION
 }
 
 /* Same as mapping_state, but MAX_CHARS bytes have already been
@@ -1607,17 +1617,19 @@ add_to_lit_pool (expressionS *exp, int size)
   /* Check if this literal value is already in the pool.  */
   for (entry = 0; entry < pool->next_free_entry; entry++)
     {
-      if ((pool->literals[entry].X_op == exp->X_op)
+      expressionS * litexp = & pool->literals[entry].exp;
+
+      if ((litexp->X_op == exp->X_op)
          && (exp->X_op == O_constant)
-         && (pool->literals[entry].X_add_number == exp->X_add_number)
-         && (pool->literals[entry].X_unsigned == exp->X_unsigned))
+         && (litexp->X_add_number == exp->X_add_number)
+         && (litexp->X_unsigned == exp->X_unsigned))
        break;
 
-      if ((pool->literals[entry].X_op == exp->X_op)
+      if ((litexp->X_op == exp->X_op)
          && (exp->X_op == O_symbol)
-         && (pool->literals[entry].X_add_number == exp->X_add_number)
-         && (pool->literals[entry].X_add_symbol == exp->X_add_symbol)
-         && (pool->literals[entry].X_op_symbol == exp->X_op_symbol))
+         && (litexp->X_add_number == exp->X_add_number)
+         && (litexp->X_add_symbol == exp->X_add_symbol)
+         && (litexp->X_op_symbol == exp->X_op_symbol))
        break;
     }
 
@@ -1630,8 +1642,18 @@ add_to_lit_pool (expressionS *exp, int size)
          return FALSE;
        }
 
-      pool->literals[entry] = *exp;
+      pool->literals[entry].exp = *exp;
       pool->next_free_entry += 1;
+      if (exp->X_op == O_big)
+       {
+         /* PR 16688: Bignums are held in a single global array.  We must
+            copy and preserve that value now, before it is overwritten.  */
+         pool->literals[entry].bignum = xmalloc (CHARS_PER_LITTLENUM * exp->X_add_number);
+         memcpy (pool->literals[entry].bignum, generic_bignum,
+                 CHARS_PER_LITTLENUM * exp->X_add_number);
+       }
+      else
+       pool->literals[entry].bignum = NULL;
     }
 
   exp->X_op = O_symbol;
@@ -1651,7 +1673,7 @@ symbol_locate (symbolS * symbolP,
               valueT valu,     /* Symbol value.  */
               fragS * frag)    /* Associated fragment.  */
 {
-  unsigned int name_length;
+  size_t name_length;
   char *preserved_copy_of_name;
 
   name_length = strlen (name) + 1;     /* +1 for \0.  */
@@ -1725,8 +1747,26 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
       symbol_table_insert (pool->symbol);
 
       for (entry = 0; entry < pool->next_free_entry; entry++)
-       /* First output the expression in the instruction to the pool.  */
-       emit_expr (&(pool->literals[entry]), size);     /* .word|.xword  */
+       {
+         expressionS * exp = & pool->literals[entry].exp;
+
+         if (exp->X_op == O_big)
+           {
+             /* PR 16688: Restore the global bignum value.  */
+             gas_assert (pool->literals[entry].bignum != NULL);
+             memcpy (generic_bignum, pool->literals[entry].bignum,
+                     CHARS_PER_LITTLENUM * exp->X_add_number);
+           }
+
+         /* First output the expression in the instruction to the pool.  */
+         emit_expr (exp, size);        /* .word|.xword  */
+
+         if (exp->X_op == O_big)
+           {
+             free (pool->literals[entry].bignum);
+             pool->literals[entry].bignum = NULL;
+           }
+       }
 
       /* Mark the pool as empty.  */
       pool->next_free_entry = 0;
@@ -1815,8 +1855,14 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED)
       return;
     }
 
-  if (!need_pass_2)
+  /* Sections are assumed to start aligned. In executable section, there is no
+     MAP_DATA symbol pending. So we only align the address during
+     MAP_DATA --> MAP_INSN transition.
+     For other sections, this is not guaranteed.  */
+  enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
+  if (!need_pass_2 && subseg_text_p (now_seg) && mapstate == MAP_DATA)
     frag_align_code (2, 0);
+
 #ifdef OBJ_ELF
   mapping_state (MAP_INSN);
 #endif
@@ -1869,6 +1915,7 @@ s_tlsdesccall (int ignored ATTRIBUTE_UNUSED)
 
 static void s_aarch64_arch (int);
 static void s_aarch64_cpu (int);
+static void s_aarch64_arch_extension (int);
 
 /* This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
@@ -1886,6 +1933,7 @@ const pseudo_typeS md_pseudo_table[] = {
   {"pool", s_ltorg, 0},
   {"cpu", s_aarch64_cpu, 0},
   {"arch", s_aarch64_arch, 0},
+  {"arch_extension", s_aarch64_arch_extension, 0},
   {"inst", s_aarch64_inst, 0},
 #ifdef OBJ_ELF
   {"tlsdesccall", s_tlsdesccall, 0},
@@ -2263,225 +2311,350 @@ struct reloc_table_entry
 {
   const char *name;
   int pc_rel;
+  bfd_reloc_code_real_type adr_type;
   bfd_reloc_code_real_type adrp_type;
   bfd_reloc_code_real_type movw_type;
   bfd_reloc_code_real_type add_type;
   bfd_reloc_code_real_type ldst_type;
+  bfd_reloc_code_real_type ld_literal_type;
 };
 
 static struct reloc_table_entry reloc_table[] = {
   /* Low 12 bits of absolute address: ADD/i and LDR/STR */
   {"lo12", 0,
+   0,                          /* adr_type */
    0,
    0,
    BFD_RELOC_AARCH64_ADD_LO12,
-   BFD_RELOC_AARCH64_LDST_LO12},
+   BFD_RELOC_AARCH64_LDST_LO12,
+   0},
 
   /* Higher 21 bits of pc-relative page offset: ADRP */
   {"pg_hi21", 1,
+   0,                          /* adr_type */
    BFD_RELOC_AARCH64_ADR_HI21_PCREL,
    0,
    0,
+   0,
    0},
 
   /* Higher 21 bits of pc-relative page offset: ADRP, no check */
   {"pg_hi21_nc", 1,
+   0,                          /* adr_type */
    BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL,
    0,
    0,
+   0,
    0},
 
   /* Most significant bits 0-15 of unsigned address/value: MOVZ */
   {"abs_g0", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G0,
    0,
+   0,
    0},
 
   /* Most significant bits 0-15 of signed address/value: MOVN/Z */
   {"abs_g0_s", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G0_S,
    0,
+   0,
    0},
 
   /* Less significant bits 0-15 of address/value: MOVK, no check */
   {"abs_g0_nc", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G0_NC,
    0,
+   0,
    0},
 
   /* Most significant bits 16-31 of unsigned address/value: MOVZ */
   {"abs_g1", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G1,
    0,
+   0,
    0},
 
   /* Most significant bits 16-31 of signed address/value: MOVN/Z */
   {"abs_g1_s", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G1_S,
    0,
+   0,
    0},
 
   /* Less significant bits 16-31 of address/value: MOVK, no check */
   {"abs_g1_nc", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G1_NC,
    0,
+   0,
    0},
 
   /* Most significant bits 32-47 of unsigned address/value: MOVZ */
   {"abs_g2", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G2,
    0,
+   0,
    0},
 
   /* Most significant bits 32-47 of signed address/value: MOVN/Z */
   {"abs_g2_s", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G2_S,
    0,
+   0,
    0},
 
   /* Less significant bits 32-47 of address/value: MOVK, no check */
   {"abs_g2_nc", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G2_NC,
    0,
+   0,
    0},
 
   /* Most significant bits 48-63 of signed/unsigned address/value: MOVZ */
   {"abs_g3", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_MOVW_G3,
    0,
-   0},
-  /* Get to the GOT entry for a symbol.  */
-  {"got_prel19", 0,
-   0,
-   0,
    0,
-   BFD_RELOC_AARCH64_GOT_LD_PREL19},
+   0},
+
   /* Get to the page containing GOT entry for a symbol.  */
   {"got", 1,
+   0,                          /* adr_type */
    BFD_RELOC_AARCH64_ADR_GOT_PAGE,
    0,
    0,
-   0},
+   0,
+   BFD_RELOC_AARCH64_GOT_LD_PREL19},
+
   /* 12 bit offset into the page containing GOT entry for that symbol.  */
   {"got_lo12", 0,
+   0,                          /* adr_type */
    0,
    0,
    0,
-   BFD_RELOC_AARCH64_LD64_GOT_LO12_NC},
+   BFD_RELOC_AARCH64_LD_GOT_LO12_NC,
+   0},
+
+  /* 15 bit offset into the page containing GOT entry for that symbol.  */
+  {"gotoff_lo15", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   0,
+   BFD_RELOC_AARCH64_LD64_GOTOFF_LO15,
+   0},
 
   /* Get to the page containing GOT TLS entry for a symbol */
   {"tlsgd", 0,
+   BFD_RELOC_AARCH64_TLSGD_ADR_PREL21, /* adr_type */
    BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21,
    0,
    0,
+   0,
    0},
 
   /* 12 bit offset into the page containing GOT TLS entry for a symbol */
   {"tlsgd_lo12", 0,
+   0,                          /* adr_type */
    0,
    0,
    BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC,
+   0,
    0},
 
   /* Get to the page containing GOT TLS entry for a symbol */
   {"tlsdesc", 0,
+   BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21, /* adr_type */
    BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21,
    0,
    0,
-   0},
+   0,
+   BFD_RELOC_AARCH64_TLSDESC_LD_PREL19},
 
   /* 12 bit offset into the page containing GOT TLS entry for a symbol */
   {"tlsdesc_lo12", 0,
+   0,                          /* adr_type */
    0,
    0,
    BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC,
-   BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC},
+   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
+     zero without any outstanding runtime relocation. */
+  {"tlsldm", 0,
+   BFD_RELOC_AARCH64_TLSLD_ADR_PREL21, /* adr_type */
+   BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21,
+   0,
+   0,
+   0,
+   0},
+
+  /* 12 bit offset into the page containing GOT TLS entry for a symbol */
+  {"tlsldm_lo12_nc", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC,
+   0,
+   0},
+
+  /* 12 bit offset into the module TLS base address.  */
+  {"dtprel_lo12", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12,
+   0,
+   0},
+
+  /* Same as dtprel_lo12, no overflow check.  */
+  {"dtprel_lo12_nc", 0,
+   0,                          /* adr_type */
+   0,
+   0,
+   BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC,
+   0,
+   0},
 
   /* Get to the page containing GOT TLS entry for a symbol */
   {"gottprel", 0,
+   0,                          /* adr_type */
    BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21,
    0,
    0,
-   0},
+   0,
+   BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19},
 
   /* 12 bit offset into the page containing GOT TLS entry for a symbol */
   {"gottprel_lo12", 0,
+   0,                          /* adr_type */
    0,
    0,
    0,
-   BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC},
+   BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC,
+   0},
 
   /* Get tp offset for a symbol.  */
   {"tprel", 0,
+   0,                          /* adr_type */
    0,
    0,
    BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12,
+   0,
    0},
 
   /* Get tp offset for a symbol.  */
   {"tprel_lo12", 0,
+   0,                          /* adr_type */
    0,
    0,
    BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12,
+   0,
    0},
 
   /* Get tp offset for a symbol.  */
   {"tprel_hi12", 0,
+   0,                          /* adr_type */
    0,
    0,
    BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12,
+   0,
    0},
 
   /* Get tp offset for a symbol.  */
   {"tprel_lo12_nc", 0,
+   0,                          /* adr_type */
    0,
    0,
    BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC,
+   0,
    0},
 
   /* Most significant bits 32-47 of address/value: MOVZ.  */
   {"tprel_g2", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2,
    0,
+   0,
    0},
 
   /* Most significant bits 16-31 of address/value: MOVZ.  */
   {"tprel_g1", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1,
    0,
+   0,
    0},
 
   /* Most significant bits 16-31 of address/value: MOVZ, no check.  */
   {"tprel_g1_nc", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC,
    0,
+   0,
    0},
 
   /* Most significant bits 0-15 of address/value: MOVZ.  */
   {"tprel_g0", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0,
    0,
+   0,
    0},
 
   /* Most significant bits 0-15 of address/value: MOVZ, no check.  */
   {"tprel_g0_nc", 0,
+   0,                          /* adr_type */
    0,
    BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC,
    0,
+   0,
+   0},
+
+  /* 15bit offset from got entry to base address of GOT table.  */
+  {"gotpage_lo15", 0,
+   0,
+   0,
+   0,
+   0,
+   BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15,
+   0},
+
+  /* 14bit offset from got entry to base address of GOT table.  */
+  {"gotpage_lo14", 0,
+   0,
+   0,
+   0,
+   0,
+   BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14,
    0},
 };
 
@@ -2810,7 +2983,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
       if (**str == '\0')
        return TRUE;
 
-      /* Otherwise, we have a shifted reloc modifier, so rewind to 
+      /* Otherwise, we have a shifted reloc modifier, so rewind to
          recover the variable name and continue parsing for the shifter.  */
       *str = p;
       return parse_shifter_operand_imm (str, operand, mode);
@@ -2888,6 +3061,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
       skip_past_char (&p, '#');
       if (reloc && skip_past_char (&p, ':'))
        {
+         bfd_reloc_code_real_type ty;
          struct reloc_table_entry *entry;
 
          /* Try to parse a relocation modifier.  Anything else is
@@ -2899,7 +3073,19 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
              return FALSE;
            }
 
-         if (entry->ldst_type == 0)
+         switch (operand->type)
+           {
+           case AARCH64_OPND_ADDR_PCREL21:
+             /* adr */
+             ty = entry->adr_type;
+             break;
+
+           default:
+             ty = entry->ld_literal_type;
+             break;
+           }
+
+         if (ty == 0)
            {
              set_syntax_error
                (_("this relocation modifier is not allowed on this "
@@ -2915,8 +3101,8 @@ parse_address_main (char **str, aarch64_opnd_info *operand, int reloc,
            }
 
          /* #:<reloc_op>:<expr>  */
-         /* Record the load/store relocation type.  */
-         inst.reloc.type = entry->ldst_type;
+         /* Record the relocation type.  */
+         inst.reloc.type = ty;
          inst.reloc.pc_rel = entry->pc_rel;
        }
       else
@@ -3264,14 +3450,19 @@ parse_barrier (char **str)
    Returns the encoding for the option, or PARSE_FAIL.
 
    If IMPLE_DEFINED_P is non-zero, the function will also try to parse the
-   implementation defined system register name S3_<op1>_<Cn>_<Cm>_<op2>.  */
+   implementation defined system register name S<op0>_<op1>_<Cn>_<Cm>_<op2>.
+
+   If PSTATEFIELD_P is non-zero, the function will parse the name as a PSTATE
+   field, otherwise as a system register.
+*/
 
 static int
-parse_sys_reg (char **str, struct hash_control *sys_regs, int imple_defined_p)
+parse_sys_reg (char **str, struct hash_control *sys_regs,
+              int imple_defined_p, int pstatefield_p)
 {
   char *p, *q;
   char buf[32];
-  const struct aarch64_name_value_pair *o;
+  const aarch64_sys_reg *o;
   int value;
 
   p = buf;
@@ -3289,25 +3480,30 @@ parse_sys_reg (char **str, struct hash_control *sys_regs, int imple_defined_p)
        return PARSE_FAIL;
       else
        {
-         /* Parse S3_<op1>_<Cn>_<Cm>_<op2>, the implementation defined
-            registers.  */
+         /* Parse S<op0>_<op1>_<Cn>_<Cm>_<op2>.  */
          unsigned int op0, op1, cn, cm, op2;
-         if (sscanf (buf, "s%u_%u_c%u_c%u_%u", &op0, &op1, &cn, &cm, &op2) != 5)
+
+         if (sscanf (buf, "s%u_%u_c%u_c%u_%u", &op0, &op1, &cn, &cm, &op2)
+             != 5)
            return PARSE_FAIL;
-         /* The architecture specifies the encoding space for implementation
-            defined registers as:
-            op0  op1  CRn   CRm   op2
-            11   xxx  1x11  xxxx  xxx
-            For convenience GAS accepts a wider encoding space, as follows:
-            op0  op1  CRn   CRm   op2
-            11   xxx  xxxx  xxxx  xxx  */
-         if (op0 != 3 || op1 > 7 || cn > 15 || cm > 15 || op2 > 7)
+         if (op0 > 3 || op1 > 7 || cn > 15 || cm > 15 || op2 > 7)
            return PARSE_FAIL;
          value = (op0 << 14) | (op1 << 11) | (cn << 7) | (cm << 3) | op2;
        }
     }
   else
-    value = o->value;
+    {
+      if (pstatefield_p && !aarch64_pstatefield_supported_p (cpu_variant, o))
+       as_bad (_("selected processor does not support PSTATE field "
+                 "name '%s'"), buf);
+      if (!pstatefield_p && !aarch64_sys_reg_supported_p (cpu_variant, o))
+       as_bad (_("selected processor does not support system register "
+                 "name '%s'"), buf);
+      if (aarch64_sys_reg_deprecated_p (o))
+       as_warn (_("system register name '%s' is deprecated and may be "
+                  "removed in a future release"), buf);
+      value = o->value;
+    }
 
   *str = q;
   return value;
@@ -3506,9 +3702,9 @@ fix_new_aarch64 (fragS * frag,
 \f
 /* Diagnostics on operands errors.  */
 
-/* By default, output one-line error message only.
-   Enable the verbose error message by -merror-verbose.  */
-static int verbose_error_p = 0;
+/* By default, output verbose error message.
+   Disable the verbose error message by -mno-verbose-error.  */
+static int verbose_error_p = 1;
 
 #ifdef DEBUG_AARCH64
 /* N.B. this is only for the purpose of debugging.  */
@@ -3896,11 +4092,11 @@ output_info (const char *format, ...)
 static void
 output_operand_error_record (const operand_error_record *record, char *str)
 {
-  int idx = record->detail.index;
+  const aarch64_operand_error *detail = &record->detail;
+  int idx = detail->index;
   const aarch64_opcode *opcode = record->opcode;
-  enum aarch64_opnd opd_code = (idx != -1 ? opcode->operands[idx]
+  enum aarch64_opnd opd_code = (idx >= 0 ? opcode->operands[idx]
                                : AARCH64_OPND_NIL);
-  const aarch64_operand_error *detail = &record->detail;
 
   switch (detail->kind)
     {
@@ -3912,20 +4108,22 @@ output_operand_error_record (const operand_error_record *record, char *str)
     case AARCH64_OPDE_RECOVERABLE:
     case AARCH64_OPDE_FATAL_SYNTAX_ERROR:
     case AARCH64_OPDE_OTHER_ERROR:
-      gas_assert (idx >= 0);
       /* Use the prepared error message if there is, otherwise use the
         operand description string to describe the error.  */
       if (detail->error != NULL)
        {
-         if (detail->index == -1)
+         if (idx < 0)
            as_bad (_("%s -- `%s'"), detail->error, str);
          else
            as_bad (_("%s at operand %d -- `%s'"),
-                   detail->error, detail->index + 1, str);
+                   detail->error, idx + 1, str);
        }
       else
-       as_bad (_("operand %d should be %s -- `%s'"), idx + 1,
+       {
+         gas_assert (idx >= 0);
+         as_bad (_("operand %d should be %s -- `%s'"), idx + 1,
                aarch64_get_operand_desc (opd_code), str);
+       }
       break;
 
     case AARCH64_OPDE_INVALID_VARIANT:
@@ -4030,28 +4228,28 @@ output_operand_error_record (const operand_error_record *record, char *str)
       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], detail->index + 1, str);
+               detail->data[0], detail->data[1], idx + 1, str);
       else
        as_bad (_("%s expected to be %d at operand %d -- `%s'"),
                detail->error ? detail->error : _("immediate value"),
-               detail->data[0], detail->index + 1, str);
+               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'"),
-               detail->index + 1, str);
+               idx + 1, str);
       else
        as_bad (_("invalid number of registers in the list; "
                  "%d registers are expected at operand %d -- `%s'"),
-             detail->data[0], detail->index + 1, str);
+             detail->data[0], idx + 1, str);
       break;
 
     case AARCH64_OPDE_UNALIGNED:
       as_bad (_("immediate value should be a multiple of "
                "%d at operand %d -- `%s'"),
-             detail->data[0], detail->index + 1, str);
+             detail->data[0], idx + 1, str);
       break;
 
     default:
@@ -4401,9 +4599,7 @@ process_movw_reloc_info (void)
       case BFD_RELOC_AARCH64_MOVW_G1_S:
       case BFD_RELOC_AARCH64_MOVW_G2_S:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
-      case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
-      case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
        set_syntax_error
          (_("the specified relocation type is not allowed for MOVK"));
@@ -4415,22 +4611,22 @@ process_movw_reloc_info (void)
   switch (inst.reloc.type)
     {
     case BFD_RELOC_AARCH64_MOVW_G0:
-    case BFD_RELOC_AARCH64_MOVW_G0_S:
     case BFD_RELOC_AARCH64_MOVW_G0_NC:
+    case BFD_RELOC_AARCH64_MOVW_G0_S:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
       shift = 0;
       break;
     case BFD_RELOC_AARCH64_MOVW_G1:
-    case BFD_RELOC_AARCH64_MOVW_G1_S:
     case BFD_RELOC_AARCH64_MOVW_G1_NC:
+    case BFD_RELOC_AARCH64_MOVW_G1_S:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
       shift = 16;
       break;
     case BFD_RELOC_AARCH64_MOVW_G2:
-    case BFD_RELOC_AARCH64_MOVW_G2_S:
     case BFD_RELOC_AARCH64_MOVW_G2_NC:
+    case BFD_RELOC_AARCH64_MOVW_G2_S:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
       if (is32)
        {
@@ -4596,6 +4792,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_Rs:
        case AARCH64_OPND_Ra:
        case AARCH64_OPND_Rt_SYS:
+       case AARCH64_OPND_PAIRREG:
          po_int_reg_or_fail (1, 0);
          break;
 
@@ -4804,7 +5001,8 @@ parse_operands (char *str, const aarch64_opcode *opcode)
        case AARCH64_OPND_IMM_MOV:
          {
            char *saved = str;
-           if (reg_name_p (str, REG_TYPE_R_Z_SP))
+           if (reg_name_p (str, REG_TYPE_R_Z_SP) ||
+               reg_name_p (str, REG_TYPE_VN))
              goto failure;
            str = saved;
            po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
@@ -4962,6 +5160,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_COND:
+       case AARCH64_OPND_COND1:
          info->cond = hash_find_n (aarch64_cond_hsh, str, 2);
          str += 2;
          if (info->cond == NULL)
@@ -4969,6 +5168,13 @@ parse_operands (char *str, const aarch64_opcode *opcode)
              set_syntax_error (_("invalid condition"));
              goto failure;
            }
+         else if (operands[i] == AARCH64_OPND_COND1
+                  && (info->cond->value & 0xe) == 0xe)
+           {
+             /* Not allow AL or NV.  */
+             set_default_error ();
+             goto failure;
+           }
          break;
 
        case AARCH64_OPND_ADDR_ADRP:
@@ -5160,7 +5366,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_SYSREG:
-         if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1))
+         if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0))
              == PARSE_FAIL)
            {
              set_syntax_error (_("unknown or missing system register name"));
@@ -5170,7 +5376,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
          break;
 
        case AARCH64_OPND_PSTATEFIELD:
-         if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0))
+         if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1))
              == PARSE_FAIL)
            {
              set_syntax_error (_("unknown or missing PSTATE field name"));
@@ -5246,6 +5452,37 @@ failure:
       if (! backtrack_pos)
        goto parse_operands_return;
 
+      {
+       /* We reach here because this operand is marked as optional, and
+          either no operand was supplied or the operand was supplied but it
+          was syntactically incorrect.  In the latter case we report an
+          error.  In the former case we perform a few more checks before
+          dropping through to the code to insert the default operand.  */
+
+       char *tmp = backtrack_pos;
+       char endchar = END_OF_INSN;
+
+       if (i != (aarch64_num_of_operands (opcode) - 1))
+         endchar = ',';
+       skip_past_char (&tmp, ',');
+
+       if (*tmp != endchar)
+         /* The user has supplied an operand in the wrong format.  */
+         goto parse_operands_return;
+
+       /* Make sure there is not a comma before the optional operand.
+          For example the fifth operand of 'sys' is optional:
+
+            sys #0,c0,c0,#0,  <--- wrong
+            sys #0,c0,c0,#0   <--- correct.  */
+       if (comma_skipped_p && i && endchar == END_OF_INSN)
+         {
+           set_fatal_syntax_error
+             (_("unexpected comma before the omitted optional operand"));
+           goto parse_operands_return;
+         }
+      }
+
       /* Reaching here means we are dealing with an optional operand that is
         omitted from the assembly line.  */
       gas_assert (optional_operand_p (opcode, i));
@@ -5256,15 +5493,6 @@ failure:
       str = backtrack_pos;
       backtrack_pos = 0;
 
-      /* If this is the last operand that is optional and omitted, but without
-        the presence of a comma.  */
-      if (i && comma_skipped_p && i == aarch64_num_of_operands (opcode) - 1)
-       {
-         set_fatal_syntax_error
-           (_("unexpected comma before the omitted optional operand"));
-         goto parse_operands_return;
-       }
-
       /* Clear any error record after the omitted optional operand has been
         successfully handled.  */
       clear_error ();
@@ -5411,6 +5639,49 @@ programmer_friendly_fixup (aarch64_instruction *instr)
   return TRUE;
 }
 
+/* Check for loads and stores that will cause unpredictable behavior.  */
+
+static void
+warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
+{
+  aarch64_inst *base = &instr->base;
+  const aarch64_opcode *opcode = base->opcode;
+  const aarch64_opnd_info *opnds = base->operands;
+  switch (opcode->iclass)
+    {
+    case ldst_pos:
+    case ldst_imm9:
+    case ldst_unscaled:
+    case ldst_unpriv:
+      /* Loading/storing the base register is unpredictable if writeback.  */
+      if ((aarch64_get_operand_class (opnds[0].type)
+          == AARCH64_OPND_CLASS_INT_REG)
+         && opnds[0].reg.regno == opnds[1].addr.base_regno
+         && opnds[1].addr.base_regno != REG_SP
+         && opnds[1].addr.writeback)
+       as_warn (_("unpredictable transfer with writeback -- `%s'"), str);
+      break;
+    case ldstpair_off:
+    case ldstnapair_offs:
+    case ldstpair_indexed:
+      /* Loading/storing the base register is unpredictable if writeback.  */
+      if ((aarch64_get_operand_class (opnds[0].type)
+          == AARCH64_OPND_CLASS_INT_REG)
+         && (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
+         && opnds[2].addr.writeback)
+           as_warn (_("unpredictable transfer with writeback -- `%s'"), str);
+      /* Load operations must load different registers.  */
+      if ((opcode->opcode & (1 << 22))
+         && opnds[0].reg.regno == opnds[1].reg.regno)
+           as_warn (_("unpredictable load of register pair -- `%s'"), str);
+      break;
+    default:
+      break;
+    }
+}
+
 /* A wrapper function to interface with libopcodes on encoding and
    record the error message if there is any.
 
@@ -5496,6 +5767,14 @@ md_assemble (char *str)
 
   init_operand_error_report ();
 
+  /* Sections are assumed to start aligned. In executable section, there is no
+     MAP_DATA symbol pending. So we only align the address during
+     MAP_DATA --> MAP_INSN transition.
+     For other sections, this is not guaranteed.  */
+  enum mstate mapstate = seg_info (now_seg)->tc_segment_info_data.mapstate;
+  if (!need_pass_2 && subseg_text_p (now_seg) && mapstate == MAP_DATA)
+    frag_align_code (2, 0);
+
   saved_cond = inst.cond;
   reset_aarch64_instruction (&inst);
   inst.cond = saved_cond;
@@ -5511,14 +5790,6 @@ md_assemble (char *str)
        dump_opcode_operands (opcode);
 #endif /* DEBUG_AARCH64 */
 
-      /* Check that this instruction is supported for this CPU.  */
-      if (!opcode->avariant
-         || !AARCH64_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
-       {
-         as_bad (_("selected processor does not support `%s'"), str);
-         return;
-       }
-
       mapping_state (MAP_INSN);
 
       inst_base = &inst.base;
@@ -5543,6 +5814,16 @@ md_assemble (char *str)
          && programmer_friendly_fixup (&inst)
          && do_encode (inst_base->opcode, &inst.base, &inst_base->value))
        {
+         /* Check that this instruction is supported for this CPU.  */
+         if (!opcode->avariant
+             || !AARCH64_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
+           {
+             as_bad (_("selected processor does not support `%s'"), str);
+             return;
+           }
+
+         warn_unpredictable_ldst (&inst, str);
+
          if (inst.reloc.type == BFD_RELOC_UNUSED
              || !inst.reloc.need_libopcodes_p)
            output_inst (NULL);
@@ -5748,7 +6029,24 @@ md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
 }
 
 /* This is called from HANDLE_ALIGN in write.c.         Fill in the contents
-   of an rs_align_code fragment.  */
+   of an rs_align_code fragment.
+
+   Here we fill the frag with the appropriate info for padding the
+   output stream.  The resulting frag will consist of a fixed (fr_fix)
+   and of a repeating (fr_var) part.
+
+   The fixed content is always emitted before the repeating content and
+   these two parts are used as follows in constructing the output:
+   - the fixed part will be used to align to a valid instruction word
+     boundary, in case that we start at a misaligned address; as no
+     executable instruction can live at the misaligned location, we
+     simply fill with zeros;
+   - the variable part will be used to cover the remaining padding and
+     we fill using the AArch64 NOP instruction.
+
+   Note that the size of a RS_ALIGN_CODE fragment is always 7 to provide
+   enough storage space for up to 3 bytes for padding the back to a valid
+   instruction alignment and exactly 4 bytes to store the NOP pattern.  */
 
 void
 aarch64_handle_align (fragS * fragP)
@@ -5759,69 +6057,33 @@ aarch64_handle_align (fragS * fragP)
 
   int bytes, fix, noop_size;
   char *p;
-  const char *noop;
 
   if (fragP->fr_type != rs_align_code)
     return;
 
   bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
   p = fragP->fr_literal + fragP->fr_fix;
-  fix = 0;
-
-  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
-    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
 
 #ifdef OBJ_ELF
   gas_assert (fragP->tc_frag_data.recorded);
 #endif
 
-  noop = aarch64_noop;
   noop_size = sizeof (aarch64_noop);
-  fragP->fr_var = noop_size;
 
-  if (bytes & (noop_size - 1))
+  fix = bytes & (noop_size - 1);
+  if (fix)
     {
-      fix = bytes & (noop_size - 1);
 #ifdef OBJ_ELF
       insert_data_mapping_symbol (MAP_INSN, fragP->fr_fix, fragP, fix);
 #endif
       memset (p, 0, fix);
       p += fix;
-      bytes -= fix;
-    }
-
-  while (bytes >= noop_size)
-    {
-      memcpy (p, noop, noop_size);
-      p += noop_size;
-      bytes -= noop_size;
-      fix += noop_size;
+      fragP->fr_fix += fix;
     }
 
-  fragP->fr_fix += fix;
-}
-
-/* Called from md_do_align.  Used to create an alignment
-   frag in a code section.  */
-
-void
-aarch64_frag_align_code (int n, int max)
-{
-  char *p;
-
-  /* We assume that there will never be a requirement
-     to support alignments greater than x bytes.  */
-  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
-    as_fatal (_
-             ("alignments greater than %d bytes not supported in .text sections"),
-             MAX_MEM_FOR_RS_ALIGN_CODE + 1);
-
-  p = frag_var (rs_align_code,
-               MAX_MEM_FOR_RS_ALIGN_CODE,
-               1,
-               (relax_substateT) max,
-               (symbolS *) NULL, (offsetT) n, (char *) NULL);
-  *p = 0;
+  if (noop_size)
+    memcpy (p, aarch64_noop, noop_size);
+  fragP->fr_var = noop_size;
 }
 
 /* Perform target specific initialisation of a frag.
@@ -5844,21 +6106,20 @@ aarch64_init_frag (fragS * fragP, int max_chars)
   /* Record a mapping symbol for alignment frags.  We will delete this
      later if the alignment ends up empty.  */
   if (!fragP->tc_frag_data.recorded)
+    fragP->tc_frag_data.recorded = 1;
+
+  switch (fragP->fr_type)
     {
-      fragP->tc_frag_data.recorded = 1;
-      switch (fragP->fr_type)
-       {
-       case rs_align:
-       case rs_align_test:
-       case rs_fill:
-         mapping_state_2 (MAP_DATA, max_chars);
-         break;
-       case rs_align_code:
-         mapping_state_2 (MAP_INSN, max_chars);
-         break;
-       default:
-         break;
-       }
+    case rs_align:
+    case rs_align_test:
+    case rs_fill:
+      mapping_state_2 (MAP_DATA, max_chars);
+      break;
+    case rs_align_code:
+      mapping_state_2 (MAP_INSN, max_chars);
+      break;
+    default:
+      break;
     }
 }
 \f
@@ -5886,12 +6147,15 @@ tc_aarch64_regname_to_dw2regnum (char *regname)
     case REG_TYPE_SP_64:
     case REG_TYPE_R_32:
     case REG_TYPE_R_64:
+      return reg->number;
+
     case REG_TYPE_FP_B:
     case REG_TYPE_FP_H:
     case REG_TYPE_FP_S:
     case REG_TYPE_FP_D:
     case REG_TYPE_FP_Q:
-      return reg->number;
+      return reg->number + 64;
+
     default:
       break;
     }
@@ -6415,8 +6679,8 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
        }
       break;
 
-    case BFD_RELOC_AARCH64_JUMP26:
     case BFD_RELOC_AARCH64_CALL26:
+    case BFD_RELOC_AARCH64_JUMP26:
       if (fixP->fx_done || !seg->use_rela_p)
        {
          if (value & 3)
@@ -6432,18 +6696,18 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       break;
 
     case BFD_RELOC_AARCH64_MOVW_G0:
-    case BFD_RELOC_AARCH64_MOVW_G0_S:
     case BFD_RELOC_AARCH64_MOVW_G0_NC:
+    case BFD_RELOC_AARCH64_MOVW_G0_S:
       scale = 0;
       goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G1:
-    case BFD_RELOC_AARCH64_MOVW_G1_S:
     case BFD_RELOC_AARCH64_MOVW_G1_NC:
+    case BFD_RELOC_AARCH64_MOVW_G1_S:
       scale = 16;
       goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G2:
-    case BFD_RELOC_AARCH64_MOVW_G2_S:
     case BFD_RELOC_AARCH64_MOVW_G2_NC:
+    case BFD_RELOC_AARCH64_MOVW_G2_S:
       scale = 32;
       goto movw_common;
     case BFD_RELOC_AARCH64_MOVW_G3:
@@ -6506,21 +6770,54 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
        }
       break;
 
-    case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC:
+      fixP->fx_r_type = (ilp32_p
+                        ? BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC
+                        : BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC);
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      /* Should always be exported to object file, see
+        aarch64_force_relocation().  */
+      gas_assert (!fixP->fx_done);
+      gas_assert (seg->use_rela_p);
+      break;
+
+    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);
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      /* Should always be exported to object file, see
+        aarch64_force_relocation().  */
+      gas_assert (!fixP->fx_done);
+      gas_assert (seg->use_rela_p);
+      break;
+
+    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+    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_LD_PREL19:
     case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
     case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
-    case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
     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:
-    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
-    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
-    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
-    case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
-    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
-    case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
+    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* Should always be exported to object file, see
         aarch64_force_relocation().  */
@@ -6528,17 +6825,31 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       gas_assert (seg->use_rela_p);
       break;
 
-    case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
-    case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
+    case BFD_RELOC_AARCH64_LD_GOT_LO12_NC:
+      /* Should always be exported to object file, see
+        aarch64_force_relocation().  */
+      fixP->fx_r_type = (ilp32_p
+                        ? BFD_RELOC_AARCH64_LD32_GOT_LO12_NC
+                        : BFD_RELOC_AARCH64_LD64_GOT_LO12_NC);
+      gas_assert (!fixP->fx_done);
+      gas_assert (seg->use_rela_p);
+      break;
+
     case BFD_RELOC_AARCH64_ADD_LO12:
-    case BFD_RELOC_AARCH64_LDST8_LO12:
+    case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+    case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
+    case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+    case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+    case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LDST128_LO12:
     case BFD_RELOC_AARCH64_LDST16_LO12:
     case BFD_RELOC_AARCH64_LDST32_LO12:
     case BFD_RELOC_AARCH64_LDST64_LO12:
-    case BFD_RELOC_AARCH64_LDST128_LO12:
-    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
-    case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
-    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LDST8_LO12:
       /* Should always be exported to object file, see
         aarch64_force_relocation().  */
       gas_assert (!fixP->fx_done);
@@ -6546,8 +6857,12 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       break;
 
     case BFD_RELOC_AARCH64_TLSDESC_ADD:
-    case BFD_RELOC_AARCH64_TLSDESC_LDR:
     case BFD_RELOC_AARCH64_TLSDESC_CALL:
+    case BFD_RELOC_AARCH64_TLSDESC_LDR:
+      break;
+
+    case BFD_RELOC_UNUSED:
+      /* An error will already have been reported.  */
       break;
 
     default:
@@ -6669,32 +6984,54 @@ aarch64_force_relocation (struct fix *fixp)
          even if the symbol is extern or weak.  */
       return 0;
 
-    case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_LD_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSDESC_LD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_LO12_NC:
+      /* Pseudo relocs that need to be fixed up according to
+        ilp32_p.  */
+      return 0;
+
+    case BFD_RELOC_AARCH64_ADD_LO12:
+    case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+    case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
+    case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+    case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+    case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+    case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+    case BFD_RELOC_AARCH64_LDST128_LO12:
+    case BFD_RELOC_AARCH64_LDST16_LO12:
+    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_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_LD_PREL19:
     case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
     case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
     case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
-    case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+    case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
     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:
-    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
-    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
-    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
     case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
-    case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
-    case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
-    case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
-    case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
-    case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
-    case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
-    case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
-    case BFD_RELOC_AARCH64_ADD_LO12:
-    case BFD_RELOC_AARCH64_LDST8_LO12:
-    case BFD_RELOC_AARCH64_LDST16_LO12:
-    case BFD_RELOC_AARCH64_LDST32_LO12:
-    case BFD_RELOC_AARCH64_LDST64_LO12:
-    case BFD_RELOC_AARCH64_LDST128_LO12:
-    case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
+    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+    case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
       /* Always leave these relocations for the linker.  */
       return 1;
 
@@ -7049,15 +7386,13 @@ static struct aarch64_option_table aarch64_opts[] = {
   {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
   {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 0,
    NULL},
-#ifdef OBJ_ELF
-  {"mlp64", N_("select the LP64 model"), &ilp32_p, 0, NULL},
-  {"milp32", N_("select the ILP32 model"), &ilp32_p, 1, NULL},
-#endif /* OBJ_ELF */
 #ifdef DEBUG_AARCH64
   {"mdebug-dump", N_("temporary switch for dumping"), &debug_dump, 1, NULL},
 #endif /* DEBUG_AARCH64 */
   {"mverbose-error", N_("output verbose error messages"), &verbose_error_p, 1,
    NULL},
+  {"mno-verbose-error", N_("do not output verbose error messages"),
+   &verbose_error_p, 0, NULL},
   {NULL, NULL, NULL, 0, NULL}
 };
 
@@ -7074,15 +7409,27 @@ struct aarch64_cpu_option_table
    recognized by GCC.  */
 static const struct aarch64_cpu_option_table aarch64_cpus[] = {
   {"all", AARCH64_ANY, NULL},
-  {"cortex-a53",       AARCH64_ARCH_V8, "Cortex-A53"},
-  {"cortex-a57",       AARCH64_ARCH_V8, "Cortex-A57"},
+  {"cortex-a53", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                                 AARCH64_FEATURE_CRC), "Cortex-A53"},
+  {"cortex-a57", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                                 AARCH64_FEATURE_CRC), "Cortex-A57"},
+  {"cortex-a72", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                                 AARCH64_FEATURE_CRC), "Cortex-A72"},
+  {"exynos-m1", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                                AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
+                               "Samsung Exynos M1"},
+  {"thunderx", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                               AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO),
+   "Cavium ThunderX"},
+  /* The 'xgene-1' name is an older name for 'xgene1', which was used
+     in earlier releases and is superseded by 'xgene1' in all
+     tools.  */
+  {"xgene-1", AARCH64_ARCH_V8, "APM X-Gene 1"},
+  {"xgene1", AARCH64_ARCH_V8, "APM X-Gene 1"},
+  {"xgene2", AARCH64_FEATURE (AARCH64_ARCH_V8,
+                             AARCH64_FEATURE_CRC), "APM X-Gene 2"},
   {"generic", AARCH64_ARCH_V8, NULL},
 
-  /* These two are example CPUs supported in GCC, once we have real
-     CPUs they will be removed.  */
-  {"example-1",        AARCH64_ARCH_V8, NULL},
-  {"example-2",        AARCH64_ARCH_V8, NULL},
-
   {NULL, AARCH64_ARCH_NONE, NULL}
 };
 
@@ -7097,6 +7444,7 @@ struct aarch64_arch_option_table
 static const struct aarch64_arch_option_table aarch64_archs[] = {
   {"all", AARCH64_ANY},
   {"armv8-a", AARCH64_ARCH_V8},
+  {"armv8.1-a", AARCH64_ARCH_V8_1},
   {NULL, AARCH64_ARCH_NONE}
 };
 
@@ -7111,7 +7459,12 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"crc",              AARCH64_FEATURE (AARCH64_FEATURE_CRC, 0)},
   {"crypto",           AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0)},
   {"fp",               AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
+  {"lse",              AARCH64_FEATURE (AARCH64_FEATURE_LSE, 0)},
   {"simd",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
+  {"pan",              AARCH64_FEATURE (AARCH64_FEATURE_PAN, 0)},
+  {"lor",              AARCH64_FEATURE (AARCH64_FEATURE_LOR, 0)},
+  {"rdma",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD
+                                        | AARCH64_FEATURE_RDMA, 0)},
   {NULL,               AARCH64_ARCH_NONE}
 };
 
@@ -7124,7 +7477,8 @@ struct aarch64_long_option_table
 };
 
 static int
-aarch64_parse_features (char *str, const aarch64_feature_set **opt_p)
+aarch64_parse_features (char *str, const aarch64_feature_set **opt_p,
+                       bfd_boolean ext_only)
 {
   /* We insist on extensions being added before being removed.  We achieve
      this by using the ADDING_VALUE variable to indicate whether we are
@@ -7140,17 +7494,19 @@ aarch64_parse_features (char *str, const aarch64_feature_set **opt_p)
   while (str != NULL && *str != 0)
     {
       const struct aarch64_option_cpu_value_table *opt;
-      char *ext;
+      char *ext = NULL;
       int optlen;
 
-      if (*str != '+')
+      if (!ext_only)
        {
-         as_bad (_("invalid architectural extension"));
-         return 0;
-       }
+         if (*str != '+')
+           {
+             as_bad (_("invalid architectural extension"));
+             return 0;
+           }
 
-      str++;
-      ext = strchr (str, '+');
+         ext = strchr (++str, '+');
+       }
 
       if (ext != NULL)
        optlen = ext - str;
@@ -7230,7 +7586,7 @@ aarch64_parse_cpu (char *str)
       {
        mcpu_cpu_opt = &opt->value;
        if (ext != NULL)
-         return aarch64_parse_features (ext, &mcpu_cpu_opt);
+         return aarch64_parse_features (ext, &mcpu_cpu_opt, FALSE);
 
        return 1;
       }
@@ -7262,7 +7618,7 @@ aarch64_parse_arch (char *str)
       {
        march_cpu_opt = &opt->value;
        if (ext != NULL)
-         return aarch64_parse_features (ext, &march_cpu_opt);
+         return aarch64_parse_features (ext, &march_cpu_opt, FALSE);
 
        return 1;
       }
@@ -7271,7 +7627,47 @@ aarch64_parse_arch (char *str)
   return 0;
 }
 
+/* ABIs.  */
+struct aarch64_option_abi_value_table
+{
+  char *name;
+  enum aarch64_abi_type value;
+};
+
+static const struct aarch64_option_abi_value_table aarch64_abis[] = {
+  {"ilp32",            AARCH64_ABI_ILP32},
+  {"lp64",             AARCH64_ABI_LP64},
+  {NULL,               0}
+};
+
+static int
+aarch64_parse_abi (char *str)
+{
+  const struct aarch64_option_abi_value_table *opt;
+  size_t optlen = strlen (str);
+
+  if (optlen == 0)
+    {
+      as_bad (_("missing abi name `%s'"), str);
+      return 0;
+    }
+
+  for (opt = aarch64_abis; opt->name != NULL; opt++)
+    if (strlen (opt->name) == optlen && strncmp (str, opt->name, optlen) == 0)
+      {
+       aarch64_abi = opt->value;
+       return 1;
+      }
+
+  as_bad (_("unknown abi `%s'\n"), str);
+  return 0;
+}
+
 static struct aarch64_long_option_table aarch64_long_opts[] = {
+#ifdef OBJ_ELF
+  {"mabi=", N_("<abi name>\t  specify for ABI <abi name>"),
+   aarch64_parse_abi, NULL},
+#endif /* OBJ_ELF */
   {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
    aarch64_parse_cpu, NULL},
   {"march=", N_("<arch name>\t  assemble for architecture <arch name>"),
@@ -7405,7 +7801,7 @@ s_aarch64_cpu (int ignored ATTRIBUTE_UNUSED)
       {
        mcpu_cpu_opt = &opt->value;
        if (ext != NULL)
-         if (!aarch64_parse_features (ext, &mcpu_cpu_opt))
+         if (!aarch64_parse_features (ext, &mcpu_cpu_opt, FALSE))
            return;
 
        cpu_variant = *mcpu_cpu_opt;
@@ -7451,7 +7847,7 @@ s_aarch64_arch (int ignored ATTRIBUTE_UNUSED)
       {
        mcpu_cpu_opt = &opt->value;
        if (ext != NULL)
-         if (!aarch64_parse_features (ext, &mcpu_cpu_opt))
+         if (!aarch64_parse_features (ext, &mcpu_cpu_opt, FALSE))
            return;
 
        cpu_variant = *mcpu_cpu_opt;
@@ -7466,6 +7862,28 @@ s_aarch64_arch (int ignored ATTRIBUTE_UNUSED)
   ignore_rest_of_line ();
 }
 
+/* Parse a .arch_extension directive.  */
+
+static void
+s_aarch64_arch_extension (int ignored ATTRIBUTE_UNUSED)
+{
+  char saved_char;
+  char *ext = input_line_pointer;;
+
+  while (*input_line_pointer && !ISSPACE (*input_line_pointer))
+    input_line_pointer++;
+  saved_char = *input_line_pointer;
+  *input_line_pointer = 0;
+
+  if (!aarch64_parse_features (ext, &mcpu_cpu_opt, TRUE))
+    return;
+
+  cpu_variant = *mcpu_cpu_opt;
+
+  *input_line_pointer = saved_char;
+  demand_empty_rest_of_line ();
+}
+
 /* Copy symbol information.  */
 
 void
This page took 0.048 seconds and 4 git commands to generate.