X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-aarch64.c;h=fb1ec0bcc31116cb320fe2530bdc74995b0bf7dc;hb=8ae2d3d9eabfd3dff6a540e7789e368e8d75fbce;hp=31985963e314cbe772afbd190d4b0ca6e9608466;hpb=ee9439704485a1e9413470fe2634b164fa31644f;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 31985963e3..fb1ec0bcc3 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-2019 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of GAS. @@ -55,6 +55,9 @@ static const aarch64_feature_set *march_cpu_opt = NULL; /* Constants for known architecture features. */ static const aarch64_feature_set cpu_default = CPU_DEFAULT; +/* Currently active instruction sequence. */ +static aarch64_instr_sequence *insn_sequence = NULL; + #ifdef OBJ_ELF /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ static symbolS *GOT_symbol; @@ -146,6 +149,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 +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. */ @@ -439,6 +446,7 @@ get_reg_expected_msg (aarch64_reg_type reg_type) /* Some well known registers that we refer to directly elsewhere. */ #define REG_SP 31 +#define REG_ZR 31 /* Instructions take 4 bytes in the object file. */ #define INSN_SIZE 4 @@ -452,6 +460,7 @@ static struct hash_control *aarch64_sys_regs_ic_hsh; static struct hash_control *aarch64_sys_regs_dc_hsh; static struct hash_control *aarch64_sys_regs_at_hsh; static struct hash_control *aarch64_sys_regs_tlbi_hsh; +static struct hash_control *aarch64_sys_regs_sr_hsh; static struct hash_control *aarch64_reg_hsh; static struct hash_control *aarch64_barrier_opt_hsh; static struct hash_control *aarch64_nzcv_hsh; @@ -520,7 +529,7 @@ const char EXP_CHARS[] = "eE"; /* As in 0f12.456 */ /* or 0d1.2345e12 */ -const char FLT_CHARS[] = "rRsSfFdDxXeEpP"; +const char FLT_CHARS[] = "rRsSfFdDxXeEpPhH"; /* Prefix character that indicates the start of an immediate value. */ #define is_immediate_prefix(C) ((C) == '#') @@ -1927,6 +1936,28 @@ s_aarch64_elf_cons (int nbytes) demand_empty_rest_of_line (); } +/* Mark symbol that it follows a variant PCS convention. */ + +static void +s_variant_pcs (int ignored ATTRIBUTE_UNUSED) +{ + char *name; + char c; + symbolS *sym; + asymbol *bfdsym; + elf_symbol_type *elfsym; + + c = get_symbol_name (&name); + if (!*name) + as_bad (_("Missing symbol name in directive")); + sym = symbol_find_or_make (name); + restore_line_pointer (c); + demand_empty_rest_of_line (); + bfdsym = symbol_get_bfdsym (sym); + elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); + gas_assert (elfsym); + elfsym->internal_elf_sym.st_other |= STO_AARCH64_VARIANT_PCS; +} #endif /* OBJ_ELF */ /* Output a 32-bit word, but mark as an instruction. */ @@ -1982,6 +2013,14 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +static void +s_aarch64_cfi_b_key_frame (int ignored ATTRIBUTE_UNUSED) +{ + demand_empty_rest_of_line (); + struct fde_entry *fde = frchain_now->frch_cfi_data->cur_fde_data; + fde->pauth_key = AARCH64_PAUTH_KEY_B; +} + #ifdef OBJ_ELF /* Emit BFD_RELOC_AARCH64_TLSDESC_ADD on the next ADD instruction. */ @@ -2056,6 +2095,7 @@ const pseudo_typeS md_pseudo_table[] = { {"arch", s_aarch64_arch, 0}, {"arch_extension", s_aarch64_arch_extension, 0}, {"inst", s_aarch64_inst, 0}, + {"cfi_b_key_frame", s_aarch64_cfi_b_key_frame, 0}, #ifdef OBJ_ELF {"tlsdescadd", s_tlsdescadd, 0}, {"tlsdesccall", s_tlsdesccall, 0}, @@ -2064,7 +2104,9 @@ const pseudo_typeS md_pseudo_table[] = { {"long", s_aarch64_elf_cons, 4}, {"xword", s_aarch64_elf_cons, 8}, {"dword", s_aarch64_elf_cons, 8}, + {"variant_pcs", s_variant_pcs, 0}, #endif + {"float16", float_cons, 'h'}, {0, 0, 0} }; @@ -3360,6 +3402,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, [base,Xm,SXTX {#imm}] [base,Wm,(S|U)XTW {#imm}] Pre-indexed + [base]! // in ldraa/ldrab exclusive [base,#imm]! Post-indexed [base],#imm @@ -3373,6 +3416,7 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, [base,Zm.D,(S|U)XTW {#imm}] // ignores top 32 bits of Zm.D elements [Zn.S,#imm] [Zn.D,#imm] + [Zn.S{, Xm}] [Zn.S,Zm.S{,LSL #imm}] // in ADR [Zn.D,Zm.D{,LSL #imm}] // in ADR [Zn.D,Zm.D,(S|U)XTW {#imm}] // in ADR @@ -3538,6 +3582,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand, return FALSE; } /* We only accept: + [base,Xm] # For vector plus scalar SVE2 indexing. [base,Xm{,LSL #imm}] [base,Xm,SXTX {#imm}] [base,Wm,(S|U)XTW {#imm}] */ @@ -3551,7 +3596,10 @@ parse_address_main (char **str, aarch64_opnd_info *operand, return FALSE; } if (aarch64_get_qualifier_esize (*base_qualifier) - != aarch64_get_qualifier_esize (*offset_qualifier)) + != aarch64_get_qualifier_esize (*offset_qualifier) + && (operand->type != AARCH64_OPND_SVE_ADDR_ZX + || *base_qualifier != AARCH64_OPND_QLF_S_S + || *offset_qualifier != AARCH64_OPND_QLF_X)) { set_syntax_error (_("offset has different size from base")); return FALSE; @@ -3669,19 +3717,43 @@ parse_address_main (char **str, aarch64_opnd_info *operand, } /* If at this point neither .preind nor .postind is set, we have a - bare [Rn]{!}; reject [Rn]! but accept [Rn] as a shorthand for [Rn,#0]. */ + bare [Rn]{!}; only accept [Rn]! as a shorthand for [Rn,#0]! for ldraa and + ldrab, accept [Rn] as a shorthand for [Rn,#0]. + For SVE2 vector plus scalar offsets, allow [Zn.] 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; @@ -3922,6 +3994,47 @@ parse_barrier_psb (char **str, return 0; } +/* Parse an operand for BTI. Set *HINT_OPT to the hint-option record + return 0 if successful. Otherwise return PARSE_FAIL. */ + +static int +parse_bti_operand (char **str, + const struct aarch64_name_value_pair ** hint_opt) +{ + char *p, *q; + const struct aarch64_name_value_pair *o; + + p = q = *str; + while (ISALPHA (*q)) + q++; + + o = hash_find_n (aarch64_hint_opt_hsh, p, q - p); + if (!o) + { + set_fatal_syntax_error + ( _("unknown option to BTI")); + return PARSE_FAIL; + } + + switch (o->value) + { + /* Valid BTI operands. */ + case HINT_OPD_C: + case HINT_OPD_J: + case HINT_OPD_JC: + break; + + default: + set_syntax_error + (_("unknown option to BTI")); + return PARSE_FAIL; + } + + *str = q; + *hint_opt = o; + return 0; +} + /* Parse a system register or a PSTATE field name for an MSR/MRS instruction. Returns the encoding for the option, or PARSE_FAIL. @@ -4661,7 +4774,7 @@ output_operand_error_record (const operand_error_record *record, char *str) && programmer_friendly_fixup (&inst); gas_assert (result); result = aarch64_opcode_encode (opcode, inst_base, &inst_base->value, - NULL, NULL); + NULL, NULL, insn_sequence); gas_assert (!result); /* Find the most matched qualifier sequence. */ @@ -4797,10 +4910,12 @@ output_operand_error_report (char *str, bfd_boolean non_fatal_only) { 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. */ @@ -4809,7 +4924,7 @@ output_operand_error_report (char *str, bfd_boolean non_fatal_only) /* 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 && !head->detail.non_fatal)) + || (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 @@ -5072,6 +5187,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_SP: case AARCH64_OPND_Rs: case AARCH64_OPND_Ra: case AARCH64_OPND_Rt_SYS: @@ -5138,6 +5254,11 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode, case AARCH64_OPND_BARRIER_ISB: operand->barrier = aarch64_barrier_options + default_value; + break; + + case AARCH64_OPND_BTI_TARGET: + operand->hint_option = aarch64_hint_options + default_value; + break; default: break; @@ -5443,6 +5564,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) case AARCH64_OPND_Rd_SP: case AARCH64_OPND_Rn_SP: + case AARCH64_OPND_Rt_SP: case AARCH64_OPND_SVE_Rn_SP: case AARCH64_OPND_Rm_SP: po_int_reg_or_fail (REG_TYPE_R_SP); @@ -5567,6 +5689,8 @@ parse_operands (char *str, const aarch64_opcode *opcode) 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; @@ -5624,11 +5748,20 @@ parse_operands (char *str, const aarch64_opcode *opcode) val = parse_vector_reg_list (&str, reg_type, &vectype); if (val == PARSE_FAIL) goto failure; + if (! reg_list_valid_p (val, /* accept_alternate */ 0)) { set_fatal_syntax_error (_("invalid register list")); goto failure; } + + if (vectype.width != 0 && *str != ',') + { + set_fatal_syntax_error + (_("expected element type rather than vector type")); + goto failure; + } + info->reglist.first_regno = (val >> 2) & 0x1f; info->reglist.num_regs = (val & 0x3) + 1; } @@ -5682,7 +5815,10 @@ parse_operands (char *str, const aarch64_opcode *opcode) case AARCH64_OPND_CCMP_IMM: case AARCH64_OPND_SIMM5: case AARCH64_OPND_FBITS: + case AARCH64_OPND_TME_UIMM16: case AARCH64_OPND_UIMM4: + case AARCH64_OPND_UIMM4_ADDG: + case AARCH64_OPND_UIMM10: case AARCH64_OPND_UIMM3_OP1: case AARCH64_OPND_UIMM3_OP2: case AARCH64_OPND_IMM_VLSL: @@ -5694,8 +5830,10 @@ parse_operands (char *str, const aarch64_opcode *opcode) 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: @@ -5709,6 +5847,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) 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; @@ -6153,6 +6292,8 @@ parse_operands (char *str, const aarch64_opcode *opcode) case AARCH64_OPND_ADDR_SIMM9: case AARCH64_OPND_ADDR_SIMM9_2: + case AARCH64_OPND_ADDR_SIMM11: + case AARCH64_OPND_ADDR_SIMM13: po_misc_or_fail (parse_address (&str, info)); if (info->addr.pcrel || info->addr.offset.is_reg || (!info->addr.preind && !info->addr.postind) @@ -6342,6 +6483,33 @@ parse_operands (char *str, const aarch64_opcode *opcode) info->qualifier = offset_qualifier; goto regoff_addr; + case AARCH64_OPND_SVE_ADDR_ZX: + /* [Zn.{, }]. */ + 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: @@ -6410,14 +6578,22 @@ parse_operands (char *str, const aarch64_opcode *opcode) inst.base.operands[i].sysins_op = parse_sys_ins_reg (&str, aarch64_sys_regs_ic_hsh); goto sys_reg_ins; + case AARCH64_OPND_SYSREG_DC: inst.base.operands[i].sysins_op = parse_sys_ins_reg (&str, aarch64_sys_regs_dc_hsh); goto sys_reg_ins; + case AARCH64_OPND_SYSREG_AT: inst.base.operands[i].sysins_op = parse_sys_ins_reg (&str, aarch64_sys_regs_at_hsh); goto sys_reg_ins; + + case AARCH64_OPND_SYSREG_SR: + inst.base.operands[i].sysins_op = + parse_sys_ins_reg (&str, aarch64_sys_regs_sr_hsh); + goto sys_reg_ins; + case AARCH64_OPND_SYSREG_TLBI: inst.base.operands[i].sysins_op = parse_sys_ins_reg (&str, aarch64_sys_regs_tlbi_hsh); @@ -6462,6 +6638,12 @@ sys_reg_ins: goto failure; break; + case AARCH64_OPND_BTI_TARGET: + val = parse_bti_operand (&str, &(info->hint_option)); + if (val == PARSE_FAIL) + goto failure; + break; + default: as_fatal (_("unhandled operand code %d"), operands[i]); } @@ -6686,9 +6868,12 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str) == AARCH64_OPND_CLASS_INT_REG) && opnds[0].reg.regno == opnds[1].addr.base_regno && opnds[1].addr.base_regno != REG_SP + /* Exempt STG/STZG/ST2G/STZ2G. */ + && !(opnds[1].type == AARCH64_OPND_ADDR_SIMM13) && opnds[1].addr.writeback) as_warn (_("unpredictable transfer with writeback -- `%s'"), str); break; + case ldstpair_off: case ldstnapair_offs: case ldstpair_indexed: @@ -6698,6 +6883,8 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str) && (opnds[0].reg.regno == opnds[2].addr.base_regno || opnds[1].reg.regno == opnds[2].addr.base_regno) && opnds[2].addr.base_regno != REG_SP + /* Exempt STGP. */ + && !(opnds[2].type == AARCH64_OPND_ADDR_SIMM11) && opnds[2].addr.writeback) as_warn (_("unpredictable transfer with writeback -- `%s'"), str); /* Load operations must load different registers. */ @@ -6726,6 +6913,17 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str) } } +static void +force_automatic_sequence_close (void) +{ + if (now_instr_sequence.instr) + { + as_warn (_("previous `%s' sequence has not been closed"), + now_instr_sequence.instr->opcode->name); + init_insn_sequence (NULL, &now_instr_sequence); + } +} + /* A wrapper function to interface with libopcodes on encoding and record the error message if there is any. @@ -6738,7 +6936,7 @@ do_encode (const aarch64_opcode *opcode, aarch64_inst *instr, aarch64_operand_error error_info; memset (&error_info, '\0', sizeof (error_info)); error_info.kind = AARCH64_OPDE_NIL; - if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info) + if (aarch64_opcode_encode (opcode, instr, code, NULL, &error_info, insn_sequence) && !error_info.non_fatal) return TRUE; @@ -6784,6 +6982,9 @@ md_assemble (char *str) S_SET_SEGMENT (last_label_seen, now_seg); } + /* Update the current insn_sequence from the segment. */ + insn_sequence = &seg_info (now_seg)->tc_segment_info_data.insn_sequence; + inst.reloc.type = BFD_RELOC_UNUSED; DEBUG_TRACE ("\n\n"); @@ -6916,6 +7117,13 @@ aarch64_frob_label (symbolS * sym) dwarf2_emit_label (sym); } +void +aarch64_frob_section (asection *sec ATTRIBUTE_UNUSED) +{ + /* Check to see if we have a block to close. */ + force_automatic_sequence_close (); +} + int aarch64_data_in_code (void) { @@ -7169,7 +7377,7 @@ aarch64_init_frag (fragS * fragP, int max_chars) /* PR 21809: Do not set a mapping state for debug sections - it just confuses other tools. */ - if (bfd_get_section_flags (NULL, now_seg) & SEC_DEBUGGING) + if (bfd_section_flags (now_seg) & SEC_DEBUGGING) return; switch (fragP->fr_type) @@ -7376,7 +7584,8 @@ try_to_encode_as_unscaled_ldst (aarch64_inst *instr) DEBUG_TRACE ("Found LDURB entry to encode programmer-friendly LDRB"); - if (!aarch64_opcode_encode (instr->opcode, instr, &instr->value, NULL, NULL)) + if (!aarch64_opcode_encode (instr->opcode, instr, &instr->value, NULL, NULL, + insn_sequence)) return FALSE; return TRUE; @@ -7410,7 +7619,7 @@ fix_mov_imm_insn (fixS *fixP, char *buf, aarch64_inst *instr, offsetT value) opcode = aarch64_get_opcode (OP_MOV_IMM_WIDE); aarch64_replace_opcode (instr, opcode); if (aarch64_opcode_encode (instr->opcode, instr, - &instr->value, NULL, NULL)) + &instr->value, NULL, NULL, insn_sequence)) { put_aarch64_insn (buf, instr->value); return; @@ -7419,7 +7628,7 @@ fix_mov_imm_insn (fixS *fixP, char *buf, aarch64_inst *instr, offsetT value) opcode = aarch64_get_opcode (OP_MOV_IMM_WIDEN); aarch64_replace_opcode (instr, opcode); if (aarch64_opcode_encode (instr->opcode, instr, - &instr->value, NULL, NULL)) + &instr->value, NULL, NULL, insn_sequence)) { put_aarch64_insn (buf, instr->value); return; @@ -7432,7 +7641,7 @@ fix_mov_imm_insn (fixS *fixP, char *buf, aarch64_inst *instr, offsetT value) opcode = aarch64_get_opcode (OP_MOV_IMM_LOG); aarch64_replace_opcode (instr, opcode); if (aarch64_opcode_encode (instr->opcode, instr, - &instr->value, NULL, NULL)) + &instr->value, NULL, NULL, insn_sequence)) { put_aarch64_insn (buf, instr->value); return; @@ -7543,7 +7752,7 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value) idx = aarch64_operand_index (new_inst->opcode->operands, opnd); new_inst->operands[idx].imm.value = value; if (aarch64_opcode_encode (new_inst->opcode, new_inst, - &new_inst->value, NULL, NULL)) + &new_inst->value, NULL, NULL, insn_sequence)) put_aarch64_insn (buf, new_inst->value); else as_bad_where (fixP->fx_file, fixP->fx_line, @@ -7577,6 +7786,8 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value) case AARCH64_OPND_ADDR_SIMM9_2: case AARCH64_OPND_ADDR_SIMM10: case AARCH64_OPND_ADDR_UIMM12: + case AARCH64_OPND_ADDR_SIMM11: + case AARCH64_OPND_ADDR_SIMM13: /* Immediate offset in an address. */ insn = get_aarch64_insn (buf); @@ -7597,7 +7808,7 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value) /* Encode/fix-up. */ if (aarch64_opcode_encode (new_inst->opcode, new_inst, - &new_inst->value, NULL, NULL)) + &new_inst->value, NULL, NULL, insn_sequence)) { put_aarch64_insn (buf, new_inst->value); break; @@ -8216,15 +8427,18 @@ aarch64_after_parse_args (void) const char * elf64_aarch64_target_format (void) { - if (strcmp (TARGET_OS, "cloudabi") == 0) - { - /* FIXME: What to do for ilp32_p ? */ - return target_big_endian ? "elf64-bigaarch64-cloudabi" : "elf64-littleaarch64-cloudabi"; - } +#ifdef TE_CLOUDABI + /* FIXME: What to do for ilp32_p ? */ + if (target_big_endian) + return "elf64-bigaarch64-cloudabi"; + else + return "elf64-littleaarch64-cloudabi"; +#else if (target_big_endian) return ilp32_p ? "elf32-bigaarch64" : "elf64-bigaarch64"; else return ilp32_p ? "elf32-littleaarch64" : "elf64-littleaarch64"; +#endif } void @@ -8405,6 +8619,7 @@ md_begin (void) || (aarch64_sys_regs_dc_hsh = hash_new ()) == NULL || (aarch64_sys_regs_at_hsh = hash_new ()) == NULL || (aarch64_sys_regs_tlbi_hsh = hash_new ()) == NULL + || (aarch64_sys_regs_sr_hsh = hash_new ()) == NULL || (aarch64_reg_hsh = hash_new ()) == NULL || (aarch64_barrier_opt_hsh = hash_new ()) == NULL || (aarch64_nzcv_hsh = hash_new ()) == NULL @@ -8443,6 +8658,11 @@ md_begin (void) aarch64_sys_regs_tlbi[i].name, (void *) (aarch64_sys_regs_tlbi + i)); + for (i = 0; aarch64_sys_regs_sr[i].name != NULL; i++) + checked_hash_insert (aarch64_sys_regs_sr_hsh, + aarch64_sys_regs_sr[i].name, + (void *) (aarch64_sys_regs_sr + i)); + for (i = 0; i < ARRAY_SIZE (reg_names); i++) checked_hash_insert (aarch64_reg_hsh, reg_names[i].name, (void *) (reg_names + i)); @@ -8594,6 +8814,8 @@ struct aarch64_cpu_option_table recognized by GCC. */ static const struct aarch64_cpu_option_table aarch64_cpus[] = { {"all", AARCH64_ANY, NULL}, + {"cortex-a34", AARCH64_FEATURE (AARCH64_ARCH_V8, + AARCH64_FEATURE_CRC), "Cortex-A34"}, {"cortex-a35", AARCH64_FEATURE (AARCH64_ARCH_V8, AARCH64_FEATURE_CRC), "Cortex-A35"}, {"cortex-a53", AARCH64_FEATURE (AARCH64_ARCH_V8, @@ -8613,6 +8835,31 @@ static const struct aarch64_cpu_option_table aarch64_cpus[] = { {"cortex-a76", AARCH64_FEATURE (AARCH64_ARCH_V8_2, AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16 | AARCH64_FEATURE_DOTPROD), "Cortex-A76"}, + {"cortex-a76ae", AARCH64_FEATURE (AARCH64_ARCH_V8_2, + AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC + | AARCH64_FEATURE_DOTPROD + | AARCH64_FEATURE_SSBS), + "Cortex-A76AE"}, + {"cortex-a77", AARCH64_FEATURE (AARCH64_ARCH_V8_2, + AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC + | AARCH64_FEATURE_DOTPROD + | AARCH64_FEATURE_SSBS), + "Cortex-A77"}, + {"cortex-a65", AARCH64_FEATURE (AARCH64_ARCH_V8_2, + AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC + | AARCH64_FEATURE_DOTPROD + | AARCH64_FEATURE_SSBS), + "Cortex-A65"}, + {"cortex-a65ae", AARCH64_FEATURE (AARCH64_ARCH_V8_2, + AARCH64_FEATURE_F16 | AARCH64_FEATURE_RCPC + | AARCH64_FEATURE_DOTPROD + | AARCH64_FEATURE_SSBS), + "Cortex-A65AE"}, + {"ares", AARCH64_FEATURE (AARCH64_ARCH_V8_2, + AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16 + | AARCH64_FEATURE_DOTPROD + | AARCH64_FEATURE_PROFILE), + "Ares"}, {"exynos-m1", AARCH64_FEATURE (AARCH64_ARCH_V8, AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO), "Samsung Exynos M1"}, @@ -8620,6 +8867,16 @@ static const struct aarch64_cpu_option_table aarch64_cpus[] = { AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO | AARCH64_FEATURE_RDMA), "Qualcomm Falkor"}, + {"neoverse-e1", AARCH64_FEATURE (AARCH64_ARCH_V8_2, + AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16 + | AARCH64_FEATURE_DOTPROD + | AARCH64_FEATURE_SSBS), + "Neoverse E1"}, + {"neoverse-n1", AARCH64_FEATURE (AARCH64_ARCH_V8_2, + AARCH64_FEATURE_RCPC | AARCH64_FEATURE_F16 + | AARCH64_FEATURE_DOTPROD + | AARCH64_FEATURE_PROFILE), + "Neoverse N1"}, {"qdf24xx", AARCH64_FEATURE (AARCH64_ARCH_V8, AARCH64_FEATURE_CRC | AARCH64_FEATURE_CRYPTO | AARCH64_FEATURE_RDMA), @@ -8660,6 +8917,8 @@ static const struct aarch64_arch_option_table aarch64_archs[] = { {"armv8.2-a", AARCH64_ARCH_V8_2}, {"armv8.3-a", AARCH64_ARCH_V8_3}, {"armv8.4-a", AARCH64_ARCH_V8_4}, + {"armv8.5-a", AARCH64_ARCH_V8_5}, + {"armv8.6-a", AARCH64_ARCH_V8_6}, {NULL, AARCH64_ARCH_NONE} }; @@ -8703,6 +8962,8 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = { AARCH64_FEATURE (AARCH64_FEATURE_F16 | AARCH64_FEATURE_SIMD | AARCH64_FEATURE_COMPNUM, 0)}, + {"tme", AARCH64_FEATURE (AARCH64_FEATURE_TME, 0), + AARCH64_ARCH_NONE}, {"compnum", AARCH64_FEATURE (AARCH64_FEATURE_COMPNUM, 0), AARCH64_FEATURE (AARCH64_FEATURE_F16 | AARCH64_FEATURE_SIMD, 0)}, @@ -8712,6 +8973,10 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = { AARCH64_ARCH_NONE}, {"sha2", AARCH64_FEATURE (AARCH64_FEATURE_SHA2, 0), AARCH64_ARCH_NONE}, + {"sb", AARCH64_FEATURE (AARCH64_FEATURE_SB, 0), + AARCH64_ARCH_NONE}, + {"predres", AARCH64_FEATURE (AARCH64_FEATURE_PREDRES, 0), + AARCH64_ARCH_NONE}, {"aes", AARCH64_FEATURE (AARCH64_FEATURE_AES, 0), AARCH64_ARCH_NONE}, {"sm4", AARCH64_FEATURE (AARCH64_FEATURE_SM4, 0), @@ -8719,6 +8984,25 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = { {"sha3", AARCH64_FEATURE (AARCH64_FEATURE_SHA2 | AARCH64_FEATURE_SHA3, 0), AARCH64_ARCH_NONE}, + {"rng", AARCH64_FEATURE (AARCH64_FEATURE_RNG, 0), + AARCH64_ARCH_NONE}, + {"ssbs", AARCH64_FEATURE (AARCH64_FEATURE_SSBS, 0), + AARCH64_ARCH_NONE}, + {"memtag", AARCH64_FEATURE (AARCH64_FEATURE_MEMTAG, 0), + AARCH64_ARCH_NONE}, + {"sve2", AARCH64_FEATURE (AARCH64_FEATURE_SVE2, 0), + AARCH64_FEATURE (AARCH64_FEATURE_SVE, 0)}, + {"sve2-sm4", AARCH64_FEATURE (AARCH64_FEATURE_SVE2_SM4, 0), + AARCH64_FEATURE (AARCH64_FEATURE_SVE2 + | AARCH64_FEATURE_SM4, 0)}, + {"sve2-aes", AARCH64_FEATURE (AARCH64_FEATURE_SVE2_AES, 0), + AARCH64_FEATURE (AARCH64_FEATURE_SVE2 + | AARCH64_FEATURE_AES, 0)}, + {"sve2-sha3", AARCH64_FEATURE (AARCH64_FEATURE_SVE2_SHA3, 0), + AARCH64_FEATURE (AARCH64_FEATURE_SVE2 + | AARCH64_FEATURE_SHA3, 0)}, + {"sve2-bitperm", AARCH64_FEATURE (AARCH64_FEATURE_SVE2_BITPERM, 0), + AARCH64_FEATURE (AARCH64_FEATURE_SVE2, 0)}, {NULL, AARCH64_ARCH_NONE, AARCH64_ARCH_NONE}, }; @@ -9183,3 +9467,35 @@ aarch64_copy_symbol_attributes (symbolS * dest, symbolS * src) { AARCH64_GET_FLAG (dest) = AARCH64_GET_FLAG (src); } + +#ifdef OBJ_ELF +/* Same as elf_copy_symbol_attributes, but without copying st_other. + This is needed so AArch64 specific st_other values can be independently + specified for an IFUNC resolver (that is called by the dynamic linker) + and the symbol it resolves (aliased to the resolver). In particular, + if a function symbol has special st_other value set via directives, + then attaching an IFUNC resolver to that symbol should not override + the st_other setting. Requiring the directive on the IFUNC resolver + symbol would be unexpected and problematic in C code, where the two + symbols appear as two independent function declarations. */ + +void +aarch64_elf_copy_symbol_attributes (symbolS *dest, symbolS *src) +{ + struct elf_obj_sy *srcelf = symbol_get_obj (src); + struct elf_obj_sy *destelf = symbol_get_obj (dest); + if (srcelf->size) + { + if (destelf->size == NULL) + destelf->size = XNEW (expressionS); + *destelf->size = *srcelf->size; + } + else + { + if (destelf->size != NULL) + free (destelf->size); + destelf->size = NULL; + } + S_SET_SIZE (dest, S_GET_SIZE (src)); +} +#endif