@@ -379,6 +379,7 @@ extern int vfp3_const_double_for_bits (rtx);
extern void arm_emit_coreregs_64bit_shift (enum rtx_code, rtx, rtx, rtx, rtx,
rtx);
extern bool arm_fusion_enabled_p (tune_params::fuse_ops);
+extern bool arm_current_function_pac_enabled_p (void);
extern bool arm_valid_symbolic_address_p (rtx);
extern bool arm_validize_comparison (rtx *, rtx *, rtx *);
extern bool arm_expand_vector_compare (rtx, rtx_code, rtx, rtx, bool);
@@ -3209,6 +3209,9 @@ arm_option_override_internal (struct gcc_options *opts,
arm_stack_protector_guard_offset = offs;
}
+ if (arm_current_function_pac_enabled_p () && !(arm_arch7 && arm_arch_cmse))
+ error ("This architecture does not support branch protection instructions");
+
#ifdef SUBTARGET_OVERRIDE_INTERNAL_OPTIONS
SUBTARGET_OVERRIDE_INTERNAL_OPTIONS;
#endif
@@ -21139,6 +21142,9 @@ arm_compute_save_core_reg_mask (void)
save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
+ if (arm_current_function_pac_enabled_p ())
+ save_reg_mask |= 1 << IP_REGNUM;
+
/* Decide if we need to save the link register.
Interrupt routines have their own banked link register,
so they never need to save it.
@@ -23362,6 +23368,12 @@ output_probe_stack_range (rtx reg1, rtx reg2)
return "";
}
+static bool
+aarch_bti_enabled ()
+{
+ return false;
+}
+
/* Generate the prologue instructions for entry into an ARM or Thumb-2
function. */
void
@@ -23440,12 +23452,13 @@ arm_expand_prologue (void)
/* The static chain register is the same as the IP register. If it is
clobbered when creating the frame, we need to save and restore it. */
- clobber_ip = IS_NESTED (func_type)
- && ((TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
- || ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
- || flag_stack_clash_protection)
- && !df_regs_ever_live_p (LR_REGNUM)
- && arm_r3_live_at_start_p ()));
+ clobber_ip = (IS_NESTED (func_type)
+ && (((TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
+ || ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
+ && !df_regs_ever_live_p (LR_REGNUM)
+ && arm_r3_live_at_start_p ()))
+ || (arm_current_function_pac_enabled_p ())));
/* Find somewhere to store IP whilst the frame is being created.
We try the following places in order:
@@ -23521,6 +23534,14 @@ arm_expand_prologue (void)
}
}
+ if (arm_current_function_pac_enabled_p ())
+ {
+ if (aarch_bti_enabled ())
+ emit_insn (gen_pacbti_nop ());
+ else
+ emit_insn (gen_pac_nop ());
+ }
+
if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
{
if (IS_INTERRUPT (func_type))
@@ -27309,7 +27330,7 @@ thumb2_expand_return (bool simple_return)
to assert it for now to ensure that future code changes do not silently
change this behavior. */
gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
- if (num_regs == 1)
+ if (num_regs == 1 && !arm_current_function_pac_enabled_p ())
{
rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
rtx reg = gen_rtx_REG (SImode, PC_REGNUM);
@@ -27324,10 +27345,20 @@ thumb2_expand_return (bool simple_return)
}
else
{
- saved_regs_mask &= ~ (1 << LR_REGNUM);
- saved_regs_mask |= (1 << PC_REGNUM);
- arm_emit_multi_reg_pop (saved_regs_mask);
- }
+ if (arm_current_function_pac_enabled_p ())
+ {
+ gcc_assert (!(saved_regs_mask & (1 << PC_REGNUM)));
+ arm_emit_multi_reg_pop (saved_regs_mask);
+ emit_insn (gen_aut_nop ());
+ emit_jump_insn (simple_return_rtx);
+ }
+ else
+ {
+ saved_regs_mask &= ~ (1 << LR_REGNUM);
+ saved_regs_mask |= (1 << PC_REGNUM);
+ arm_emit_multi_reg_pop (saved_regs_mask);
+ }
+ }
}
else
{
@@ -27733,7 +27764,8 @@ arm_expand_epilogue (bool really_return)
&& really_return
&& crtl->args.pretend_args_size == 0
&& saved_regs_mask & (1 << LR_REGNUM)
- && !crtl->calls_eh_return)
+ && !crtl->calls_eh_return
+ && !arm_current_function_pac_enabled_p ())
{
saved_regs_mask &= ~(1 << LR_REGNUM);
saved_regs_mask |= (1 << PC_REGNUM);
@@ -27847,6 +27879,9 @@ arm_expand_epilogue (bool really_return)
}
}
+ if (arm_current_function_pac_enabled_p ())
+ emit_insn (gen_aut_nop ());
+
if (!really_return)
return;
@@ -32941,6 +32976,15 @@ arm_fusion_enabled_p (tune_params::fuse_ops op)
return current_tune->fusible_ops & op;
}
+/* Return TRUE if return address signing mechanism is enabled. */
+bool
+arm_current_function_pac_enabled_p (void)
+{
+ return aarch_ra_sign_scope == AARCH_FUNCTION_ALL
+ || (aarch_ra_sign_scope == AARCH_FUNCTION_NON_LEAF
+ && !crtl->is_leaf);
+}
+
/* Implement TARGET_SCHED_CAN_SPECULATE_INSN. Return true if INSN can be
scheduled for speculative execution. Reject the long-running division
and square-root instructions. */
@@ -11518,7 +11518,7 @@
arm_expand_prologue ();
else
thumb1_expand_prologue ();
- DONE;
+ DONE;
"
)
@@ -12890,6 +12890,29 @@
(set_attr "length" "8")]
)
+(define_insn "pac_nop"
+ [(set (reg:SI IP_REGNUM)
+ (unspec:SI [(reg:SI SP_REGNUM) (reg:SI LR_REGNUM)]
+ UNSPEC_PAC_NOP))]
+ "arm_arch7 && arm_arch_cmse"
+ "pac\t%|ip, %|lr, %|sp"
+ [(set_attr "length" "4")])
+
+(define_insn "pacbti_nop"
+ [(set (reg:SI IP_REGNUM)
+ (unspec:SI [(reg:SI SP_REGNUM) (reg:SI LR_REGNUM)]
+ UNSPEC_PACBTI_NOP))]
+ "arm_arch7 && arm_arch_cmse"
+ "pacbti\t%|ip, %|lr, %|sp"
+ [(set_attr "length" "4")])
+
+(define_insn "aut_nop"
+ [(unspec:SI [(reg:SI IP_REGNUM) (reg:SI SP_REGNUM) (reg:SI LR_REGNUM)]
+ UNSPEC_AUT_NOP)]
+ "arm_arch7 && arm_arch_cmse"
+ "aut\t%|ip, %|lr, %|sp"
+ [(set_attr "length" "4")])
+
;; Vector bits common to IWMMXT, Neon and MVE
(include "vec-common.md")
;; Load the Intel Wireless Multimedia Extension patterns
@@ -159,6 +159,9 @@
UNSPEC_VCDE ; Custom Datapath Extension instruction.
UNSPEC_VCDEA ; Custom Datapath Extension instruction.
UNSPEC_DLS ; Used for DLS (Do Loop Start), Armv8.1-M Mainline instruction
+ UNSPEC_PAC_NOP ; Represents PAC signing LR
+ UNSPEC_PACBTI_NOP ; Represents PAC signing LR + valid landing pad
+ UNSPEC_AUT_NOP ; Represents PAC verifying LR
])
new file mode 100644
@@ -0,0 +1,12 @@
+/* Testing return address signing. */
+/* { dg-do run } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-require-effective-target arm_pacbti_hw } */
+/* { dg-options "-march=armv8.1-m.main+pacbti+fp -mbranch-protection=pac-ret+leaf -mthumb -mfloat-abi=hard --save-temps -O0" } */
+
+#include "pac.h"
+
+/* { dg-final { scan-assembler-times "pac\tip, lr, sp" 2 } } */
+/* { dg-final { scan-assembler-times "aut\tip, lr, sp" 2 } } */
+/* { dg-final { scan-assembler-not "\tbti" } } */
+
new file mode 100644
@@ -0,0 +1,11 @@
+/* Testing return address signing. */
+/* { dg-do run } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-require-effective-target arm_pacbti_hw } */
+/* { dg-options "-march=armv8.1-m.main+pacbti+fp -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard --save-temps -O0" } */
+
+#include "pac.h"
+
+/* { dg-final { scan-assembler "pac\tip, lr, sp" } } */
+/* { dg-final { scan-assembler "aut\tip, lr, sp" } } */
+/* { dg-final { scan-assembler-not "\tbti" } } */
new file mode 100644
@@ -0,0 +1,11 @@
+/* Testing return address signing. */
+/* { dg-do run } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-require-effective-target arm_pacbti_hw } */
+/* { dg-options "-march=armv8.1-m.main+pacbti+fp -mbranch-protection=bti+pac-ret+leaf -mthumb -mfloat-abi=hard --save-temps -O2" } */
+
+#include "pac.h"
+
+/* { dg-final { scan-assembler-times "pacbti\tip, lr, sp" 2 } } */
+/* { dg-final { scan-assembler-times "aut\tip, lr, sp" 2 } } */
+/* { dg-final { scan-assembler-not "\tbti" } } */
new file mode 100644
@@ -0,0 +1,10 @@
+/* Testing return address signing. */
+/* { dg-do compile } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-options "-march=armv8.1-m.main+pacbti+fp -mthumb -mfloat-abi=hard --save-temps -O2" } */
+
+#include "pac.h"
+
+/* { dg-final { scan-assembler-not "\tbti\t" } } */
+/* { dg-final { scan-assembler-not "\tpac\t" } } */
+/* { dg-final { scan-assembler-not "\tpacbti\t" } } */
new file mode 100644
@@ -0,0 +1,28 @@
+/* Testing return address signing. */
+/* { dg-do run } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-require-effective-target arm_pacbti_hw } */
+/* { dg-options "-march=armv8.1-m.main+pacbti+fp -mbranch-protection=pac-ret+leaf -mthumb -mfloat-abi=hard --save-temps -O0" } */
+
+#include <stdlib.h>
+
+int
+__attribute__((noinline))
+foo1 (int a, int b)
+{
+ int square (int z) { return z * z; }
+ return square (a) + square (b);
+}
+
+int
+main (void)
+{
+ if (foo1 (1, 2) != 5)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "pac\tip, lr, sp" 3 } } */
+/* { dg-final { scan-assembler-times "aut\tip, lr, sp" 3 } } */
+/* { dg-final { scan-assembler-not "\tbti" } } */
new file mode 100644
@@ -0,0 +1,18 @@
+/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE pseudo hard-register. */
+/* { dg-do compile } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-options "-march=armv8.1-m.main+fp -mbranch-protection=pac-ret+leaf -mthumb --save-temps -O0 -g" } */
+
+int i;
+
+void foo (int);
+
+int bar()
+{
+ foo (i);
+ return 0;
+}
+
+/* { dg-final { scan-assembler "pac\tip, lr, sp" } } */
+/* { dg-final { scan-assembler "aut\tip, lr, sp" } } */
+/* { dg-final { scan-assembler-not "bti" } } */
new file mode 100644
@@ -0,0 +1,32 @@
+/* Testing return address signing. */
+/* { dg-do run } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-require-effective-target arm_pacbti_hw } */
+/* { dg-options "-march=armv8.1-m.main+pacbti+fp -mbranch-protection=pac-ret+leaf -mthumb -mfloat-abi=hard --save-temps -O0" } */
+
+#include <stdlib.h>
+
+int
+__attribute__((noinline))
+foo1 (int a, int b)
+{
+ int x = 4;
+ int foo2 (int a, int b)
+ {
+ return a + b + x;
+ }
+ return foo2 (a, b);
+}
+
+int
+main (void)
+{
+ if (foo1 (1, 2) != 7)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "pac\tip, lr, sp" 3 } } */
+/* { dg-final { scan-assembler-times "aut\tip, lr, sp" 3 } } */
+/* { dg-final { scan-assembler-not "\tbti" } } */
new file mode 100644
@@ -0,0 +1,34 @@
+/* Testing return address signing. */
+/* { dg-do run } */
+/* { dg-require-effective-target mbranch_protection_ok } */
+/* { dg-require-effective-target arm_pacbti_hw } */
+/* { dg-options "-march=armv8.1-m.main+pacbti+fp -mbranch-protection=pac-ret+leaf -mthumb -mfloat-abi=hard --save-temps -O0" } */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+int acc (int n, ...)
+{
+ int sum = 0;
+ va_list ptr;
+
+ va_start (ptr, n);
+
+ for (int i = 0; i < n; i++)
+ sum += va_arg (ptr, int);
+ va_end (ptr);
+
+ return sum;
+}
+
+int main()
+{
+ if (acc (3, 1, 2, 3) != 6)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "pac\tip, lr, sp" 2 } } */
+/* { dg-final { scan-assembler-times "aut\tip, lr, sp" 2 } } */
+/* { dg-final { scan-assembler-not "\tbti" } } */
new file mode 100644
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+
+int
+__attribute__((noinline))
+foo1 (int a, int b)
+{
+ return a + b;
+}
+
+int
+main (void)
+{
+ if (foo1 (1, 2) != 3)
+ abort ();
+
+ return 0;
+}