X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-aarch64.c;h=c9040a08ad83a01bbe3d2c7febc41b45c91a8abd;hb=e54ae97fb7672350fc2bf28663cacf7721d9e30b;hp=cd4601682beb4e03a943029a50c60fe8546680ba;hpb=2dc4b12fcd647b883223efeb308c277e629b369c;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index cd4601682b..c9040a08ad 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-2019 Free Software Foundation, Inc. + Copyright (C) 2009-2020 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of GAS. @@ -247,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; @@ -451,21 +445,21 @@ get_reg_expected_msg (aarch64_reg_type reg_type) /* 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_sys_regs_sr_hsh; -static struct hash_control *aarch64_reg_hsh; -static struct hash_control *aarch64_barrier_opt_hsh; -static struct hash_control *aarch64_nzcv_hsh; -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: @@ -764,7 +758,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; @@ -883,7 +877,7 @@ parse_vector_type_for_operand (aarch64_reg_type reg_type, return FALSE; } -elt_size: + elt_size: switch (TOLOWER (*ptr)) { case 'b': @@ -1315,7 +1309,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'"), @@ -1337,8 +1331,7 @@ insert_reg_alias (char *str, int number, aarch64_reg_type type) new->type = type; new->builtin = FALSE; - if (hash_insert (aarch64_reg_hsh, name, (void *) new)) - abort (); + str_hash_insert (aarch64_reg_hsh, name, new, 0); return new; } @@ -1367,7 +1360,7 @@ create_register_alias (char *newname, char *p) if (*oldname == '\0') 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); @@ -1456,7 +1449,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); @@ -1468,7 +1461,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); @@ -1479,20 +1472,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); } @@ -1536,7 +1529,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 @@ -1743,7 +1736,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++; } @@ -2002,7 +1995,7 @@ s_variant_pcs (int ignored ATTRIBUTE_UNUSED) 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 (bfdsym); gas_assert (elfsym); elfsym->internal_elf_sym.st_other |= STO_AARCH64_VARIANT_PCS; } @@ -2190,7 +2183,7 @@ reg_name_p (char *str, aarch64_reg_type 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; @@ -2424,7 +2417,7 @@ parse_aarch64_imm_float (char **ccp, int *immed, bfd_boolean dp_p, *ccp = str; return TRUE; -invalid_fp: + invalid_fp: set_fatal_syntax_error (_("invalid floating-point constant")); return FALSE; } @@ -3122,7 +3115,7 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode) 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) { @@ -3979,7 +3972,7 @@ parse_pldop (char **str) while (ISALNUM (*q)) q++; - o = hash_find_n (aarch64_pldop_hsh, p, q - p); + o = str_hash_find_n (aarch64_pldop_hsh, p, q - p); if (!o) return PARSE_FAIL; @@ -3994,13 +3987,13 @@ 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)) q++; - o = hash_find_n (aarch64_barrier_opt_hsh, p, q - p); + o = str_hash_find_n (aarch64_barrier_opt_hsh, p, q - p); if (!o) return PARSE_FAIL; @@ -4022,11 +4015,11 @@ parse_barrier_psb (char **str, while (ISALPHA (*q)) q++; - o = hash_find_n (aarch64_hint_opt_hsh, p, q - p); + o = str_hash_find_n (aarch64_hint_opt_hsh, p, q - p); if (!o) { set_fatal_syntax_error - ( _("unknown or missing option to PSB")); + ( _("unknown or missing option to PSB/TSB")); return PARSE_FAIL; } @@ -4034,7 +4027,7 @@ 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; } @@ -4043,6 +4036,29 @@ parse_barrier_psb (char **str, return 0; } +/* Parse an operand for CSR (CSRE instruction). */ + +static int +parse_csr_operand (char **str) +{ + char *p, *q; + + p = q = *str; + while (ISALPHA (*q)) + q++; + + /* Instruction has only one operand PDEC which encodes Rt field of the + operation to 0b11111. */ + if (strcasecmp(p, "pdec")) + { + set_syntax_error (_("CSR instruction accepts only PDEC")); + return PARSE_FAIL; + } + + *str = q; + return 0; +} + /* Parse an operand for BTI. Set *HINT_OPT to the hint-option record return 0 if successful. Otherwise return PARSE_FAIL. */ @@ -4057,7 +4073,7 @@ parse_bti_operand (char **str, while (ISALPHA (*q)) q++; - o = hash_find_n (aarch64_hint_opt_hsh, p, q - p); + o = str_hash_find_n (aarch64_hint_opt_hsh, p, q - p); if (!o) { set_fatal_syntax_error @@ -4095,24 +4111,28 @@ parse_bti_operand (char **str, */ static int -parse_sys_reg (char **str, struct hash_control *sys_regs, +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); - o = hash_find (sys_regs, buf); + /* 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 = str_hash_find (sys_regs, buf); if (!o) { if (!imple_defined_p) @@ -4137,10 +4157,12 @@ parse_sys_reg (char **str, struct hash_control *sys_regs, 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; @@ -4156,25 +4178,35 @@ parse_sys_reg (char **str, struct hash_control *sys_regs, 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'; - o = hash_find (sys_ins_regs, buf); + /* 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 = str_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; @@ -4328,7 +4360,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; @@ -4698,7 +4733,7 @@ print_operands (char *buf, const aarch64_opcode *opcode, /* Generate the operand string in STR. */ aarch64_print_operand (str, sizeof (str), 0, opcode, opnds, i, NULL, NULL, - NULL); + NULL, cpu_variant); /* Delimiter. */ if (str[0] != '\0') @@ -5024,7 +5059,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; } @@ -5077,7 +5113,7 @@ lookup_mnemonic (const char *start, int len) { templates *templ = NULL; - templ = hash_find_n (aarch64_ops_hsh, start, len); + templ = str_hash_find_n (aarch64_ops_hsh, start, len); return templ; } @@ -5108,7 +5144,7 @@ opcode_lookup (char **str) /* Handle a possible condition. */ if (dot) { - cond = hash_find_n (aarch64_cond_hsh, dot + 1, end - dot - 1); + cond = str_hash_find_n (aarch64_cond_hsh, dot + 1, end - dot - 1); if (cond) { inst.cond = cond->value; @@ -5215,7 +5251,7 @@ vectype_to_qualifier (const struct vector_type_el *vectype) return offset; } -vectype_conversion_fail: + vectype_conversion_fail: first_error (_("bad vector arrangement type")); return AARCH64_OPND_QLF_NIL; } @@ -5240,6 +5276,7 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode, case AARCH64_OPND_Rm: case AARCH64_OPND_Rt: case AARCH64_OPND_Rt2: + case AARCH64_OPND_Rt_LS64: case AARCH64_OPND_Rt_SP: case AARCH64_OPND_Rs: case AARCH64_OPND_Ra: @@ -5609,10 +5646,26 @@ parse_operands (char *str, const aarch64_opcode *opcode) 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: @@ -6148,6 +6201,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) 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, @@ -6158,7 +6212,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) case AARCH64_OPND_NZCV: { - const asm_nzcv *nzcv = hash_find_n (aarch64_nzcv_hsh, str, 4); + const asm_nzcv *nzcv = str_hash_find_n (aarch64_nzcv_hsh, str, 4); if (nzcv != NULL) { str += 4; @@ -6177,7 +6231,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) do str++; while (ISALPHA (*str)); - info->cond = hash_find_n (aarch64_cond_hsh, start, str - start); + info->cond = str_hash_find_n (aarch64_cond_hsh, start, str - start); if (info->cond == NULL) { set_syntax_error (_("invalid condition")); @@ -6651,7 +6705,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) 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")); @@ -6672,12 +6726,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