@@ -970,4 +970,16 @@ extern tree aarch64_fp16_ptr_type_node;
|| (aarch64_ra_sign_scope == AARCH64_FUNCTION_NON_LEAF \
&& cfun->machine->frame.reg_offset[LR_REGNUM] >= 0))
+/* AArch64 pointer authentication action types. See AArch64 DWARF ABI for
+ details. */
+enum aarch64_pauth_action_type
+{
+ /* Drop the authentication signature for instruction pointer. */
+ AARCH64_PAUTH_DROP_I,
+ /* Likewise for data pointer. */
+ AARCH64_PAUTH_DROP_D,
+ /* Do authentication. */
+ AARCH64_PAUTH_AUTH
+};
+
#endif /* GCC_AARCH64_H */
@@ -2717,6 +2717,104 @@ aarch64_output_probe_stack_range (rtx reg1, rtx reg2)
return "";
}
+/* Generate return address signing DWARF annotation using general DWARF
+ operator. DWARF frame size will be bigger than using shortcut DWARF
+ operator. See aarch64_attach_ra_auth_dwarf for parameter meanings. */
+
+static rtx
+aarch64_attach_ra_auth_dwarf_general (rtx notes, HOST_WIDE_INT offset)
+{
+ /* The authentication descriptor. */
+ HOST_WIDE_INT desc_const = (AARCH64_PAUTH_AUTH | (aarch64_pauth_key << 4));
+
+ /* DW_OP_AARCH64_pauth takes one uleb128 operand which is the authentication
+ descriptor. The low 4 bits of the descriptor is the authentication action
+ code, all other bits are reserved and initialized into zero except when the
+ action code is AARCH64_PAUTH_AUTH then bits[7:4] is the authentication key
+ index. */
+ rtx auth_op
+ = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, GEN_INT (desc_const), const0_rtx),
+ DW_OP_AARCH64_pauth);
+
+ rtx par;
+ if (offset == 0)
+ {
+ /* Step 1: Push LR onto stack.
+ NOTE: the bottom of DWARF expression stack is always CFA.
+ Step 2: Issue AArch64 authentication operation. */
+ par = gen_rtx_PARALLEL (DImode,
+ gen_rtvec (2, gen_rtx_REG (Pmode, LR_REGNUM),
+ auth_op));
+ }
+ else
+ {
+ rtx dup_cfa
+ = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+ DW_OP_dup);
+
+ rtx deref_op
+ = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+ DW_OP_deref);
+
+ rtx raw_plus
+ = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+ DW_OP_plus);
+ /* Step 1: Push the authentication key on to dwarf expression stack.
+ Step 2: Push the stack address of where return address saved, followed
+ by a memory de-reference operation.
+ Step 3: Push the authentication descriptor.
+ Step 4: Issue AArch64 authentication operation. */
+ par = gen_rtx_PARALLEL (DImode,
+ gen_rtvec (5, dup_cfa, GEN_INT (offset), raw_plus,
+ deref_op, auth_op));
+ }
+
+ /* Generate the final dwarf value expression. */
+ return alloc_reg_note (REG_CFA_VAL_EXPRESSION,
+ gen_rtx_SET (gen_rtx_REG (DImode, LR_REGNUM), par),
+ notes);
+}
+
+/* Generate return address signing DWARF annotation using shortcut DWARF
+ operators. See aarch64_attach_ra_auth_dwarf for parameter meanings. */
+
+static rtx
+aarch64_attach_ra_auth_dwarf_shortcut (rtx notes, HOST_WIDE_INT offset)
+{
+ rtx auth_op, par;
+
+ /* See GCC/include/dwarf2.def for the semantics of DW_OP_AARCH64_paciasp
+ and DW_OP_AARCH64_paciasp_deref. */
+ if (offset == 0)
+ auth_op
+ = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+ DW_OP_AARCH64_paciasp);
+ else
+ auth_op
+ = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, GEN_INT (offset), const0_rtx),
+ DW_OP_AARCH64_paciasp_deref);
+
+ par = gen_rtx_PARALLEL (DImode, gen_rtvec (1, auth_op));
+
+ /* Generate the final dwarf value expression. */
+ return alloc_reg_note (REG_CFA_VAL_EXPRESSION,
+ gen_rtx_SET (gen_rtx_REG (DImode, LR_REGNUM), par),
+ notes);
+}
+
+/* Generate AArch64 specific dwarf expression annotation. NOTES is any existed
+ annotation that we want this new one to append. BASE is a valid base
+ register if the value should be fetch from BASE + OFFSET. */
+
+static rtx
+aarch64_attach_ra_auth_dwarf_note (rtx notes, HOST_WIDE_INT offset)
+{
+ if (aarch64_pauth_key != AARCH64_PAUTH_IKEY_A)
+ return aarch64_attach_ra_auth_dwarf_general (notes, offset);
+ else
+ return aarch64_attach_ra_auth_dwarf_shortcut (notes, offset);
+}
+
static bool
aarch64_frame_pointer_required (void)
{
@@ -3058,6 +3156,7 @@ aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
{
rtx reg, mem;
HOST_WIDE_INT offset;
+ unsigned lr_pair_reg = INVALID_REGNUM;
if (skip_wb
&& (regno == cfun->machine->frame.wb_candidate1
@@ -3069,6 +3168,9 @@ aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
mem = gen_mem_ref (mode, plus_constant (Pmode, stack_pointer_rtx,
offset));
+ if (regno == LR_REGNUM)
+ lr_pair_reg = LR_REGNUM;
+
regno2 = aarch64_next_callee_save (regno + 1, limit);
if (regno2 <= limit
@@ -3090,12 +3192,39 @@ aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
calculations; subsequent parts, are only
frame-related if explicitly marked. */
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
+
+ if (regno2 == LR_REGNUM)
+ lr_pair_reg = regno;
+
regno = regno2;
}
else
insn = emit_move_insn (mem, reg);
RTX_FRAME_RELATED_P (insn) = 1;
+
+ if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN && lr_pair_reg != INVALID_REGNUM)
+ {
+ rtx cfi_ops = NULL_RTX;
+
+ if (lr_pair_reg != LR_REGNUM)
+ {
+ /* Another register is saved together with LR to make a STP. We
+ need to generate .cfi_offset for that register. */
+ cfi_ops =
+ alloc_reg_note (REG_CFA_OFFSET,
+ gen_rtx_SET (mem,
+ gen_rtx_REG (Pmode, lr_pair_reg)),
+ NULL_RTX);
+ }
+
+ HOST_WIDE_INT lr_cfa_adj
+ = (-cfun->machine->frame.hard_fp_offset
+ + cfun->machine->frame.reg_offset[LR_REGNUM]);
+
+ REG_NOTES (insn)
+ = aarch64_attach_ra_auth_dwarf_note (cfi_ops, lr_cfa_adj);
+ }
}
}
@@ -3204,12 +3333,18 @@ aarch64_expand_prologue (void)
unsigned reg2 = cfun->machine->frame.wb_candidate2;
rtx_insn *insn;
+ /* Do return address signing for all functions, even those for which LR is not
+ pushed onto stack. */
if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN)
- emit_insn (gen_sign_reg (gen_rtx_REG (Pmode, LR_REGNUM),
- gen_rtx_REG (Pmode, LR_REGNUM),
- stack_pointer_rtx,
- GEN_INT (aarch64_pauth_key),
- const0_rtx));
+ {
+ insn = emit_insn (gen_sign_reg (gen_rtx_REG (Pmode, LR_REGNUM),
+ gen_rtx_REG (Pmode, LR_REGNUM),
+ stack_pointer_rtx,
+ GEN_INT (aarch64_pauth_key),
+ const0_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ REG_NOTES (insn) = aarch64_attach_ra_auth_dwarf_note (NULL_RTX, 0);
+ }
if (flag_stack_usage_info)
current_function_static_stack_size = frame_size;
@@ -3229,7 +3364,42 @@ aarch64_expand_prologue (void)
aarch64_add_constant (Pmode, SP_REGNUM, IP0_REGNUM, -initial_adjust, true);
if (callee_adjust != 0)
- aarch64_push_regs (reg1, reg2, callee_adjust);
+ {
+ aarch64_push_regs (reg1, reg2, callee_adjust);
+ /* Generate return address signing dwarf annotation when
+ omit-frame-pointer. */
+ if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN
+ && (reg1 == LR_REGNUM || reg2 == LR_REGNUM))
+ {
+ rtx cfi_ops = NULL_RTX;
+
+ if (reg2 == LR_REGNUM)
+ {
+ rtx mem_loc
+ = gen_rtx_MEM (Pmode,
+ plus_constant (Pmode, stack_pointer_rtx, 0));
+ cfi_ops
+ = alloc_reg_note (REG_CFA_OFFSET,
+ gen_rtx_SET (mem_loc,
+ gen_rtx_REG (Pmode, reg1)),
+ cfi_ops);
+ }
+
+ rtx sp_adj
+ = plus_constant (Pmode, stack_pointer_rtx, -callee_adjust);
+ cfi_ops
+ = alloc_reg_note (REG_CFA_ADJUST_CFA,
+ gen_rtx_SET (stack_pointer_rtx, sp_adj),
+ cfi_ops);
+
+ HOST_WIDE_INT lr_cfa_adj
+ = (-cfun->machine->frame.hard_fp_offset
+ + cfun->machine->frame.reg_offset[LR_REGNUM]);
+ rtx insn = get_last_insn ();
+ REG_NOTES (insn) = aarch64_attach_ra_auth_dwarf_note (cfi_ops,
+ lr_cfa_adj);
+ }
+ }
if (frame_pointer_needed)
{
@@ -3331,7 +3501,12 @@ aarch64_expand_epilogue (bool for_sibcall)
/* Emit delayed restores and set the CFA to be SP + initial_adjust. */
insn = get_last_insn ();
rtx new_cfa = plus_constant (Pmode, stack_pointer_rtx, initial_adjust);
- REG_NOTES (insn) = alloc_reg_note (REG_CFA_DEF_CFA, new_cfa, cfi_ops);
+ cfi_ops = alloc_reg_note (REG_CFA_DEF_CFA, new_cfa, cfi_ops);
+
+ if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN)
+ REG_NOTES (insn) = aarch64_attach_ra_auth_dwarf_note (cfi_ops, 0);
+ else
+ REG_NOTES (insn) = cfi_ops;
RTX_FRAME_RELATED_P (insn) = 1;
cfi_ops = NULL;
}
@@ -3355,11 +3530,14 @@ aarch64_expand_epilogue (bool for_sibcall)
__builtin_eh_return. */
if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN
&& (for_sibcall || !TARGET_PAUTH || crtl->calls_eh_return))
- emit_insn (gen_auth_reg (gen_rtx_REG (Pmode, LR_REGNUM),
- gen_rtx_REG (Pmode, LR_REGNUM),
- stack_pointer_rtx,
- GEN_INT (aarch64_pauth_key),
- const0_rtx));
+ {
+ insn = emit_insn (gen_auth_reg (gen_rtx_REG (Pmode, LR_REGNUM),
+ gen_rtx_REG (Pmode, LR_REGNUM),
+ stack_pointer_rtx,
+ GEN_INT (aarch64_pauth_key), const0_rtx));
+ add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
/* Stack adjustment for exception handler. */
if (crtl->calls_eh_return)