TLS_GNU,
TLS_GNU2
};
+
+/* Where to get the canary for the stack protector. */
+enum stack_protector_guard {
+ SSP_TLSREG, /* per-thread canary in TLS register */
+ SSP_GLOBAL /* global canary */
+};
#endif
extern rtx arm_load_tp (rtx);
extern bool arm_coproc_builtin_available (enum unspecv);
extern bool arm_coproc_ldc_stc_legitimate_address (rtx);
+extern rtx arm_stack_protect_tls_canary_mem (bool);
+
#if defined TREE_CODE
extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
#undef TARGET_MD_ASM_ADJUST
#define TARGET_MD_ASM_ADJUST arm_md_asm_adjust
+
+#undef TARGET_STACK_PROTECT_GUARD
+#define TARGET_STACK_PROTECT_GUARD arm_stack_protect_guard
\f
/* Obstack for minipool constant handling. */
static struct obstack minipool_obstack;
if (TARGET_THUMB2_P (opts->x_target_flags))
opts->x_inline_asm_unified = true;
+ if (arm_stack_protector_guard == SSP_GLOBAL
+ && opts->x_arm_stack_protector_guard_offset_str)
+ {
+ error ("incompatible options %'-mstack-protector-guard=global%' and"
+ "%'-mstack-protector-guard-offset=%qs%'",
+ arm_stack_protector_guard_offset_str);
+ }
+
+ if (opts->x_arm_stack_protector_guard_offset_str)
+ {
+ char *end;
+ const char *str = arm_stack_protector_guard_offset_str;
+ errno = 0;
+ long offs = strtol (arm_stack_protector_guard_offset_str, &end, 0);
+ if (!*str || *end || errno)
+ error ("%qs is not a valid offset in %qs", str,
+ "-mstack-protector-guard-offset=");
+ arm_stack_protector_guard_offset = offs;
+ }
+
#ifdef SUBTARGET_OVERRIDE_INTERNAL_OPTIONS
SUBTARGET_OVERRIDE_INTERNAL_OPTIONS;
#endif
else
target_thread_pointer = TP_SOFT;
}
+
+ if (!TARGET_HARD_TP && arm_stack_protector_guard == SSP_TLSREG)
+ error("%'-mstack-protector-guard=tls%' needs a hardware TLS register");
}
/* Perform some validation between the desired architecture and the rest of the
}
+/* Generate insns that produce the address of the stack canary */
+rtx
+arm_stack_protect_tls_canary_mem (bool reload)
+{
+ rtx tp = gen_reg_rtx (SImode);
+ if (reload)
+ emit_insn (gen_reload_tp_hard (tp));
+ else
+ emit_insn (gen_load_tp_hard (tp));
+
+ rtx reg = gen_reg_rtx (SImode);
+ rtx offset = GEN_INT (arm_stack_protector_guard_offset);
+ emit_set_insn (reg, gen_rtx_PLUS (SImode, tp, offset));
+ return gen_rtx_MEM (SImode, reg);
+}
+
+
/* Whether a register is callee saved or not. This is necessary because high
registers are marked as caller saved when optimizing for size on Thumb-1
targets despite being callee saved in order to avoid using them. */
#define TARGET_RUN_TARGET_SELFTESTS selftest::arm_run_selftests
#endif /* CHECKING_P */
+/* Implement TARGET_STACK_PROTECT_GUARD. In case of a
+ global variable based guard use the default else
+ return a null tree. */
+static tree
+arm_stack_protect_guard (void)
+{
+ if (arm_stack_protector_guard == SSP_GLOBAL)
+ return default_stack_protect_guard ();
+
+ return NULL_TREE;
+}
+
/* Worker function for TARGET_MD_ASM_ADJUST, while in thumb1 mode.
Unlike the arm version, we do NOT implement asm flag outputs. */
UNSPEC_SP_SET))
(clobber (match_scratch:SI 2 ""))
(clobber (match_scratch:SI 3 ""))])]
- ""
+ "arm_stack_protector_guard == SSP_GLOBAL"
""
)
(clobber (match_scratch:SI 3 ""))
(clobber (match_scratch:SI 4 ""))
(clobber (reg:CC CC_REGNUM))])]
- ""
+ "arm_stack_protector_guard == SSP_GLOBAL"
""
)
(set_attr "arch" "t,32")]
)
+(define_expand "stack_protect_set"
+ [(match_operand:SI 0 "memory_operand")
+ (match_operand:SI 1 "memory_operand")]
+ "arm_stack_protector_guard == SSP_TLSREG"
+ "
+{
+ operands[1] = arm_stack_protect_tls_canary_mem (false /* reload */);
+ emit_insn (gen_stack_protect_set_tls (operands[0], operands[1]));
+ DONE;
+}"
+)
+
+;; DO NOT SPLIT THIS PATTERN. It is important for security reasons that the
+;; canary value does not live beyond the life of this sequence.
+(define_insn "stack_protect_set_tls"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (unspec:SI [(match_operand:SI 1 "memory_operand" "m")]
+ UNSPEC_SP_SET))
+ (set (match_scratch:SI 2 "=&r") (const_int 0))]
+ ""
+ "ldr\\t%2, %1\;str\\t%2, %0\;mov\t%2, #0"
+ [(set_attr "length" "12")
+ (set_attr "conds" "unconditional")
+ (set_attr "type" "multiple")]
+)
+
+(define_expand "stack_protect_test"
+ [(match_operand:SI 0 "memory_operand")
+ (match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2)]
+ "arm_stack_protector_guard == SSP_TLSREG"
+ "
+{
+ operands[1] = arm_stack_protect_tls_canary_mem (true /* reload */);
+ emit_insn (gen_stack_protect_test_tls (operands[0], operands[1]));
+
+ rtx cc_reg = gen_rtx_REG (CC_Zmode, CC_REGNUM);
+ rtx eq = gen_rtx_EQ (CC_Zmode, cc_reg, const0_rtx);
+ emit_jump_insn (gen_arm_cond_branch (operands[2], eq, cc_reg));
+ DONE;
+}"
+)
+
+(define_insn "stack_protect_test_tls"
+ [(set (reg:CC_Z CC_REGNUM)
+ (compare:CC_Z (unspec:SI [(match_operand:SI 0 "memory_operand" "m")
+ (match_operand:SI 1 "memory_operand" "m")]
+ UNSPEC_SP_TEST)
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 "=&r"))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ ""
+ "ldr\t%2, %0\;ldr\t%3, %1\;eors\t%2, %3, %2\;mov\t%3, #0"
+ [(set_attr "length" "16")
+ (set_attr "conds" "set")
+ (set_attr "type" "multiple")]
+)
+
(define_expand "casesi"
[(match_operand:SI 0 "s_register_operand") ; index to jump on
(match_operand:SI 1 "const_int_operand") ; lower bound
(set_attr "type" "mrs")]
)
+;; Used by the TLS register based stack protector
+(define_insn "reload_tp_hard"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] VUNSPEC_MRC))]
+ "TARGET_HARD_TP"
+ "mrc\\tp15, 0, %0, c13, c0, 3\\t@ reload_tp_hard"
+ [(set_attr "type" "mrs")]
+)
+
;; Doesn't clobber R1-R3. Must use r0 for the first operand.
(define_insn "load_tp_soft_fdpic"
[(set (reg:SI 0) (unspec:SI [(const_int 0)] UNSPEC_TLS))
mfdpic
Target Mask(FDPIC)
Enable Function Descriptor PIC mode.
+
+mstack-protector-guard=
+Target RejectNegative Joined Enum(stack_protector_guard) Var(arm_stack_protector_guard) Init(SSP_GLOBAL)
+Use given stack-protector guard.
+
+Enum
+Name(stack_protector_guard) Type(enum stack_protector_guard)
+Valid arguments to -mstack-protector-guard=:
+
+EnumValue
+Enum(stack_protector_guard) String(tls) Value(SSP_TLSREG)
+
+EnumValue
+Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
+
+mstack-protector-guard-offset=
+Target Joined RejectNegative String Var(arm_stack_protector_guard_offset_str)
+Use an immediate to offset from the TLS register. This option is for use with
+fstack-protector-guard=tls and not for use in user-land code.
+
+TargetVariable
+long arm_stack_protector_guard_offset = 0
-mpure-code @gol
-mcmse @gol
-mfix-cmse-cve-2021-35465 @gol
+-mstack-protector-guard=@var{guard} -mstack-protector-guard-offset=@var{offset} @gol
-mfdpic}
@emph{AVR Options}
@code{cortex-m33}, @code{cortex-m35p} or @code{cortex-m55}. The option
@option{-mno-fix-cmse-cve-2021-35465} can be used to disable the mitigation.
+@item -mstack-protector-guard=@var{guard}
+@itemx -mstack-protector-guard-offset=@var{offset}
+@opindex mstack-protector-guard
+@opindex mstack-protector-guard-offset
+Generate stack protection code using canary at @var{guard}. Supported
+locations are @samp{global} for a global canary or @samp{tls} for a
+canary accessible via the TLS register. The option
+@option{-mstack-protector-guard-offset=} is for use with
+@option{-fstack-protector-guard=tls} and not for use in user-land code.
+
@item -mfdpic
@itemx -mno-fdpic
@opindex mfdpic
--- /dev/null
+/* { dg-require-effective-target arm_hard_vfp_ok } */
+/* { dg-require-effective-target arm_arch_v7a_ok } */
+/* { dg-do compile } */
+/* { dg-options "-march=armv7-a -mfpu=vfp -fstack-protector-all -Os -mstack-protector-guard=tls -mstack-protector-guard-offset=1296 -mtp=cp15" } */
+
+#include "stack-protector-5.c"
+
+/* See the comment in stack-protector-5.c. */
+/* { dg-final { scan-assembler-times {\tstr\t} 1 } } */
+/* Expect two TLS register accesses and two occurrences of the offset */
+/* { dg-final { scan-assembler-times {\tmrc\t} 2 } } */
+/* { dg-final { scan-assembler-times {1296} 2 } } */
--- /dev/null
+/* { dg-require-effective-target arm_hard_vfp_ok } */
+/* { dg-require-effective-target arm_arch_v7a_ok } */
+/* { dg-do compile } */
+/* { dg-error "needs a hardware TLS register" "missing error when using TLS stack protector without hardware TLS register" { target *-*-* } 0 } */
+/* { dg-options "-fstack-protector-all -Os -mstack-protector-guard=tls -mtp=soft" } */
+
+int foo;