diff -rup binutils-2.30/bfd/archures.c binutils-2.30.new/bfd/archures.c --- binutils-2.30/bfd/archures.c 2021-03-23 16:21:44.001022834 +0000 +++ binutils-2.30.new/bfd/archures.c 2021-03-23 16:20:02.829710624 +0000 @@ -526,6 +526,7 @@ DESCRIPTION .#define bfd_mach_tilegx32 2 . bfd_arch_aarch64, {* AArch64. *} .#define bfd_mach_aarch64 0 +.#define bfd_mach_aarch64_8R 1 .#define bfd_mach_aarch64_ilp32 32 . bfd_arch_nios2, {* Nios II. *} .#define bfd_mach_nios2 0 diff -rup binutils-2.30/bfd/bfd-in2.h binutils-2.30.new/bfd/bfd-in2.h --- binutils-2.30/bfd/bfd-in2.h 2021-03-23 16:21:44.002022828 +0000 +++ binutils-2.30.new/bfd/bfd-in2.h 2021-03-23 16:20:02.815710719 +0000 @@ -985,12 +985,6 @@ extern void bfd_elf64_aarch64_init_maps extern void bfd_elf32_aarch64_init_maps (bfd *); -extern void bfd_elf64_aarch64_set_options - (bfd *, struct bfd_link_info *, int, int, int, int, int, int); - -extern void bfd_elf32_aarch64_set_options - (bfd *, struct bfd_link_info *, int, int, int, int, int, int); - /* ELF AArch64 mapping symbol support. */ #define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) #define BFD_AARCH64_SPECIAL_SYM_TYPE_TAG (1 << 1) @@ -2388,6 +2382,7 @@ enum bfd_architecture #define bfd_mach_tilegx32 2 bfd_arch_aarch64, /* AArch64. */ #define bfd_mach_aarch64 0 +#define bfd_mach_aarch64_8R 1 #define bfd_mach_aarch64_ilp32 32 bfd_arch_nios2, /* Nios II. */ #define bfd_mach_nios2 0 @@ -5961,6 +5956,36 @@ of a signed value. Changes instruction value's sign. */ BFD_RELOC_AARCH64_MOVW_G2_S, +/* AArch64 MOV[NZ] instruction with most significant bits 0 to 15 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_PREL_G0, + +/* AArch64 MOV[NZ] instruction with most significant bits 0 to 15 +of a signed value. Changes instruction to MOVZ or MOVN depending on the +value's sign. */ + BFD_RELOC_AARCH64_MOVW_PREL_G0_NC, + +/* AArch64 MOVK instruction with most significant bits 16 to 31 +of a signed value. */ + BFD_RELOC_AARCH64_MOVW_PREL_G1, + +/* AArch64 MOVK instruction with most significant bits 16 to 31 +of a signed value. */ + BFD_RELOC_AARCH64_MOVW_PREL_G1_NC, + +/* AArch64 MOVK instruction with most significant bits 32 to 47 +of a signed value. */ + BFD_RELOC_AARCH64_MOVW_PREL_G2, + +/* AArch64 MOVK instruction with most significant bits 32 to 47 +of a signed value. */ + BFD_RELOC_AARCH64_MOVW_PREL_G2_NC, + +/* AArch64 MOVK instruction with most significant bits 47 to 63 +of a signed value. */ + BFD_RELOC_AARCH64_MOVW_PREL_G3, + /* AArch64 Load Literal instruction, holding a 19 bit pc-relative word offset. The lowest two bits must be zero and are not stored in the instruction, giving a 21 bit signed byte offset. */ @@ -6188,6 +6213,34 @@ instructions. */ /* AArch64 TLS LOCAL EXEC relocation. */ BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC, +/* bit[11:1] of byte offset to module TLS base address, encoded in ldst +instructions. */ + BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12, + +/* Similar as BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12, but no overflow check. */ + BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC, + +/* bit[11:2] of byte offset to module TLS base address, encoded in ldst +instructions. */ + BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12, + +/* Similar as BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12, but no overflow check. */ + BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC, + +/* bit[11:3] of byte offset to module TLS base address, encoded in ldst +instructions. */ + BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12, + +/* Similar as BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12, but no overflow check. */ + BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC, + +/* bit[11:0] of byte offset to module TLS base address, encoded in ldst +instructions. */ + BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12, + +/* Similar as BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12, but no overflow check. */ + BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC, + /* AArch64 TLS DESC relocation. */ BFD_RELOC_AARCH64_TLSDESC_LD_PREL19, @@ -6271,6 +6324,14 @@ any object files. */ /* Similar as BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12, but no overflow check. */ BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC, +/* AArch64 pseudo relocation code for TLS local exec mode. It's to be +used internally by the AArch64 assembler and not (currently) written to +any object files. */ + BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12, + +/* Similar as BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12, but no overflow check. */ + BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC, + /* AArch64 pseudo relocation code to be used internally by the AArch64 assembler and not (currently) written to any object files. */ BFD_RELOC_AARCH64_LD_GOT_LO12_NC, diff -rup binutils-2.30/bfd/cpu-aarch64.c binutils-2.30.new/bfd/cpu-aarch64.c --- binutils-2.30/bfd/cpu-aarch64.c 2018-01-13 13:31:15.000000000 +0000 +++ binutils-2.30.new/bfd/cpu-aarch64.c 2021-03-23 16:20:02.830710617 +0000 @@ -1,5 +1,5 @@ /* BFD support for AArch64. - Copyright (C) 2009-2018 Free Software Foundation, Inc. + Copyright (C) 2009-2021 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of BFD, the Binary File Descriptor library. @@ -22,6 +22,7 @@ #include "bfd.h" #include "libbfd.h" #include "libiberty.h" +#include "cpu-aarch64.h" /* This routine is provided two arch_infos and works out which Aarch64 machine which would be compatible with both and returns a pointer @@ -68,10 +69,11 @@ static struct } processors[] = { - /* These two are example CPUs supported in GCC, once we have real - CPUs they will be removed. */ - { bfd_mach_aarch64, "example-1" }, - { bfd_mach_aarch64, "example-2" } + { bfd_mach_aarch64, "cortex-a34" }, + { bfd_mach_aarch64, "cortex-a65" }, + { bfd_mach_aarch64, "cortex-a65ae" }, + { bfd_mach_aarch64, "cortex-a76ae" }, + { bfd_mach_aarch64, "cortex-a77" } }; static bfd_boolean @@ -103,10 +105,14 @@ scan (const struct bfd_arch_info *info, #define N(NUMBER, PRINT, WORDSIZE, DEFAULT, NEXT) \ { WORDSIZE, WORDSIZE, 8, bfd_arch_aarch64, NUMBER, \ "aarch64", PRINT, 4, DEFAULT, compatible, scan, \ - bfd_arch_default_fill, NEXT } + bfd_arch_default_fill, NEXT, 0 } + +static const bfd_arch_info_type bfd_aarch64_arch_v8_r = + N (bfd_mach_aarch64_8R, "aarch64:armv8-r", 64, FALSE, NULL); static const bfd_arch_info_type bfd_aarch64_arch_ilp32 = - N (bfd_mach_aarch64_ilp32, "aarch64:ilp32", 32, FALSE, NULL); + N (bfd_mach_aarch64_ilp32, "aarch64:ilp32", 32, FALSE, + &bfd_aarch64_arch_v8_r); const bfd_arch_info_type bfd_aarch64_arch = N (0, "aarch64", 64, TRUE, &bfd_aarch64_arch_ilp32); diff -rup binutils-2.30/bfd/reloc.c binutils-2.30.new/bfd/reloc.c --- binutils-2.30/bfd/reloc.c 2018-01-13 13:31:15.000000000 +0000 +++ binutils-2.30.new/bfd/reloc.c 2021-03-23 16:20:02.829710624 +0000 @@ -7071,6 +7071,43 @@ ENUMDOC of a signed value. Changes instruction to MOVZ or MOVN depending on the value's sign. ENUM + BFD_RELOC_AARCH64_MOVW_PREL_G0 +ENUMDOC + AArch64 MOV[NZ] instruction with most significant bits 0 to 15 + of a signed value. Changes instruction to MOVZ or MOVN depending on the + value's sign. +ENUM + BFD_RELOC_AARCH64_MOVW_PREL_G0_NC +ENUMDOC + AArch64 MOV[NZ] instruction with most significant bits 0 to 15 + of a signed value. Changes instruction to MOVZ or MOVN depending on the + value's sign. +ENUM + BFD_RELOC_AARCH64_MOVW_PREL_G1 +ENUMDOC + AArch64 MOVK instruction with most significant bits 16 to 31 + of a signed value. +ENUM + BFD_RELOC_AARCH64_MOVW_PREL_G1_NC +ENUMDOC + AArch64 MOVK instruction with most significant bits 16 to 31 + of a signed value. +ENUM + BFD_RELOC_AARCH64_MOVW_PREL_G2 +ENUMDOC + AArch64 MOVK instruction with most significant bits 32 to 47 + of a signed value. +ENUM + BFD_RELOC_AARCH64_MOVW_PREL_G2_NC +ENUMDOC + AArch64 MOVK instruction with most significant bits 32 to 47 + of a signed value. +ENUM + BFD_RELOC_AARCH64_MOVW_PREL_G3 +ENUMDOC + AArch64 MOVK instruction with most significant bits 47 to 63 + of a signed value. +ENUM BFD_RELOC_AARCH64_LD_LO19_PCREL ENUMDOC AArch64 Load Literal instruction, holding a 19 bit pc-relative word @@ -7359,6 +7396,42 @@ ENUM ENUMDOC AArch64 TLS LOCAL EXEC relocation. ENUM + BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12 +ENUMDOC + bit[11:1] of byte offset to module TLS base address, encoded in ldst + instructions. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC +ENUMDOC + Similar as BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12, but no overflow check. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12 +ENUMDOC + bit[11:2] of byte offset to module TLS base address, encoded in ldst + instructions. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC +ENUMDOC + Similar as BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12, but no overflow check. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12 +ENUMDOC + bit[11:3] of byte offset to module TLS base address, encoded in ldst + instructions. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC +ENUMDOC + Similar as BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12, but no overflow check. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12 +ENUMDOC + bit[11:0] of byte offset to module TLS base address, encoded in ldst + instructions. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC +ENUMDOC + Similar as BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12, but no overflow check. +ENUM BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 ENUMDOC AArch64 TLS DESC relocation. @@ -7467,6 +7540,16 @@ ENUM ENUMDOC Similar as BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12, but no overflow check. ENUM + BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12 +ENUMDOC + AArch64 pseudo relocation code for TLS local exec mode. It's to be + used internally by the AArch64 assembler and not (currently) written to + any object files. +ENUM + BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC +ENUMDOC + Similar as BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12, but no overflow check. +ENUM BFD_RELOC_AARCH64_LD_GOT_LO12_NC ENUMDOC AArch64 pseudo relocation code to be used internally by the AArch64 diff -rup binutils-2.30/gas/config/tc-aarch64.c binutils-2.30.new/gas/config/tc-aarch64.c --- binutils-2.30/gas/config/tc-aarch64.c 2021-03-23 16:21:44.128021971 +0000 +++ binutils-2.30.new/gas/config/tc-aarch64.c 2021-03-23 16:19:55.031763633 +0000 @@ -1,6 +1,6 @@ /* tc-aarch64.c -- Assemble for the AArch64 ISA - Copyright (C) 2009-2018 Free Software Foundation, Inc. + Copyright (C) 2009-2021 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of GAS. @@ -35,6 +35,9 @@ #include "dwarf2dbg.h" +/* Number of littlenums required to hold an extended precision number. */ +#define MAX_LITTLENUMS 6 + /* Types of processor to assemble for. */ #ifndef CPU_DEFAULT #define CPU_DEFAULT AARCH64_ARCH_V8 @@ -55,6 +58,9 @@ static const aarch64_feature_set *march_ /* 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; @@ -146,6 +152,13 @@ static aarch64_instruction inst; static bfd_boolean parse_operands (char *, const aarch64_opcode *); static bfd_boolean programmer_friendly_fixup (aarch64_instruction *); +#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 utilities which should only be called by parse_operands @@ -228,9 +241,6 @@ set_fatal_syntax_error (const char *erro set_error (AARCH64_OPDE_FATAL_SYNTAX_ERROR, error); } -/* 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. */ @@ -243,12 +253,6 @@ set_fatal_syntax_error (const char *erro typedef struct { const char *template; - unsigned long value; -} asm_barrier_opt; - -typedef struct -{ - const char *template; uint32_t value; } asm_nzcv; @@ -439,24 +443,28 @@ get_reg_expected_msg (aarch64_reg_type r /* 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 -static struct hash_control *aarch64_ops_hsh; -static struct hash_control *aarch64_cond_hsh; -static struct hash_control *aarch64_shift_hsh; -static struct hash_control *aarch64_sys_regs_hsh; -static struct hash_control *aarch64_pstatefield_hsh; -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_reg_hsh; -static struct hash_control *aarch64_barrier_opt_hsh; -static struct hash_control *aarch64_nzcv_hsh; -static struct hash_control *aarch64_pldop_hsh; -static struct hash_control *aarch64_hint_opt_hsh; +#define htab_t struct hash_control * + +static htab_t aarch64_ops_hsh; +static htab_t aarch64_cond_hsh; +static htab_t aarch64_shift_hsh; +static htab_t aarch64_sys_regs_hsh; +static htab_t aarch64_pstatefield_hsh; +static htab_t aarch64_sys_regs_ic_hsh; +static htab_t aarch64_sys_regs_dc_hsh; +static htab_t aarch64_sys_regs_at_hsh; +static htab_t aarch64_sys_regs_tlbi_hsh; +static htab_t aarch64_sys_regs_sr_hsh; +static htab_t aarch64_reg_hsh; +static htab_t aarch64_barrier_opt_hsh; +static htab_t aarch64_nzcv_hsh; +static htab_t aarch64_pldop_hsh; +static htab_t aarch64_hint_opt_hsh; /* Stuff needed to resolve the label ambiguity As: @@ -520,7 +528,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) == '#') @@ -618,6 +626,96 @@ my_get_expression (expressionS * ep, cha return TRUE; } +#define MAX_PRECISION 5 +#define H_PRECISION 1 +#define F_PRECISION 2 +#define D_PRECISION 4 +#define X_PRECISION 5 +#define P_PRECISION 5 +/* Length in LittleNums of guard bits. */ +#define GUARD 2 + +static void +make_invalid_floating_point_number (LITTLENUM_TYPE *words) +{ + as_bad (_("cannot create floating-point number")); + /* Zero the leftmost bit. */ + words[0] = (LITTLENUM_TYPE) ((unsigned) -1) >> 1; + words[1] = (LITTLENUM_TYPE) -1; + words[2] = (LITTLENUM_TYPE) -1; + words[3] = (LITTLENUM_TYPE) -1; + words[4] = (LITTLENUM_TYPE) -1; + words[5] = (LITTLENUM_TYPE) -1; +} + +char * atof_ieee_detail (char *, int, int, LITTLENUM_TYPE *, FLONUM_TYPE *); + +/* Build a floating point constant at str into a IEEE floating + point number. This function does the same thing as atof_ieee + however it allows more control over the exact format, i.e. + explicitly specifying the precision and number of exponent bits + instead of relying on this infomation being deduced from a given type. + + If generic_float_info is not NULL then it will be set to contain generic + infomation about the parsed floating point number. + + Returns pointer past text consumed. */ +char * +atof_ieee_detail (char * str, + int precision, + int exponent_bits, + LITTLENUM_TYPE * words, + FLONUM_TYPE * generic_float_info) +{ + /* Extra bits for zeroed low-order bits. + The 1st MAX_PRECISION are zeroed, the last contain flonum bits. */ + static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; + char *return_value; + + /* Number of 16-bit words in the format. */ + FLONUM_TYPE save_gen_flonum; + + /* We have to save the generic_floating_point_number because it + contains storage allocation about the array of LITTLENUMs where + the value is actually stored. We will allocate our own array of + littlenums below, but have to restore the global one on exit. */ + save_gen_flonum = generic_floating_point_number; + + return_value = str; + generic_floating_point_number.low = bits + MAX_PRECISION; + generic_floating_point_number.high = NULL; + generic_floating_point_number.leader = NULL; + generic_floating_point_number.exponent = 0; + generic_floating_point_number.sign = '\0'; + + /* Use more LittleNums than seems necessary: the highest flonum may + have 15 leading 0 bits, so could be useless. */ + + memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION); + + generic_floating_point_number.high + = generic_floating_point_number.low + precision - 1 + GUARD; + + if (atof_generic (&return_value, ".", EXP_CHARS, + &generic_floating_point_number)) + { + make_invalid_floating_point_number (words); + return NULL; + } + + if (generic_float_info) + *generic_float_info = generic_floating_point_number; + + gen_to_words (words, precision, exponent_bits); + + /* Restore the generic_floating_point_number's storage alloc (and + everything else). */ + generic_floating_point_number = save_gen_flonum; + + return return_value; +} + + /* Turn a string in input_line_pointer into a floating point constant of type TYPE, and store the appropriate bytes in *LITP. The number of LITTLENUMS emitted is stored in *SIZEP. An error message is @@ -626,6 +724,54 @@ my_get_expression (expressionS * ep, cha const char * md_atof (int type, char *litP, int *sizeP) { + /* If this is a bfloat16 type, then parse it slightly differently - + as it does not follow the IEEE standard exactly. */ + if (type == 'b') + { + char * t; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + FLONUM_TYPE generic_float; + + t = atof_ieee_detail (input_line_pointer, 1, 8, words, &generic_float); + + if (t) + input_line_pointer = t; + else + return _("invalid floating point number"); + + switch (generic_float.sign) + { + /* Is +Inf. */ + case 'P': + words[0] = 0x7f80; + break; + + /* Is -Inf. */ + case 'N': + words[0] = 0xff80; + break; + + /* Is NaN. */ + /* bfloat16 has two types of NaN - quiet and signalling. + Quiet NaN has bit[6] == 1 && faction != 0, whereas + signalling Nan's have bit[0] == 0 && fraction != 0. + Chose this specific encoding as it is the same form + as used by other IEEE 754 encodings in GAS. */ + case 0: + words[0] = 0x7fff; + break; + + default: + break; + } + + *sizeP = 2; + + md_number_to_chars (litP, (valueT) words[0], sizeof (LITTLENUM_TYPE)); + + return NULL; + } + return ieee_md_atof (type, litP, sizeP, target_big_endian); } @@ -826,7 +972,7 @@ parse_vector_type_for_operand (aarch64_r return FALSE; } -elt_size: + elt_size: switch (TOLOWER (*ptr)) { case 'b': @@ -1945,7 +2091,7 @@ s_variant_pcs (int ignored ATTRIBUTE_UNU restore_line_pointer (c); demand_empty_rest_of_line (); bfdsym = symbol_get_bfdsym (sym); - elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); + elfsym = elf_symbol_from (NULL, bfdsym); gas_assert (elfsym); elfsym->internal_elf_sym.st_other |= STO_AARCH64_VARIANT_PCS; } @@ -2088,6 +2234,8 @@ const pseudo_typeS md_pseudo_table[] = { {"dword", s_aarch64_elf_cons, 8}, {"variant_pcs", s_variant_pcs, 0}, #endif + {"float16", float_cons, 'h'}, + {"bfloat16", float_cons, 'b'}, {0, 0, 0} }; @@ -2122,7 +2270,7 @@ reg_name_p (char *str, aarch64_reg_type return FALSE; skip_whitespace (str); - if (*str == ',' || is_end_of_line[(unsigned int) *str]) + if (*str == ',' || is_end_of_line[(unsigned char) *str]) return TRUE; return FALSE; @@ -2302,7 +2450,6 @@ parse_aarch64_imm_float (char **ccp, int 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; @@ -2332,26 +2479,10 @@ parse_aarch64_imm_float (char **ccp, int 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) @@ -2373,7 +2504,7 @@ parse_aarch64_imm_float (char **ccp, int *ccp = str; return TRUE; -invalid_fp: + invalid_fp: set_fatal_syntax_error (_("invalid floating-point constant")); return FALSE; } @@ -2600,6 +2731,69 @@ static struct reloc_table_entry reloc_ta 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 */ @@ -2862,7 +3056,7 @@ static struct reloc_table_entry reloc_ta 0, 0, BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12, - 0, + BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12, 0}, /* Get tp offset for a symbol. */ @@ -2880,7 +3074,7 @@ static struct reloc_table_entry reloc_ta 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. */ @@ -3337,6 +3531,7 @@ parse_shifter_operand_reloc (char **str, [base,Xm,SXTX {#imm}] [base,Wm,(S|U)XTW {#imm}] Pre-indexed + [base]! // in ldraa/ldrab exclusive [base,#imm]! Post-indexed [base],#imm @@ -3350,6 +3545,7 @@ parse_shifter_operand_reloc (char **str, [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 @@ -3515,6 +3711,7 @@ parse_address_main (char **str, aarch64_ 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}] */ @@ -3528,7 +3725,10 @@ parse_address_main (char **str, aarch64_ 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; @@ -3646,18 +3846,43 @@ parse_address_main (char **str, aarch64_ } /* 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.] as shorthand for + [Zn., 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; @@ -3849,7 +4074,7 @@ static int parse_barrier (char **str) { char *p, *q; - const asm_barrier_opt *o; + const struct aarch64_name_value_pair *o; p = q = *str; while (ISALPHA (*q)) @@ -3881,7 +4106,7 @@ parse_barrier_psb (char **str, if (!o) { set_fatal_syntax_error - ( _("unknown or missing option to PSB")); + ( _("unknown or missing option to PSB/TSB")); return PARSE_FAIL; } @@ -3889,7 +4114,48 @@ parse_barrier_psb (char **str, { /* PSB only accepts option name 'CSYNC'. */ set_syntax_error - (_("the specified option is not accepted for PSB")); + (_("the specified option is not accepted for PSB/TSB")); + return PARSE_FAIL; + } + + *str = q; + *hint_opt = o; + 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; } @@ -3909,21 +4175,26 @@ parse_barrier_psb (char **str, */ static int -parse_sys_reg (char **str, struct hash_control *sys_regs, - int imple_defined_p, int pstatefield_p) +parse_sys_reg (char **str, htab_t sys_regs, + int imple_defined_p, int pstatefield_p, + uint32_t* flags) { char *p, *q; - char buf[32]; + char buf[AARCH64_MAX_SYSREG_NAME_LEN]; const aarch64_sys_reg *o; int value; p = buf; for (q = *str; ISALNUM (*q) || *q == '_'; q++) - if (p < buf + 31) + if (p < buf + (sizeof (buf) - 1)) *p++ = TOLOWER (*q); *p = '\0'; - /* Assert that BUF be large enough. */ - gas_assert (p - buf == q - *str); + + /* If the name is longer than AARCH64_MAX_SYSREG_NAME_LEN then it cannot be a + valid system register. This is enforced by construction of the hash + table. */ + if (p - buf != q - *str) + return PARSE_FAIL; o = hash_find (sys_regs, buf); if (!o) @@ -3941,6 +4212,8 @@ parse_sys_reg (char **str, struct hash_c 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 @@ -3948,13 +4221,17 @@ parse_sys_reg (char **str, struct hash_c 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)) + if (!pstatefield_p + && !aarch64_sys_ins_reg_supported_p (cpu_variant, o->name, + o->value, o->flags, o->features)) as_bad (_("selected processor does not support system register " "name '%s'"), buf); - if (aarch64_sys_reg_deprecated_p (o)) + if (aarch64_sys_reg_deprecated_p (o->flags)) 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; @@ -3965,25 +4242,35 @@ parse_sys_reg (char **str, struct hash_c for the option, or NULL. */ static const aarch64_sys_ins_reg * -parse_sys_ins_reg (char **str, struct hash_control *sys_ins_regs) +parse_sys_ins_reg (char **str, htab_t sys_ins_regs) { char *p, *q; - char buf[32]; + char buf[AARCH64_MAX_SYSREG_NAME_LEN]; const aarch64_sys_ins_reg *o; p = buf; for (q = *str; ISALNUM (*q) || *q == '_'; q++) - if (p < buf + 31) + if (p < buf + (sizeof (buf) - 1)) *p++ = TOLOWER (*q); *p = '\0'; + /* If the name is longer than AARCH64_MAX_SYSREG_NAME_LEN then it cannot be a + valid system register. This is enforced by construction of the hash + table. */ + if (p - buf != q - *str) + return NULL; + o = hash_find (sys_ins_regs, buf); if (!o) return NULL; - if (!aarch64_sys_ins_reg_supported_p (cpu_variant, o)) + if (!aarch64_sys_ins_reg_supported_p (cpu_variant, + o->name, o->value, o->flags, 0)) as_bad (_("selected processor does not support system register " "name '%s'"), buf); + if (aarch64_sys_reg_deprecated_p (o->flags)) + as_warn (_("system register name '%s' is deprecated and may be " + "removed in a future release"), buf); *str = q; return o; @@ -4137,7 +4424,10 @@ reencode_movzn_to_movn (uint32_t opcode) static fixS * fix_new_aarch64 (fragS * frag, int where, - short int size, expressionS * exp, int pc_rel, int reloc) + short int size, + expressionS * exp, + int pc_rel, + int reloc) { fixS *new_fix; @@ -4371,6 +4661,7 @@ record_operand_error (const aarch64_opco info.index = idx; info.kind = kind; info.error = error; + info.non_fatal = FALSE; record_operand_error_info (opcode, &info); } @@ -4386,6 +4677,7 @@ record_operand_error_with_data (const aa 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); } @@ -4504,7 +4796,8 @@ print_operands (char *buf, const aarch64 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, cpu_variant); /* Delimiter. */ if (str[0] != '\0') @@ -4550,12 +4843,14 @@ output_operand_error_record (const opera 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: @@ -4565,21 +4860,21 @@ output_operand_error_record (const opera 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 @@ -4627,7 +4922,7 @@ output_operand_error_record (const opera && 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. */ @@ -4676,36 +4971,36 @@ output_operand_error_record (const opera 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: @@ -4719,10 +5014,15 @@ output_operand_error_record (const opera 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 multiple instruction templates; output the - error message that most closely describes the problem. */ + 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; @@ -4740,9 +5040,14 @@ 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; } @@ -4753,16 +5058,21 @@ output_operand_error_report (char *str) { 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 @@ -4778,6 +5088,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]); @@ -4802,7 +5123,8 @@ get_aarch64_insn (char *buf) { unsigned char *where = (unsigned char *) buf; uint32_t result; - result = (where[0] | (where[1] << 8) | (where[2] << 16) | (where[3] << 24)); + result = ((where[0] | (where[1] << 8) | (where[2] << 16) + | ((uint32_t) where[3] << 24))); return result; } @@ -4957,6 +5279,10 @@ vectype_to_qualifier (const struct vecto if (vectype->type == NT_b && vectype->width == 4) return AARCH64_OPND_QLF_S_4B; + /* Special case S_2H. */ + if (vectype->type == NT_h && vectype->width == 2) + return AARCH64_OPND_QLF_S_2H; + /* Vector element register. */ return AARCH64_OPND_QLF_S_B + vectype->type; } @@ -4989,7 +5315,7 @@ vectype_to_qualifier (const struct vecto return offset; } -vectype_conversion_fail: + vectype_conversion_fail: first_error (_("bad vector arrangement type")); return AARCH64_OPND_QLF_NIL; } @@ -5014,6 +5340,8 @@ process_omitted_operand (enum aarch64_op case AARCH64_OPND_Rm: case AARCH64_OPND_Rt: case AARCH64_OPND_Rt2: + case AARCH64_OPND_Rt_LS64: + case AARCH64_OPND_Rt_SP: case AARCH64_OPND_Rs: case AARCH64_OPND_Ra: case AARCH64_OPND_Rt_SYS: @@ -5041,6 +5369,7 @@ process_omitted_operand (enum aarch64_op 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; @@ -5079,6 +5408,11 @@ process_omitted_operand (enum aarch64_op 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; @@ -5102,6 +5436,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: @@ -5119,6 +5457,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: @@ -5132,6 +5472,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: @@ -5144,6 +5486,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) @@ -5156,6 +5500,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 @@ -5202,7 +5547,7 @@ ldst_lo12_determine_real_reloc_type (voi 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, @@ -5223,13 +5568,31 @@ ldst_lo12_determine_real_reloc_type (voi 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) @@ -5240,7 +5603,9 @@ ldst_lo12_determine_real_reloc_type (voi 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); @@ -5345,14 +5710,31 @@ parse_operands (char *str, const aarch64 case AARCH64_OPND_Rt2: case AARCH64_OPND_Rs: case AARCH64_OPND_Ra: + case AARCH64_OPND_Rt_LS64: case AARCH64_OPND_Rt_SYS: case AARCH64_OPND_PAIRREG: case AARCH64_OPND_SVE_Rm: po_int_reg_or_fail (REG_TYPE_R_Z); + + /* In LS64 load/store instructions Rt register number must be even + and <=22. */ + if (operands[i] == AARCH64_OPND_Rt_LS64) + { + /* We've already checked if this is valid register. + This will check if register number (Rt) is not undefined for LS64 + instructions: + if Rt<4:3> == '11' || Rt<0> == '1' then UNDEFINED. */ + if ((info->reg.regno & 0x18) == 0x18 || (info->reg.regno & 0x01) == 0x01) + { + set_syntax_error (_("invalid Rt register number in 64-byte load/store")); + goto failure; + } + } break; 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); @@ -5477,6 +5859,8 @@ parse_operands (char *str, const aarch64 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; @@ -5485,6 +5869,7 @@ parse_operands (char *str, const aarch64 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: @@ -5533,11 +5918,20 @@ parse_operands (char *str, const aarch64 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; } @@ -5591,7 +5985,10 @@ parse_operands (char *str, const aarch64 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: @@ -5603,8 +6000,10 @@ parse_operands (char *str, const aarch64 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: @@ -5618,6 +6017,7 @@ parse_operands (char *str, const aarch64 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; @@ -5865,6 +6265,7 @@ parse_operands (char *str, const aarch64 break; case AARCH64_OPND_EXCEPTION: + case AARCH64_OPND_UNDEFINED: po_misc_or_fail (parse_immediate_expression (&str, &inst.reloc.exp, imm_reg_type)); assign_imm_if_const_or_fixup_later (&inst.reloc, info, @@ -6062,6 +6463,8 @@ parse_operands (char *str, const aarch64 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) @@ -6116,7 +6519,11 @@ parse_operands (char *str, const aarch64 || (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; @@ -6144,6 +6551,7 @@ parse_operands (char *str, const aarch64 break; case AARCH64_OPND_SVE_ADDR_RI_S4x16: + case AARCH64_OPND_SVE_ADDR_RI_S4x32: case AARCH64_OPND_SVE_ADDR_RI_S4xVL: case AARCH64_OPND_SVE_ADDR_RI_S4x2xVL: case AARCH64_OPND_SVE_ADDR_RI_S4x3xVL: @@ -6182,6 +6590,25 @@ parse_operands (char *str, const aarch64 info->addr.offset.imm = inst.reloc.exp.X_add_number; break; + case AARCH64_OPND_SVE_ADDR_R: + /* [{, }] + 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: @@ -6228,6 +6655,33 @@ parse_operands (char *str, const aarch64 info->qualifier = offset_qualifier; goto regoff_addr; + case AARCH64_OPND_SVE_ADDR_ZX: + /* [Zn.{, }]. */ + 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: @@ -6269,17 +6723,21 @@ parse_operands (char *str, const aarch64 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")); @@ -6292,18 +6750,26 @@ parse_operands (char *str, const aarch64 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); -sys_reg_ins: + sys_reg_ins: if (inst.base.operands[i].sysins_op == NULL) { set_fatal_syntax_error ( _("unknown or missing operation name")); @@ -6324,12 +6790,53 @@ sys_reg_ins: backtrack_pos = 0; goto failure; } + if (val != PARSE_FAIL + && operands[i] == AARCH64_OPND_BARRIER) + { + /* Regular barriers accept options CRm (C0-C15). + DSB nXS barrier variant accepts values > 15. */ + if (val < 0 || val > 15) + { + set_syntax_error (_("the specified option is not accepted in DSB")); + goto failure; + } + } /* This is an extension to accept a 0..15 immediate. */ if (val == PARSE_FAIL) po_imm_or_fail (0, 15); info->barrier = aarch64_barrier_options + val; break; + case AARCH64_OPND_BARRIER_DSB_NXS: + val = parse_barrier (&str); + if (val != PARSE_FAIL) + { + /* DSB nXS barrier variant accept only