X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-aarch64.c;h=9ff2d6803dd1972ffd03178f8bb4633d263c2a36;hb=96cbfd9f0488e9536bfc27550ebf90cb1ecac93b;hp=e857f2929a46fea086ddd8058b86a2b142ed0afb;hpb=c8d59609b1cf66eaff3c486e483f5e3d647c66ff;p=thirdparty%2Fbinutils-gdb.git diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index e857f2929a4..9ff2d6803dd 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -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. @@ -22,7 +22,7 @@ #include "as.h" #include #include -#include "bfd_stdint.h" +#include #define NO_RELOC 0 #include "safe-ctype.h" #include "subsegs.h" @@ -55,6 +55,9 @@ static const aarch64_feature_set *march_cpu_opt = NULL; /* Constants for known architecture features. */ static const aarch64_feature_set cpu_default = CPU_DEFAULT; +/* Currently active instruction sequence. */ +static aarch64_instr_sequence *insn_sequence = NULL; + #ifdef OBJ_ELF /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ static symbolS *GOT_symbol; @@ -143,8 +146,15 @@ typedef struct aarch64_instruction aarch64_instruction; static aarch64_instruction inst; -static bfd_boolean parse_operands (char *, const aarch64_opcode *); -static bfd_boolean programmer_friendly_fixup (aarch64_instruction *); +static bool parse_operands (char *, const aarch64_opcode *); +static bool 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. @@ -170,7 +180,7 @@ clear_error (void) inst.parsing_error.error = NULL; } -static inline bfd_boolean +static inline bool error_p (void) { return inst.parsing_error.kind != AARCH64_OPDE_NIL; @@ -228,9 +238,6 @@ set_fatal_syntax_error (const char *error) 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. */ @@ -240,12 +247,6 @@ set_fatal_syntax_error (const char *error) present. */ #define COND_ALWAYS 0x10 -typedef struct -{ - const char *template; - unsigned long value; -} asm_barrier_opt; - typedef struct { const char *template; @@ -439,24 +440,26 @@ get_reg_expected_msg (aarch64_reg_type reg_type) /* Some well known registers that we refer to directly elsewhere. */ #define REG_SP 31 +#define REG_ZR 31 /* Instructions take 4 bytes in the object file. */ #define INSN_SIZE 4 -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; +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 +523,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) == '#') @@ -529,85 +532,99 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP"; #define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0) -static inline bfd_boolean +static inline bool skip_past_char (char **str, char c) { if (**str == c) { (*str)++; - return TRUE; + return true; } else - return FALSE; + return false; } #define skip_past_comma(str) skip_past_char (str, ',') /* Arithmetic expressions (possibly involving symbols). */ -static bfd_boolean in_my_get_expression_p = FALSE; +static bool in_aarch64_get_expression = false; + +/* Third argument to aarch64_get_expression. */ +#define GE_NO_PREFIX false +#define GE_OPT_PREFIX true + +/* Fourth argument to aarch64_get_expression. */ +#define ALLOW_ABSENT false +#define REJECT_ABSENT true -/* Third argument to my_get_expression. */ -#define GE_NO_PREFIX 0 -#define GE_OPT_PREFIX 1 +/* Fifth argument to aarch64_get_expression. */ +#define NORMAL_RESOLUTION false /* Return TRUE if the string pointed by *STR is successfully parsed as an valid expression; *EP will be filled with the information of - such an expression. Otherwise return FALSE. */ + such an expression. Otherwise return FALSE. -static bfd_boolean -my_get_expression (expressionS * ep, char **str, int prefix_mode, - int reject_absent) + If ALLOW_IMMEDIATE_PREFIX is true then skip a '#' at the start. + If REJECT_ABSENT is true then trat missing expressions as an error. + If DEFER_RESOLUTION is true, then do not resolve expressions against + constant symbols. Necessary if the expression is part of a fixup + that uses a reloc that must be emitted. */ + +static bool +aarch64_get_expression (expressionS * ep, + char ** str, + bool allow_immediate_prefix, + bool reject_absent, + bool defer_resolution) { char *save_in; segT seg; - int prefix_present_p = 0; + bool prefix_present = false; - switch (prefix_mode) + if (allow_immediate_prefix) { - case GE_NO_PREFIX: - break; - case GE_OPT_PREFIX: if (is_immediate_prefix (**str)) { (*str)++; - prefix_present_p = 1; + prefix_present = true; } - break; - default: - abort (); } memset (ep, 0, sizeof (expressionS)); save_in = input_line_pointer; input_line_pointer = *str; - in_my_get_expression_p = TRUE; - seg = expression (ep); - in_my_get_expression_p = FALSE; + in_aarch64_get_expression = true; + if (defer_resolution) + seg = deferred_expression (ep); + else + seg = expression (ep); + in_aarch64_get_expression = false; if (ep->X_op == O_illegal || (reject_absent && ep->X_op == O_absent)) { /* We found a bad expression in md_operand(). */ *str = input_line_pointer; input_line_pointer = save_in; - if (prefix_present_p && ! error_p ()) + if (prefix_present && ! error_p ()) set_fatal_syntax_error (_("bad expression")); else set_first_syntax_error (_("bad expression")); - return FALSE; + return false; } #ifdef OBJ_AOUT if (seg != absolute_section && seg != text_section && seg != data_section - && seg != bss_section && seg != undefined_section) + && seg != bss_section + && seg != undefined_section) { set_syntax_error (_("bad segment")); *str = input_line_pointer; input_line_pointer = save_in; - return FALSE; + return false; } #else (void) seg; @@ -615,7 +632,7 @@ my_get_expression (expressionS * ep, char **str, int prefix_mode, *str = input_line_pointer; input_line_pointer = save_in; - return TRUE; + return true; } /* Turn a string in input_line_pointer into a floating point constant @@ -626,6 +643,54 @@ my_get_expression (expressionS * ep, char **str, int prefix_mode, 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); } @@ -634,7 +699,7 @@ md_atof (int type, char *litP, int *sizeP) void md_operand (expressionS * exp) { - if (in_my_get_expression_p) + if (in_aarch64_get_expression) exp->X_op = O_illegal; } @@ -707,7 +772,7 @@ parse_reg (char **ccp) p++; while (ISALPHA (*p) || ISDIGIT (*p) || *p == '_'); - reg = (reg_entry *) hash_find_n (aarch64_reg_hsh, start, p - start); + reg = (reg_entry *) str_hash_find_n (aarch64_reg_hsh, start, p - start); if (!reg) return NULL; @@ -718,7 +783,7 @@ parse_reg (char **ccp) /* Return TRUE if REG->TYPE is a valid type of TYPE; otherwise return FALSE. */ -static bfd_boolean +static bool aarch64_check_reg_type (const reg_entry *reg, aarch64_reg_type type) { return (reg_type_masks[type] & (1 << reg->type)) != 0; @@ -801,7 +866,7 @@ aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier) Accept only one occurrence of: 4b 8b 16b 2h 4h 8h 2s 4s 1d 2d b h s d q */ -static bfd_boolean +static bool parse_vector_type_for_operand (aarch64_reg_type reg_type, struct vector_type_el *parsed_type, char **str) { @@ -823,10 +888,10 @@ parse_vector_type_for_operand (aarch64_reg_type reg_type, if (width != 1 && width != 2 && width != 4 && width != 8 && width != 16) { first_error_fmt (_("bad size %d in vector width specifier"), width); - return FALSE; + return false; } -elt_size: + elt_size: switch (TOLOWER (*ptr)) { case 'b': @@ -858,7 +923,7 @@ elt_size: first_error_fmt (_("unexpected character `%c' in element size"), *ptr); else first_error (_("missing element size")); - return FALSE; + return false; } if (width != 0 && width * element_size != 64 && width * element_size != 128 @@ -868,7 +933,7 @@ elt_size: first_error_fmt (_ ("invalid element size %d and vector size combination %c"), width, *ptr); - return FALSE; + return false; } ptr++; @@ -877,13 +942,13 @@ elt_size: *str = ptr; - return TRUE; + return true; } /* *STR contains an SVE zero/merge predication suffix. Parse it into *PARSED_TYPE and point *STR at the end of the suffix. */ -static bfd_boolean +static bool parse_predication_for_operand (struct vector_type_el *parsed_type, char **str) { char *ptr = *str; @@ -905,11 +970,11 @@ parse_predication_for_operand (struct vector_type_el *parsed_type, char **str) *ptr); else first_error (_("missing predication type")); - return FALSE; + return false; } parsed_type->width = 0; *str = ptr + 1; - return TRUE; + return true; } /* Parse a register of the type TYPE. @@ -926,13 +991,13 @@ parse_predication_for_operand (struct vector_type_el *parsed_type, char **str) static int parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype, - struct vector_type_el *typeinfo, bfd_boolean in_reg_list) + struct vector_type_el *typeinfo, bool in_reg_list) { char *str = *ccp; const reg_entry *reg = parse_reg (&str); struct vector_type_el atype; struct vector_type_el parsetype; - bfd_boolean is_typed_vecreg = FALSE; + bool is_typed_vecreg = false; atype.defined = 0; atype.type = NT_invtype; @@ -970,7 +1035,7 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype, } /* Register if of the form Vn.[bhsdq]. */ - is_typed_vecreg = TRUE; + is_typed_vecreg = true; if (type == REG_TYPE_ZN || type == REG_TYPE_PN) { @@ -1011,7 +1076,8 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype, atype.defined |= NTA_HASINDEX; - my_get_expression (&exp, &str, GE_NO_PREFIX, 1); + aarch64_get_expression (&exp, &str, GE_NO_PREFIX, REJECT_ABSENT, + NORMAL_RESOLUTION); if (exp.X_op != O_constant) { @@ -1067,7 +1133,7 @@ aarch64_reg_parse (char **ccp, aarch64_reg_type type, struct vector_type_el atype; char *str = *ccp; int reg = parse_typed_reg (&str, type, rtype, &atype, - /*in_reg_list= */ FALSE); + /*in_reg_list= */ false); if (reg == PARSE_FAIL) return PARSE_FAIL; @@ -1080,7 +1146,7 @@ aarch64_reg_parse (char **ccp, aarch64_reg_type type, return reg; } -static inline bfd_boolean +static inline bool eq_vector_type_el (struct vector_type_el e1, struct vector_type_el e2) { return @@ -1121,8 +1187,8 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type, int in_range; int ret_val; int i; - bfd_boolean error = FALSE; - bfd_boolean expect_index = FALSE; + bool error = false; + bool expect_index = false; if (*str != '{') { @@ -1148,23 +1214,23 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type, val_range = val; } val = parse_typed_reg (&str, type, NULL, &typeinfo, - /*in_reg_list= */ TRUE); + /*in_reg_list= */ true); if (val == PARSE_FAIL) { set_first_syntax_error (_("invalid vector register in list")); - error = TRUE; + error = true; continue; } /* reject [bhsd]n */ if (type == REG_TYPE_VN && typeinfo.defined == 0) { set_first_syntax_error (_("invalid scalar register in list")); - error = TRUE; + error = true; continue; } if (typeinfo.defined & NTA_HASINDEX) - expect_index = TRUE; + expect_index = true; if (in_range) { @@ -1172,7 +1238,7 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type, { set_first_syntax_error (_("invalid range in vector register list")); - error = TRUE; + error = true; } val_range++; } @@ -1185,7 +1251,7 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type, { set_first_syntax_error (_("type mismatch in vector register list")); - error = TRUE; + error = true; } } if (! error) @@ -1202,7 +1268,7 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type, if (*str != '}') { set_first_syntax_error (_("end of vector register list not found")); - error = TRUE; + error = true; } str++; @@ -1214,33 +1280,34 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type, { expressionS exp; - my_get_expression (&exp, &str, GE_NO_PREFIX, 1); + aarch64_get_expression (&exp, &str, GE_NO_PREFIX, REJECT_ABSENT, + NORMAL_RESOLUTION); if (exp.X_op != O_constant) { set_first_syntax_error (_("constant expression required.")); - error = TRUE; + error = true; } if (! skip_past_char (&str, ']')) - error = TRUE; + error = true; else typeinfo_first.index = exp.X_add_number; } else { set_first_syntax_error (_("expected index")); - error = TRUE; + error = true; } } if (nb_regs > 4) { set_first_syntax_error (_("too many registers in vector register list")); - error = TRUE; + error = true; } else if (nb_regs == 0) { set_first_syntax_error (_("empty vector register list")); - error = TRUE; + error = true; } *ccp = str; @@ -1258,7 +1325,7 @@ insert_reg_alias (char *str, int number, aarch64_reg_type type) reg_entry *new; const char *name; - if ((new = hash_find (aarch64_reg_hsh, str)) != 0) + if ((new = str_hash_find (aarch64_reg_hsh, str)) != 0) { if (new->builtin) as_warn (_("ignoring attempt to redefine built-in register '%s'"), @@ -1278,10 +1345,9 @@ insert_reg_alias (char *str, int number, aarch64_reg_type type) new->name = name; new->number = number; new->type = type; - new->builtin = FALSE; + new->builtin = false; - if (hash_insert (aarch64_reg_hsh, name, (void *) new)) - abort (); + str_hash_insert (aarch64_reg_hsh, name, new, 0); return new; } @@ -1293,7 +1359,7 @@ insert_reg_alias (char *str, int number, aarch64_reg_type type) If we find one, or if it looks sufficiently like one that we want to handle any error here, return TRUE. Otherwise return FALSE. */ -static bfd_boolean +static bool create_register_alias (char *newname, char *p) { const reg_entry *old; @@ -1303,18 +1369,18 @@ create_register_alias (char *newname, char *p) /* The input scrubber ensures that whitespace after the mnemonic is collapsed to single spaces. */ oldname = p; - if (strncmp (oldname, " .req ", 6) != 0) - return FALSE; + if (!startswith (oldname, " .req ")) + return false; oldname += 6; if (*oldname == '\0') - return FALSE; + return false; - old = hash_find (aarch64_reg_hsh, oldname); + old = str_hash_find (aarch64_reg_hsh, oldname); if (!old) { as_warn (_("unknown register '%s' -- .req ignored"), oldname); - return TRUE; + return true; } /* If TC_CASE_SENSITIVE is defined, then newname already points to @@ -1351,7 +1417,7 @@ create_register_alias (char *newname, char *p) if (insert_reg_alias (nbuf, old->number, old->type) == NULL) { free (nbuf); - return TRUE; + return true; } } @@ -1363,7 +1429,7 @@ create_register_alias (char *newname, char *p) } free (nbuf); - return TRUE; + return true; } /* Should never be called, as .req goes between the alias and the @@ -1399,7 +1465,7 @@ s_unreq (int a ATTRIBUTE_UNUSED) as_bad (_("invalid syntax for .unreq directive")); else { - reg_entry *reg = hash_find (aarch64_reg_hsh, name); + reg_entry *reg = str_hash_find (aarch64_reg_hsh, name); if (!reg) as_bad (_("unknown register alias '%s'"), name); @@ -1411,7 +1477,7 @@ s_unreq (int a ATTRIBUTE_UNUSED) char *p; char *nbuf; - hash_delete (aarch64_reg_hsh, name, FALSE); + str_hash_delete (aarch64_reg_hsh, name); free ((char *) reg->name); free (reg); @@ -1422,20 +1488,20 @@ s_unreq (int a ATTRIBUTE_UNUSED) nbuf = strdup (name); for (p = nbuf; *p; p++) *p = TOUPPER (*p); - reg = hash_find (aarch64_reg_hsh, nbuf); + reg = str_hash_find (aarch64_reg_hsh, nbuf); if (reg) { - hash_delete (aarch64_reg_hsh, nbuf, FALSE); + str_hash_delete (aarch64_reg_hsh, nbuf); free ((char *) reg->name); free (reg); } for (p = nbuf; *p; p++) *p = TOLOWER (*p); - reg = hash_find (aarch64_reg_hsh, nbuf); + reg = str_hash_find (aarch64_reg_hsh, nbuf); if (reg) { - hash_delete (aarch64_reg_hsh, nbuf, FALSE); + str_hash_delete (aarch64_reg_hsh, nbuf); free ((char *) reg->name); free (reg); } @@ -1479,7 +1545,7 @@ make_mapping_symbol (enum mstate state, valueT value, fragS * frag) abort (); } - symbolP = symbol_new (symname, now_seg, value, frag); + symbolP = symbol_new (symname, now_seg, frag, value); symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL; /* Save the mapping symbols for future reference. Also check that @@ -1686,7 +1752,7 @@ find_or_make_literal_pool (int size) if (pool->symbol == NULL) { pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section, - (valueT) 0, &zero_address_frag); + &zero_address_frag, 0); pool->id = latest_pool_num++; } @@ -1696,7 +1762,7 @@ find_or_make_literal_pool (int size) /* Add the literal of size SIZE in *EXP to the relevant literal pool. Return TRUE on success, otherwise return FALSE. */ -static bfd_boolean +static bool add_to_lit_pool (expressionS *exp, int size) { literal_pool *pool; @@ -1729,7 +1795,7 @@ add_to_lit_pool (expressionS *exp, int size) if (entry >= MAX_LITERAL_POOL_SIZE) { set_syntax_error (_("literal pool overflow")); - return FALSE; + return false; } pool->literals[entry].exp = *exp; @@ -1751,7 +1817,7 @@ add_to_lit_pool (expressionS *exp, int size) exp->X_add_number = ((int) entry) * size; exp->X_add_symbol = pool->symbol; - return TRUE; + return true; } /* Can't use symbol_new here, so have to create a symbol and then at @@ -1927,6 +1993,28 @@ s_aarch64_elf_cons (int nbytes) demand_empty_rest_of_line (); } +/* Mark symbol that it follows a variant PCS convention. */ + +static void +s_variant_pcs (int ignored ATTRIBUTE_UNUSED) +{ + char *name; + char c; + symbolS *sym; + asymbol *bfdsym; + elf_symbol_type *elfsym; + + c = get_symbol_name (&name); + if (!*name) + as_bad (_("Missing symbol name in directive")); + sym = symbol_find_or_make (name); + restore_line_pointer (c); + demand_empty_rest_of_line (); + bfdsym = symbol_get_bfdsym (sym); + elfsym = elf_symbol_from (bfdsym); + gas_assert (elfsym); + elfsym->internal_elf_sym.st_other |= STO_AARCH64_VARIANT_PCS; +} #endif /* OBJ_ELF */ /* Output a 32-bit word, but mark as an instruction. */ @@ -1982,6 +2070,14 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +static void +s_aarch64_cfi_b_key_frame (int ignored ATTRIBUTE_UNUSED) +{ + demand_empty_rest_of_line (); + struct fde_entry *fde = frchain_now->frch_cfi_data->cur_fde_data; + fde->pauth_key = AARCH64_PAUTH_KEY_B; +} + #ifdef OBJ_ELF /* Emit BFD_RELOC_AARCH64_TLSDESC_ADD on the next ADD instruction. */ @@ -2056,6 +2152,7 @@ const pseudo_typeS md_pseudo_table[] = { {"arch", s_aarch64_arch, 0}, {"arch_extension", s_aarch64_arch_extension, 0}, {"inst", s_aarch64_inst, 0}, + {"cfi_b_key_frame", s_aarch64_cfi_b_key_frame, 0}, #ifdef OBJ_ELF {"tlsdescadd", s_tlsdescadd, 0}, {"tlsdesccall", s_tlsdesccall, 0}, @@ -2064,7 +2161,10 @@ const pseudo_typeS md_pseudo_table[] = { {"long", s_aarch64_elf_cons, 4}, {"xword", s_aarch64_elf_cons, 8}, {"dword", s_aarch64_elf_cons, 8}, + {"variant_pcs", s_variant_pcs, 0}, #endif + {"float16", float_cons, 'h'}, + {"bfloat16", float_cons, 'b'}, {0, 0, 0} }; @@ -2081,14 +2181,14 @@ const pseudo_typeS md_pseudo_table[] = { state from being spoiled. The function currently serves parse_constant_immediate and parse_big_immediate only. */ -static bfd_boolean +static bool reg_name_p (char *str, aarch64_reg_type reg_type) { int reg; /* Prevent the diagnostics state from being spoiled. */ if (error_p ()) - return FALSE; + return false; reg = aarch64_reg_parse (&str, reg_type, NULL, NULL); @@ -2096,13 +2196,13 @@ reg_name_p (char *str, aarch64_reg_type reg_type) clear_error (); if (reg == PARSE_FAIL) - return FALSE; + return false; skip_whitespace (str); - if (*str == ',' || is_end_of_line[(unsigned int) *str]) - return TRUE; + if (*str == ',' || is_end_of_line[(unsigned char) *str]) + return true; - return FALSE; + return false; } /* Parser functions used exclusively in instruction operands. */ @@ -2114,25 +2214,26 @@ reg_name_p (char *str, aarch64_reg_type reg_type) done to find out whether STR is a register of type REG_TYPE followed by a comma or the end of line. Return FALSE if STR is such a string. */ -static bfd_boolean +static bool parse_immediate_expression (char **str, expressionS *exp, aarch64_reg_type reg_type) { if (reg_name_p (*str, reg_type)) { set_recoverable_error (_("immediate operand required")); - return FALSE; + return false; } - my_get_expression (exp, str, GE_OPT_PREFIX, 1); + aarch64_get_expression (exp, str, GE_OPT_PREFIX, REJECT_ABSENT, + NORMAL_RESOLUTION); if (exp->X_op == O_absent) { set_fatal_syntax_error (_("missing immediate expression")); - return FALSE; + return false; } - return TRUE; + return true; } /* Constant immediate-value read function for use in insn parsing. @@ -2142,22 +2243,22 @@ parse_immediate_expression (char **str, expressionS *exp, Return TRUE on success; otherwise return FALSE. */ -static bfd_boolean +static bool parse_constant_immediate (char **str, int64_t *val, aarch64_reg_type reg_type) { expressionS exp; if (! parse_immediate_expression (str, &exp, reg_type)) - return FALSE; + return false; if (exp.X_op != O_constant) { set_syntax_error (_("constant expression required")); - return FALSE; + return false; } *val = exp.X_add_number; - return TRUE; + return true; } static uint32_t @@ -2174,7 +2275,7 @@ encode_imm_float_bits (uint32_t imm) (+/-) n / 16 * power (2, r) where n and r are integers such that 16 <= n <=31 and -3 <= r <= 4. */ -static bfd_boolean +static bool aarch64_imm_float_p (uint32_t imm) { /* If a single-precision floating-point value has the following bit @@ -2204,7 +2305,7 @@ aarch64_imm_float_p (uint32_t imm) as an IEEE float without any loss of precision. Store the value in *FPWORD if so. */ -static bfd_boolean +static bool can_convert_double_to_float (uint64_t imm, uint32_t *fpword) { /* If a double-precision floating-point value has the following bit @@ -2226,7 +2327,7 @@ can_convert_double_to_float (uint64_t imm, uint32_t *fpword) /* Lower 29 bits need to be 0s. */ if ((imm & 0x1fffffff) != 0) - return FALSE; + return false; /* Prepare the pattern for 'Eeeeeeeee'. */ if (((high32 >> 30) & 0x1) == 0) @@ -2236,21 +2337,21 @@ can_convert_double_to_float (uint64_t imm, uint32_t *fpword) /* Check E~~~. */ if ((high32 & 0x78000000) != pattern) - return FALSE; + return false; /* Check Eeee_eeee != 1111_1111. */ if ((high32 & 0x7ff00000) == 0x47f00000) - return FALSE; + return false; *fpword = ((high32 & 0xc0000000) /* 1 n bit and 1 E bit. */ | ((high32 << 3) & 0x3ffffff8) /* 7 e and 20 s bits. */ | (low32 >> 29)); /* 3 S bits. */ - return TRUE; + return true; } /* Return true if we should treat OPERAND as a double-precision floating-point operand rather than a single-precision one. */ -static bfd_boolean +static bool double_precision_operand_p (const aarch64_opnd_info *operand) { /* Check for unsuffixed SVE registers, which are allowed @@ -2272,24 +2373,23 @@ double_precision_operand_p (const aarch64_opnd_info *operand) This routine accepts any IEEE float; it is up to the callers to reject invalid ones. */ -static bfd_boolean -parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p, +static bool +parse_aarch64_imm_float (char **ccp, int *immed, bool dp_p, aarch64_reg_type reg_type) { 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; + bool hex_p = false; skip_past_char (&str, '#'); fpnum = str; skip_whitespace (fpnum); - if (strncmp (fpnum, "0x", 2) == 0) + if (startswith (fpnum, "0x")) { /* Support the hexadecimal representation of the IEEE754 encoding. Double-precision is expected when DP_P is TRUE, otherwise the @@ -2307,28 +2407,12 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p, else fpword = val; - hex_p = TRUE; + 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) @@ -2348,11 +2432,11 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p, *immed = fpword; *ccp = str; - return TRUE; + return true; -invalid_fp: + invalid_fp: set_fatal_syntax_error (_("invalid floating-point constant")); - return FALSE; + return false; } /* Less-generic immediate-value read function with the possibility of loading @@ -2364,7 +2448,7 @@ invalid_fp: out whether STR is a register of type REG_TYPE followed by a comma or the end of line. Return FALSE if STR is such a register. */ -static bfd_boolean +static bool parse_big_immediate (char **str, int64_t *imm, aarch64_reg_type reg_type) { char *ptr = *str; @@ -2372,17 +2456,18 @@ parse_big_immediate (char **str, int64_t *imm, aarch64_reg_type reg_type) if (reg_name_p (ptr, reg_type)) { set_syntax_error (_("immediate operand required")); - return FALSE; + return false; } - my_get_expression (&inst.reloc.exp, &ptr, GE_OPT_PREFIX, 1); + aarch64_get_expression (&inst.reloc.exp, &ptr, GE_OPT_PREFIX, REJECT_ABSENT, + NORMAL_RESOLUTION); if (inst.reloc.exp.X_op == O_constant) *imm = inst.reloc.exp.X_add_number; *str = ptr; - return TRUE; + return true; } /* Set operand IDX of the *INSTR that needs a GAS internal fixup. @@ -2403,7 +2488,7 @@ aarch64_set_gas_internal_fixup (struct reloc *reloc, /* Return TRUE if the instruction needs to be fixed up later internally by the GAS; otherwise return FALSE. */ -static inline bfd_boolean +static inline bool aarch64_gas_internal_fixup_p (void) { return inst.reloc.type == BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP; @@ -2459,7 +2544,8 @@ struct reloc_table_entry bfd_reloc_code_real_type ld_literal_type; }; -static struct reloc_table_entry reloc_table[] = { +static struct reloc_table_entry reloc_table[] = +{ /* Low 12 bits of absolute address: ADD/i and LDR/STR */ {"lo12", 0, 0, /* adr_type */ @@ -2902,7 +2988,7 @@ static struct reloc_table_entry reloc_table[] = { 0, 0, BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12, - 0, + BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12, 0}, /* Get tp offset for a symbol. */ @@ -2920,7 +3006,7 @@ static struct reloc_table_entry reloc_table[] = { 0, 0, BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC, - 0, + BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC, 0}, /* Most significant bits 32-47 of address/value: MOVZ. */ @@ -3012,6 +3098,114 @@ find_reloc_table_entry (char **str) return NULL; } +/* Returns 0 if the relocation should never be forced, + 1 if the relocation must be forced, and -1 if either + result is OK. */ + +static signed int +aarch64_force_reloc (unsigned int type) +{ + switch (type) + { + case BFD_RELOC_AARCH64_GAS_INTERNAL_FIXUP: + /* Perform these "immediate" internal relocations + even if the symbol is extern or weak. */ + return 0; + + 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: + 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: + case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: + case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: + case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: + 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_TLSGD_MOVW_G0_NC: + case BFD_RELOC_AARCH64_TLSGD_MOVW_G1: + 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_TLSIE_LD_GOTTPREL_PREL19: + case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: + case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: + case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12: + 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_TLSLD_LDST16_DTPREL_LO12: + case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12: + case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12: + case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12: + case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0: + case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: + case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: + case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: + case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: + case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12: + case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12: + case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12: + case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12: + case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: + case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: + case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + 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: + /* Always leave these relocations for the linker. */ + return 1; + + default: + return -1; + } +} + +int +aarch64_force_relocation (struct fix *fixp) +{ + int res = aarch64_force_reloc (fixp->fx_r_type); + + if (res == -1) + return generic_force_reloc (fixp); + return res; +} + /* Mode argument to parse_shift and parser_shifter_operand. */ enum parse_shift_mode { @@ -3029,7 +3223,7 @@ enum parse_shift_mode /* Parse a operator on an AArch64 data processing instruction. Return TRUE on success; otherwise return FALSE. */ -static bfd_boolean +static bool parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) { const struct aarch64_name_value_pair *shift_op; @@ -3045,15 +3239,15 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (p == *str) { set_syntax_error (_("shift expression expected")); - return FALSE; + return false; } - shift_op = hash_find_n (aarch64_shift_hsh, *str, p - *str); + shift_op = str_hash_find_n (aarch64_shift_hsh, *str, p - *str); if (shift_op == NULL) { set_syntax_error (_("shift operator expected")); - return FALSE; + return false; } kind = aarch64_get_operand_modifier (shift_op); @@ -3061,7 +3255,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (kind == AARCH64_MOD_MSL && mode != SHIFTED_LSL_MSL) { set_syntax_error (_("invalid use of 'MSL'")); - return FALSE; + return false; } if (kind == AARCH64_MOD_MUL @@ -3069,7 +3263,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) && mode != SHIFTED_MUL_VL) { set_syntax_error (_("invalid use of 'MUL'")); - return FALSE; + return false; } switch (mode) @@ -3078,7 +3272,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (aarch64_extend_operator_p (kind)) { set_syntax_error (_("extending shift is not permitted")); - return FALSE; + return false; } break; @@ -3086,7 +3280,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (kind == AARCH64_MOD_ROR) { set_syntax_error (_("'ROR' shift is not permitted")); - return FALSE; + return false; } break; @@ -3094,7 +3288,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (kind != AARCH64_MOD_LSL) { set_syntax_error (_("only 'LSL' shift is permitted")); - return FALSE; + return false; } break; @@ -3102,7 +3296,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (kind != AARCH64_MOD_MUL) { set_syntax_error (_("only 'MUL' is permitted")); - return FALSE; + return false; } break; @@ -3120,7 +3314,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) } } set_syntax_error (_("only 'MUL VL' is permitted")); - return FALSE; + return false; case SHIFTED_REG_OFFSET: if (kind != AARCH64_MOD_UXTW && kind != AARCH64_MOD_LSL @@ -3128,7 +3322,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) { set_fatal_syntax_error (_("invalid shift for the register offset addressing mode")); - return FALSE; + return false; } break; @@ -3136,7 +3330,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (kind != AARCH64_MOD_LSL && kind != AARCH64_MOD_MSL) { set_syntax_error (_("invalid shift operator")); - return FALSE; + return false; } break; @@ -3158,7 +3352,8 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) p++; exp_has_prefix = 1; } - my_get_expression (&exp, &p, GE_NO_PREFIX, 0); + (void) aarch64_get_expression (&exp, &p, GE_NO_PREFIX, ALLOW_ABSENT, + NORMAL_RESOLUTION); } if (kind == AARCH64_MOD_MUL_VL) /* For consistency, give MUL VL the same shift amount as an implicit @@ -3169,14 +3364,14 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) if (!aarch64_extend_operator_p (kind) || exp_has_prefix) { set_syntax_error (_("missing shift amount")); - return FALSE; + return false; } operand->shifter.amount = 0; } else if (exp.X_op != O_constant) { set_syntax_error (_("constant shift amount required")); - return FALSE; + return false; } /* For parsing purposes, MUL #n has no inherent range. The range depends on the operand and will be checked by operand-specific @@ -3185,7 +3380,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) && (exp.X_add_number < 0 || exp.X_add_number > 63)) { set_fatal_syntax_error (_("shift amount out of range 0 to 63")); - return FALSE; + return false; } else { @@ -3197,7 +3392,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) operand->shifter.kind = kind; *str = p; - return TRUE; + return true; } /* Parse a for a data processing instruction: @@ -3209,36 +3404,37 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) Return TRUE on success; otherwise return FALSE. */ -static bfd_boolean +static bool parse_shifter_operand_imm (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) { char *p; if (mode != SHIFTED_ARITH_IMM && mode != SHIFTED_LOGIC_IMM) - return FALSE; + return false; p = *str; /* Accept an immediate expression. */ - if (! my_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX, 1)) - return FALSE; + if (! aarch64_get_expression (&inst.reloc.exp, &p, GE_OPT_PREFIX, + REJECT_ABSENT, NORMAL_RESOLUTION)) + return false; /* Accept optional LSL for arithmetic immediate values. */ if (mode == SHIFTED_ARITH_IMM && skip_past_comma (&p)) if (! parse_shift (&p, operand, SHIFTED_LSL)) - return FALSE; + return false; /* Not accept any shifter for logical immediate values. */ if (mode == SHIFTED_LOGIC_IMM && skip_past_comma (&p) && parse_shift (&p, operand, mode)) { set_syntax_error (_("unexpected shift operator")); - return FALSE; + return false; } *str = p; - return TRUE; + return true; } /* Parse a for a data processing instruction: @@ -3255,7 +3451,7 @@ parse_shifter_operand_imm (char **str, aarch64_opnd_info *operand, Return TRUE on success; otherwise return FALSE. */ -static bfd_boolean +static bool parse_shifter_operand (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) { @@ -3270,13 +3466,13 @@ parse_shifter_operand (char **str, aarch64_opnd_info *operand, if (opd_class == AARCH64_OPND_CLASS_IMMEDIATE) { set_syntax_error (_("unexpected register in the immediate operand")); - return FALSE; + return false; } if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z)) { set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z))); - return FALSE; + return false; } operand->reg.regno = reg->number; @@ -3284,19 +3480,19 @@ parse_shifter_operand (char **str, aarch64_opnd_info *operand, /* Accept optional shift operation on register. */ if (! skip_past_comma (str)) - return TRUE; + return true; if (! parse_shift (str, operand, mode)) - return FALSE; + return false; - return TRUE; + return true; } else if (opd_class == AARCH64_OPND_CLASS_MODIFIED_REG) { set_syntax_error (_("integer register expected in the extended/shifted operand " "register")); - return FALSE; + return false; } /* We have a shifted immediate variable. */ @@ -3305,7 +3501,7 @@ parse_shifter_operand (char **str, aarch64_opnd_info *operand, /* Return TRUE on success; return FALSE otherwise. */ -static bfd_boolean +static bool parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) { @@ -3330,30 +3526,32 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, if (!(entry = find_reloc_table_entry (str))) { set_syntax_error (_("unknown relocation modifier")); - return FALSE; + return false; } if (entry->add_type == 0) { set_syntax_error (_("this relocation modifier is not allowed on this instruction")); - return FALSE; + return false; } /* Save str before we decompose it. */ p = *str; /* Next, we parse the expression. */ - if (! my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX, 1)) - return FALSE; - + if (! aarch64_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX, + REJECT_ABSENT, + aarch64_force_reloc (entry->add_type) == 1)) + return false; + /* Record the relocation type (use the ADD variant here). */ inst.reloc.type = entry->add_type; inst.reloc.pc_rel = entry->pc_rel; /* If str is empty, we've reached the end, stop here. */ if (**str == '\0') - return TRUE; + return true; /* Otherwise, we have a shifted reloc modifier, so rewind to recover the variable name and continue parsing for the shifter. */ @@ -3377,6 +3575,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, [base,Xm,SXTX {#imm}] [base,Wm,(S|U)XTW {#imm}] Pre-indexed + [base]! // in ldraa/ldrab exclusive [base,#imm]! Post-indexed [base],#imm @@ -3390,6 +3589,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, [base,Zm.D,(S|U)XTW {#imm}] // ignores top 32 bits of Zm.D elements [Zn.S,#imm] [Zn.D,#imm] + [Zn.S{, Xm}] [Zn.S,Zm.S{,LSL #imm}] // in ADR [Zn.D,Zm.D{,LSL #imm}] // in ADR [Zn.D,Zm.D,(S|U)XTW {#imm}] // in ADR @@ -3432,7 +3632,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, for addressing modes not supported by the instruction, and to set inst.reloc.type. */ -static bfd_boolean +static bool parse_address_main (char **str, aarch64_opnd_info *operand, aarch64_opnd_qualifier_t *base_qualifier, aarch64_opnd_qualifier_t *offset_qualifier, @@ -3464,7 +3664,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (! entry) { set_syntax_error (_("unknown relocation modifier")); - return FALSE; + return false; } switch (operand->type) @@ -3484,16 +3684,16 @@ parse_address_main (char **str, aarch64_opnd_info *operand, set_syntax_error (_("this relocation modifier is not allowed on this " "instruction")); - return FALSE; + return false; } /* #:: */ - if (! my_get_expression (exp, &p, GE_NO_PREFIX, 1)) + if (! aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT, + aarch64_force_reloc (entry->add_type) == 1)) { set_syntax_error (_("invalid relocation expression")); - return FALSE; + return false; } - /* #:: */ /* Record the relocation type. */ inst.reloc.type = ty; @@ -3501,20 +3701,20 @@ parse_address_main (char **str, aarch64_opnd_info *operand, } else { - if (skip_past_char (&p, '=')) /* =immediate; need to generate the literal in the literal pool. */ inst.gen_lit_pool = 1; - if (!my_get_expression (exp, &p, GE_NO_PREFIX, 1)) + if (!aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT, + NORMAL_RESOLUTION)) { set_syntax_error (_("invalid address")); - return FALSE; + return false; } } *str = p; - return TRUE; + return true; } /* [ */ @@ -3523,7 +3723,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (!reg || !aarch64_check_reg_type (reg, base_type)) { set_syntax_error (_(get_reg_expected_msg (base_type))); - return FALSE; + return false; } operand->addr.base_regno = reg->number; @@ -3539,7 +3739,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (!aarch64_check_reg_type (reg, offset_type)) { set_syntax_error (_(get_reg_expected_msg (offset_type))); - return FALSE; + return false; } /* [Xn,Rm */ @@ -3552,9 +3752,10 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (! parse_shift (&p, operand, SHIFTED_REG_OFFSET)) /* Use the diagnostics set in parse_shift, so not set new error message here. */ - return FALSE; + 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}] */ @@ -3565,19 +3766,22 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (*offset_qualifier == AARCH64_OPND_QLF_W) { set_syntax_error (_("invalid use of 32-bit register offset")); - return FALSE; + 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; + return false; } } else if (*offset_qualifier == AARCH64_OPND_QLF_X) { set_syntax_error (_("invalid use of 64-bit register offset")); - return FALSE; + return false; } } else @@ -3593,7 +3797,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (!(entry = find_reloc_table_entry (&p))) { set_syntax_error (_("unknown relocation modifier")); - return FALSE; + return false; } if (entry->ldst_type == 0) @@ -3601,17 +3805,18 @@ parse_address_main (char **str, aarch64_opnd_info *operand, set_syntax_error (_("this relocation modifier is not allowed on this " "instruction")); - return FALSE; + return false; } /* [Xn,#:: */ /* We now have the group relocation table entry corresponding to the name in the assembler source. Next, we parse the expression. */ - if (! my_get_expression (exp, &p, GE_NO_PREFIX, 1)) + if (! aarch64_get_expression (exp, &p, GE_NO_PREFIX, REJECT_ABSENT, + aarch64_force_reloc (entry->add_type) == 1)) { set_syntax_error (_("invalid relocation expression")); - return FALSE; + return false; } /* [Xn,#:: */ @@ -3621,16 +3826,17 @@ parse_address_main (char **str, aarch64_opnd_info *operand, } else { - if (! my_get_expression (exp, &p, GE_OPT_PREFIX, 1)) + if (! aarch64_get_expression (exp, &p, GE_OPT_PREFIX, REJECT_ABSENT, + NORMAL_RESOLUTION)) { set_syntax_error (_("invalid expression in the address")); - return FALSE; + return false; } /* [Xn, */ if (imm_shift_mode != SHIFTED_NONE && skip_past_comma (&p)) /* [Xn,, */ if (! parse_shift (&p, operand, imm_shift_mode)) - return FALSE; + return false; } } } @@ -3638,7 +3844,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (! skip_past_char (&p, ']')) { set_syntax_error (_("']' expected")); - return FALSE; + return false; } if (skip_past_char (&p, '!')) @@ -3647,7 +3853,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, { set_syntax_error (_("register offset not allowed in pre-indexed " "addressing mode")); - return FALSE; + return false; } /* [Xn]! */ operand->addr.writeback = 1; @@ -3661,7 +3867,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (operand->addr.preind) { set_syntax_error (_("cannot combine pre- and post-indexing")); - return FALSE; + return false; } reg = aarch64_reg_parse_32_64 (&p, offset_qualifier); @@ -3671,43 +3877,68 @@ parse_address_main (char **str, aarch64_opnd_info *operand, if (!aarch64_check_reg_type (reg, REG_TYPE_R_64)) { set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_64))); - return FALSE; + return false; } operand->addr.offset.regno = reg->number; operand->addr.offset.is_reg = 1; } - else if (! my_get_expression (exp, &p, GE_OPT_PREFIX, 1)) + else if (! aarch64_get_expression (exp, &p, GE_OPT_PREFIX, REJECT_ABSENT, + NORMAL_RESOLUTION)) { /* [Xn],#expr */ set_syntax_error (_("invalid expression in the address")); - return FALSE; + return false; } } /* 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; - return TRUE; + return true; } /* Parse a base AArch64 address (as opposed to an SVE one). Return TRUE on success. */ -static bfd_boolean +static bool parse_address (char **str, aarch64_opnd_info *operand) { aarch64_opnd_qualifier_t base_qualifier, offset_qualifier; @@ -3718,7 +3949,7 @@ parse_address (char **str, aarch64_opnd_info *operand) /* Parse an address in which SVE vector registers and MUL VL are allowed. The arguments have the same meaning as for parse_address_main. Return TRUE on success. */ -static bfd_boolean +static bool parse_sve_address (char **str, aarch64_opnd_info *operand, aarch64_opnd_qualifier_t *base_qualifier, aarch64_opnd_qualifier_t *offset_qualifier) @@ -3730,7 +3961,7 @@ parse_sve_address (char **str, aarch64_opnd_info *operand, /* Parse an operand for a MOVZ, MOVN or MOVK instruction. Return TRUE on success; otherwise return FALSE. */ -static bfd_boolean +static bool parse_half (char **str, int *internal_fixup_p) { char *p = *str; @@ -3746,17 +3977,18 @@ parse_half (char **str, int *internal_fixup_p) /* Try to parse a relocation. Anything else is an error. */ ++p; + if (!(entry = find_reloc_table_entry (&p))) { set_syntax_error (_("unknown relocation modifier")); - return FALSE; + return false; } if (entry->movw_type == 0) { set_syntax_error (_("this relocation modifier is not allowed on this instruction")); - return FALSE; + return false; } inst.reloc.type = entry->movw_type; @@ -3764,18 +3996,19 @@ parse_half (char **str, int *internal_fixup_p) else *internal_fixup_p = 1; - if (! my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX, 1)) - return FALSE; + if (! aarch64_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX, REJECT_ABSENT, + aarch64_force_reloc (inst.reloc.type) == 1)) + return false; *str = p; - return TRUE; + return true; } /* Parse an operand for an ADRP instruction: ADRP ,