machine_mode);
int aarch64_uxt_size (int, HOST_WIDE_INT);
int aarch64_vec_fpconst_pow_of_2 (rtx);
-rtx aarch64_eh_return_handler_rtx (void);
rtx aarch64_mask_from_zextract_ops (rtx, rtx);
const char *aarch64_output_move_struct (rtx *operands);
rtx aarch64_return_addr_rtx (void);
/* This function should only be called after frame laid out. */
gcc_assert (cfun->machine->frame.laid_out);
- /* Turn return address signing off in any function that uses
- __builtin_eh_return. The address passed to __builtin_eh_return
- is not signed so either it has to be signed (with original sp)
- or the code path that uses it has to avoid authenticating it.
- Currently eh return introduces a return to anywhere gadget, no
- matter what we do here since it uses ret with user provided
- address. An ideal fix for that is to use indirect branch which
- can be protected with BTI j (to some extent). */
- if (crtl->calls_eh_return)
- return false;
-
/* If signing scope is AARCH_FUNCTION_NON_LEAF, we only sign a leaf function
if its LR is pushed onto stack. */
return (aarch_ra_sign_scope == AARCH_FUNCTION_ALL
RTX_FRAME_RELATED_P (insn) = 1;
}
+ /* Stack adjustment for exception handler. */
+ if (crtl->calls_eh_return && !for_sibcall)
+ {
+ /* If the EH_RETURN_TAKEN_RTX flag is set then we need
+ to unwind the stack and jump to the handler, otherwise
+ skip this eh_return logic and continue with normal
+ return after the label. We have already reset the CFA
+ to be SP; letting the CFA move during this adjustment
+ is just as correct as retaining the CFA from the body
+ of the function. Therefore, do nothing special. */
+ rtx label = gen_label_rtx ();
+ rtx x = gen_rtx_EQ (VOIDmode, EH_RETURN_TAKEN_RTX, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
+ gen_rtx_LABEL_REF (Pmode, label), pc_rtx);
+ rtx jump = emit_jump_insn (gen_rtx_SET (pc_rtx, x));
+ JUMP_LABEL (jump) = label;
+ LABEL_NUSES (label)++;
+ emit_insn (gen_add2_insn (stack_pointer_rtx,
+ EH_RETURN_STACKADJ_RTX));
+ emit_jump_insn (gen_indirect_jump (EH_RETURN_HANDLER_RTX));
+ emit_barrier ();
+ emit_label (label);
+ }
+
/* We prefer to emit the combined return/authenticate instruction RETAA,
however there are three cases in which we must instead emit an explicit
authentication instruction.
RTX_FRAME_RELATED_P (insn) = 1;
}
- /* Stack adjustment for exception handler. */
- if (crtl->calls_eh_return && !for_sibcall)
- {
- /* We need to unwind the stack by the offset computed by
- EH_RETURN_STACKADJ_RTX. We have already reset the CFA
- to be SP; letting the CFA move during this adjustment
- is just as correct as retaining the CFA from the body
- of the function. Therefore, do nothing special. */
- emit_insn (gen_add2_insn (stack_pointer_rtx, EH_RETURN_STACKADJ_RTX));
- }
-
emit_use (gen_rtx_REG (DImode, LR_REGNUM));
if (!for_sibcall)
emit_jump_insn (ret_rtx);
}
-/* Implement EH_RETURN_HANDLER_RTX. EH returns need to either return
- normally or return to a previous frame after unwinding.
-
- An EH return uses a single shared return sequence. The epilogue is
- exactly like a normal epilogue except that it has an extra input
- register (EH_RETURN_STACKADJ_RTX) which contains the stack adjustment
- that must be applied after the frame has been destroyed. An extra label
- is inserted before the epilogue which initializes this register to zero,
- and this is the entry point for a normal return.
-
- An actual EH return updates the return address, initializes the stack
- adjustment and jumps directly into the epilogue (bypassing the zeroing
- of the adjustment). Since the return address is typically saved on the
- stack when a function makes a call, the saved LR must be updated outside
- the epilogue.
-
- This poses problems as the store is generated well before the epilogue,
- so the offset of LR is not known yet. Also optimizations will remove the
- store as it appears dead, even after the epilogue is generated (as the
- base or offset for loading LR is different in many cases).
-
- To avoid these problems this implementation forces the frame pointer
- in eh_return functions so that the location of LR is fixed and known early.
- It also marks the store volatile, so no optimization is permitted to
- remove the store. */
-rtx
-aarch64_eh_return_handler_rtx (void)
-{
- rtx tmp = gen_frame_mem (Pmode,
- plus_constant (Pmode, hard_frame_pointer_rtx, UNITS_PER_WORD));
-
- /* Mark the store volatile, so no optimization is permitted to remove it. */
- MEM_VOLATILE_P (tmp) = true;
- return tmp;
-}
-
/* Output code to add DELTA to the first argument, and then jump
to FUNCTION. Used for C++ multiple inheritance. */
static void
/* Output assembly strings after .cfi_startproc is emitted. */
#define ASM_POST_CFI_STARTPROC aarch64_post_cfi_startproc
-/* For EH returns X4 contains the stack adjustment. */
-#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, R4_REGNUM)
-#define EH_RETURN_HANDLER_RTX aarch64_eh_return_handler_rtx ()
+/* For EH returns X4 is a flag that is set in the EH return
+ code paths and then X5 and X6 contain the stack adjustment
+ and return address respectively. */
+#define EH_RETURN_TAKEN_RTX gen_rtx_REG (Pmode, R4_REGNUM)
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, R5_REGNUM)
+#define EH_RETURN_HANDLER_RTX gen_rtx_REG (Pmode, R6_REGNUM)
#undef TARGET_COMPUTE_FRAME_LAYOUT
#define TARGET_COMPUTE_FRAME_LAYOUT aarch64_layout_frame
}
#endif
+#ifdef EH_RETURN_TAKEN_RTX
+ if ((!targetm.have_epilogue () || ! epilogue_completed)
+ && crtl->calls_eh_return)
+ {
+ rtx tmp = EH_RETURN_TAKEN_RTX;
+ if (tmp && REG_P (tmp))
+ df_mark_reg (tmp, exit_block_uses);
+ }
+#endif
+
if ((!targetm.have_epilogue () || ! epilogue_completed)
&& crtl->calls_eh_return)
{
define either this macro or the @code{eh_return} instruction pattern.
@end defmac
+@defmac EH_RETURN_TAKEN_RTX
+A C expression whose value is RTL representing a location in which
+to store if the EH return path was taken instead of a normal return.
+This macro allows conditionally executing different code in the
+epilogue for the EH and normal return cases.
+
+When this macro is defined, the macros @code{EH_RETURN_STACKADJ_RTX}
+and @code{EH_RETURN_HANDLER_RTX} are only meaningful in the epilogue
+when 1 is stored to the specified location. The value 0 means normal
+return.
+@end defmac
+
@defmac RETURN_ADDR_OFFSET
If defined, an integer-valued C expression for which rtl will be generated
to add it to the exception handler address before it is searched in the
define either this macro or the @code{eh_return} instruction pattern.
@end defmac
+@defmac EH_RETURN_TAKEN_RTX
+A C expression whose value is RTL representing a location in which
+to store if the EH return path was taken instead of a normal return.
+This macro allows conditionally executing different code in the
+epilogue for the EH and normal return cases.
+
+When this macro is defined, the macros @code{EH_RETURN_STACKADJ_RTX}
+and @code{EH_RETURN_HANDLER_RTX} are only meaningful in the epilogue
+when 1 is stored to the specified location. The value 0 means normal
+return.
+@end defmac
+
@defmac RETURN_ADDR_OFFSET
If defined, an integer-valued C expression for which rtl will be generated
to add it to the exception handler address before it is searched in the
emit_move_insn (EH_RETURN_STACKADJ_RTX, const0_rtx);
#endif
+#ifdef EH_RETURN_TAKEN_RTX
+ emit_move_insn (EH_RETURN_TAKEN_RTX, const0_rtx);
+#endif
+
around_label = gen_label_rtx ();
emit_jump (around_label);
emit_move_insn (EH_RETURN_STACKADJ_RTX, crtl->eh.ehr_stackadj);
#endif
+#ifdef EH_RETURN_TAKEN_RTX
+ emit_move_insn (EH_RETURN_TAKEN_RTX, const1_rtx);
+#endif
+
if (targetm.have_eh_return ())
emit_insn (targetm.gen_eh_return (crtl->eh.ehr_handler));
else
error ("%<__builtin_eh_return%> not supported on this target");
}
+#ifdef EH_RETURN_TAKEN_RTX
+ rtx_code_label *eh_done_label = gen_label_rtx ();
+ emit_jump (eh_done_label);
+#endif
+
emit_label (around_label);
+
+#ifdef EH_RETURN_TAKEN_RTX
+ for (rtx tmp : { EH_RETURN_STACKADJ_RTX, EH_RETURN_HANDLER_RTX })
+ if (tmp && REG_P (tmp))
+ emit_clobber (tmp);
+ emit_label (eh_done_label);
+#endif
}
/* Convert a ptr_mode address ADDR_TREE to a Pmode address controlled by
/* autiasp */
}
-/* eh_return. */
-void __attribute__ ((target ("arch=armv8.3-a")))
-func4 (long offset, void *handler, int *ptr, int imm1, int imm2)
-{
- /* no paciasp */
- *ptr = imm1 + foo (imm1) + imm2;
- __builtin_eh_return (offset, handler);
- /* no autiasp */
- return;
-}
-
-/* { dg-final { scan-assembler-times "autiasp" 3 } } */
/* { dg-final { scan-assembler-times "paciasp" 3 } } */
+/* { dg-final { scan-assembler-times "autiasp" 3 } } */
/* retaa */
}
-/* { dg-final { scan-assembler-times "paciasp" 1 } } */
-/* { dg-final { scan-assembler-times "retaa" 1 } } */
+/* eh_return. */
+void __attribute__ ((target ("arch=armv8.3-a")))
+func4 (long offset, void *handler, int *ptr, int imm1, int imm2)
+{
+ /* paciasp */
+ *ptr = imm1 + foo (imm1) + imm2;
+ if (handler)
+ /* br */
+ __builtin_eh_return (offset, handler);
+ /* retaa */
+ return;
+}
+
+/* { dg-final { scan-assembler-times "paciasp" 2 } } */
+/* { dg-final { scan-assembler-times "retaa" 2 } } */
/* autibsp */
}
-/* eh_return. */
-void __attribute__ ((target ("arch=armv8.3-a")))
-func4 (long offset, void *handler, int *ptr, int imm1, int imm2)
-{
- /* no pacibsp */
- *ptr = imm1 + foo (imm1) + imm2;
- __builtin_eh_return (offset, handler);
- /* no autibsp */
- return;
-}
-
/* { dg-final { scan-assembler-times "pacibsp" 3 } } */
/* { dg-final { scan-assembler-times "autibsp" 3 } } */
/* retab */
}
-/* { dg-final { scan-assembler-times "pacibsp" 1 } } */
-/* { dg-final { scan-assembler-times "retab" 1 } } */
+/* eh_return. */
+void __attribute__ ((target ("arch=armv8.3-a")))
+func4 (long offset, void *handler, int *ptr, int imm1, int imm2)
+{
+ /* pacibsp */
+ *ptr = imm1 + foo (imm1) + imm2;
+ if (handler)
+ /* br */
+ __builtin_eh_return (offset, handler);
+ /* retab */
+ return;
+}
+
+/* { dg-final { scan-assembler-times "pacibsp" 2 } } */
+/* { dg-final { scan-assembler-times "retab" 2 } } */