aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamana Radhakrishnan <ramana.radhakrishnan@arm.com>2019-01-18 10:32:40 +0000
committerRamana Radhakrishnan <ramana@gcc.gnu.org>2019-01-18 10:32:40 +0000
commitcd0b2d361df82c848dc7e1c3078651bb0624c3c6 (patch)
tree9bf64856b6da788ce37851a53348ede044c34ba9
parentd0bf921f6a0b8ffdad74fa5eb5ddf2e70a9acfd6 (diff)
downloadgcc-cd0b2d361df82c848dc7e1c3078651bb0624c3c6.zip
gcc-cd0b2d361df82c848dc7e1c3078651bb0624c3c6.tar.gz
gcc-cd0b2d361df82c848dc7e1c3078651bb0624c3c6.tar.bz2
[AArch64] Add support for system register based stack protector canary access
2019-01-18 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com> * config/aarch64/aarch64-opts.h (enum stack_protector_guard): New * config/aarch64/aarch64.c (aarch64_override_options_internal): Handle and put in error checks for stack protector guard options. (aarch64_stack_protect_guard): New. (TARGET_STACK_PROTECT_GUARD): Define. * config/aarch64/aarch64.md (UNSPEC_SSP_SYSREG): New. (reg_stack_protect_address<mode>): New. (stack_protect_set): Adjust for SSP_GLOBAL. (stack_protect_test): Likewise. * config/aarch64/aarch64.opt (-mstack-protector-guard-reg): New. (-mstack-protector-guard): Likewise. (-mstack-protector-guard-offset): Likewise. From-SVN: r268068
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/config/aarch64/aarch64-opts.h6
-rw-r--r--gcc/config/aarch64/aarch64.c51
-rw-r--r--gcc/config/aarch64/aarch64.md64
-rw-r--r--gcc/config/aarch64/aarch64.opt30
-rw-r--r--gcc/doc/invoke.texi40
6 files changed, 201 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a16deb6..6dbff4b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2019-01-18 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
+
+ * config/aarch64/aarch64-opts.h (enum stack_protector_guard): New
+ * config/aarch64/aarch64.c (aarch64_override_options_internal): Handle
+ and put in error checks for stack protector guard options.
+ (aarch64_stack_protect_guard): New.
+ (TARGET_STACK_PROTECT_GUARD): Define.
+ * config/aarch64/aarch64.md (UNSPEC_SSP_SYSREG): New.
+ (reg_stack_protect_address<mode>): New.
+ (stack_protect_set): Adjust for SSP_GLOBAL.
+ (stack_protect_test): Likewise.
+ * config/aarch64/aarch64.opt (-mstack-protector-guard-reg): New.
+ (-mstack-protector-guard): Likewise.
+ (-mstack-protector-guard-offset): Likewise.
+
2019-01-18 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/86214
diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h
index 7982de1..4b07d29 100644
--- a/gcc/config/aarch64/aarch64-opts.h
+++ b/gcc/config/aarch64/aarch64-opts.h
@@ -92,4 +92,10 @@ enum aarch64_sve_vector_bits_enum {
SVE_2048 = 2048
};
+/* Where to get the canary for the stack protector. */
+enum stack_protector_guard {
+ SSP_SYSREG, /* per-thread canary in special system register */
+ SSP_GLOBAL /* global canary */
+};
+
#endif
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 7eb9316..e13bada 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -11409,6 +11409,41 @@ aarch64_override_options_internal (struct gcc_options *opts)
if (opts->x_flag_strict_volatile_bitfields < 0 && abi_version_at_least (2))
opts->x_flag_strict_volatile_bitfields = 1;
+ if (aarch64_stack_protector_guard == SSP_GLOBAL
+ && opts->x_aarch64_stack_protector_guard_offset_str)
+ {
+ error ("incompatible options -mstack-protector-guard=global and"
+ "-mstack-protector-guard-offset=%qs",
+ aarch64_stack_protector_guard_offset_str);
+ }
+
+ if (aarch64_stack_protector_guard == SSP_SYSREG
+ && !(opts->x_aarch64_stack_protector_guard_offset_str
+ && opts->x_aarch64_stack_protector_guard_reg_str))
+ {
+ error ("both -mstack-protector-guard-offset and "
+ "-mstack-protector-guard-reg must be used "
+ "with -mstack-protector-guard=sysreg");
+ }
+
+ if (opts->x_aarch64_stack_protector_guard_reg_str)
+ {
+ if (strlen (opts->x_aarch64_stack_protector_guard_reg_str) > 100)
+ error ("specify a system register with a small string length.");
+ }
+
+ if (opts->x_aarch64_stack_protector_guard_offset_str)
+ {
+ char *end;
+ const char *str = aarch64_stack_protector_guard_offset_str;
+ errno = 0;
+ long offs = strtol (aarch64_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=");
+ aarch64_stack_protector_guard_offset = offs;
+ }
+
initialize_aarch64_code_model (opts);
initialize_aarch64_tls_size (opts);
@@ -18671,8 +18706,24 @@ aarch64_run_selftests (void)
} // namespace selftest
+/* Implement TARGET_STACK_PROTECT_GUARD. In case of a
+ global variable based guard use the default else
+ return a null tree. */
+static tree
+aarch64_stack_protect_guard (void)
+{
+ if (aarch64_stack_protector_guard == SSP_GLOBAL)
+ return default_stack_protect_guard ();
+
+ return NULL_TREE;
+}
+
+
#endif /* #if CHECKING_P */
+#undef TARGET_STACK_PROTECT_GUARD
+#define TARGET_STACK_PROTECT_GUARD aarch64_stack_protect_guard
+
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST aarch64_address_cost
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 522c774..b7f6fe0 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -201,6 +201,7 @@
UNSPEC_UCVTF
UNSPEC_USHL_2S
UNSPEC_VSTRUCTDUMMY
+ UNSPEC_SSP_SYSREG
UNSPEC_SP_SET
UNSPEC_SP_TEST
UNSPEC_RSQRT
@@ -6774,13 +6775,46 @@
""
{
machine_mode mode = GET_MODE (operands[0]);
+ if (aarch64_stack_protector_guard != SSP_GLOBAL)
+ {
+ /* Generate access through the system register. */
+ rtx tmp_reg = gen_reg_rtx (mode);
+ if (mode == DImode)
+ {
+ emit_insn (gen_reg_stack_protect_address_di (tmp_reg));
+ emit_insn (gen_adddi3 (tmp_reg, tmp_reg,
+ GEN_INT (aarch64_stack_protector_guard_offset)));
+ }
+ else
+ {
+ emit_insn (gen_reg_stack_protect_address_si (tmp_reg));
+ emit_insn (gen_addsi3 (tmp_reg, tmp_reg,
+ GEN_INT (aarch64_stack_protector_guard_offset)));
+ }
+ operands[1] = gen_rtx_MEM (mode, tmp_reg);
+ }
+
emit_insn ((mode == DImode
? gen_stack_protect_set_di
: gen_stack_protect_set_si) (operands[0], operands[1]));
DONE;
})
+(define_insn "reg_stack_protect_address_<mode>"
+ [(set (match_operand:PTR 0 "register_operand" "=r")
+ (unspec:PTR [(const_int 0)]
+ UNSPEC_SSP_SYSREG))]
+ "aarch64_stack_protector_guard != SSP_GLOBAL"
+ {
+ char buf[150];
+ snprintf (buf, 150, "mrs\\t%%<w>0, %s",
+ aarch64_stack_protector_guard_reg_str);
+ output_asm_insn (buf, operands);
+ return "";
+ }
+ [(set_attr "type" "mrs")])
+
(define_insn "stack_protect_set_<mode>"
[(set (match_operand:PTR 0 "memory_operand" "=m")
(unspec:PTR [(match_operand:PTR 1 "memory_operand" "m")]
@@ -6801,12 +6835,34 @@
machine_mode mode = GET_MODE (operands[0]);
result = gen_reg_rtx(mode);
+ if (aarch64_stack_protector_guard != SSP_GLOBAL)
+ {
+ /* Generate access through the system register. The
+ sequence we want here is the access
+ of the stack offset to come with
+ mrs scratch_reg, <system_register>
+ add scratch_reg, scratch_reg, :lo12:offset. */
+ rtx tmp_reg = gen_reg_rtx (mode);
+ if (mode == DImode)
+ {
+ emit_insn (gen_reg_stack_protect_address_di (tmp_reg));
+ emit_insn (gen_adddi3 (tmp_reg, tmp_reg,
+ GEN_INT (aarch64_stack_protector_guard_offset)));
+ }
+ else
+ {
+ emit_insn (gen_reg_stack_protect_address_si (tmp_reg));
+ emit_insn (gen_addsi3 (tmp_reg, tmp_reg,
+ GEN_INT (aarch64_stack_protector_guard_offset)));
+ }
+ operands[1] = gen_rtx_MEM (mode, tmp_reg);
+ }
emit_insn ((mode == DImode
- ? gen_stack_protect_test_di
- : gen_stack_protect_test_si) (result,
- operands[0],
- operands[1]));
+ ? gen_stack_protect_test_di
+ : gen_stack_protect_test_si) (result,
+ operands[0],
+ operands[1]));
if (mode == DImode)
emit_jump_insn (gen_cbranchdi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index 6de7b22..5a1e687 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -225,3 +225,33 @@ Enables verbose cost model dumping in the debug dump files.
mtrack-speculation
Target Var(aarch64_track_speculation)
Generate code to track when the CPU might be speculating incorrectly.
+
+mstack-protector-guard=
+Target RejectNegative Joined Enum(stack_protector_guard) Var(aarch64_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(sysreg) Value(SSP_SYSREG)
+
+EnumValue
+Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
+
+mstack-protector-guard-reg=
+Target Joined RejectNegative String Var(aarch64_stack_protector_guard_reg_str)
+Use the system register specified on the command line as the stack protector
+guard register. This option is for use with fstack-protector-strong and
+not for use in user-land code.
+
+mstack-protector-guard-offset=
+Target Joined RejectNegative String Var(aarch64_stack_protector_guard_offset_str)
+Use an immediate to offset from the stack protector guard register, sp_el0.
+This option is for use with fstack-protector-strong and not for use in
+user-land code.
+
+TargetVariable
+long aarch64_stack_protector_guard_offset = 0
+
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1151708..9997dcb 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -633,7 +633,9 @@ Objective-C and Objective-C++ Dialects}.
-msign-return-address=@var{scope} @gol
-mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}] @gol
-march=@var{name} -mcpu=@var{name} -mtune=@var{name} @gol
--moverride=@var{string} -mverbose-cost-dump -mtrack-speculation}
+-moverride=@var{string} -mverbose-cost-dump @gol
+-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{sysreg} @gol
+-mstack-protector-guard-offset=@var{offset} -mtrack-speculation }
@emph{Adapteva Epiphany Options}
@gccoptlist{-mhalf-reg-file -mprefer-short-insn-regs @gol
@@ -15606,6 +15608,42 @@ object boundary as described in the architecture specification.
Omit or keep the frame pointer in leaf functions. The former behavior is the
default.
+@item -mstack-protector-guard=@var{guard}
+@itemx -mstack-protector-guard-reg=@var{reg}
+@itemx -mstack-protector-guard-offset=@var{offset}
+@opindex mstack-protector-guard
+@opindex mstack-protector-guard-reg
+@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{sysreg} for a
+canary in an appropriate system register.
+
+With the latter choice the options
+@option{-mstack-protector-guard-reg=@var{reg}} and
+@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
+which system register to use as base register for reading the canary,
+and from what offset from that base register. There is no default
+register or offset as this is entirely for use within the Linux
+kernel.
+
+@item -mstack-protector-guard=@var{guard}
+@itemx -mstack-protector-guard-reg=@var{reg}
+@itemx -mstack-protector-guard-offset=@var{offset}
+@opindex mstack-protector-guard
+@opindex mstack-protector-guard-reg
+@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{sysreg} for a
+canary in an appropriate system register.
+
+With the latter choice the options
+@option{-mstack-protector-guard-reg=@var{reg}} and
+@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
+which system register to use as base register for reading the canary,
+and from what offset from that base register. There is no default
+register or offset as this is entirely for use within the Linux
+kernel.
+
@item -mtls-dialect=desc
@opindex mtls-dialect=desc
Use TLS descriptors as the thread-local storage mechanism for dynamic accesses