From 1b3254e4bbe82245421a55324bc8fe34a99c6e3c Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 17 Jan 2017 23:02:42 +0100 Subject: [PATCH] -mstack-protector-guard and friends (PR78875) Currently, on PowerPC, code compiled with -fstack-protector will load the canary from -0x7010(13) (for -m64) or from -0x7008(2) (for -m32) if GCC was compiled against GNU libc 2.4 or newer or some other libc that supports -fstack-protector, and from the global variable __stack_chk_guard otherwise. This does not work well for Linux and other OS kernels and similar. For such non-standard applications, this patch creates a few new command-line options. The relevant new use cases are: -mstack-protector-guard=global Use the __stack_chk_guard variable, no matter how this GCC was configured. -mstack-protector-guard=tls Use the canary from TLS. This will error out if this GCC was built with a C library that does not support it. -mstack-protector-guard=tls -mstack-protector-register= -mstack-protector-offset= Load the canary from offset from base register . PR target/78875 * config/rs6000/rs6000-opts.h (stack_protector_guard): New enum. * config/rs6000/rs6000.c (rs6000_option_override_internal): Handle the new options. * config/rs6000/rs6000.md (stack_protect_set): Handle the new more flexible settings. (stack_protect_test): Ditto. * config/rs6000/rs6000.opt (mstack-protector-guard=, mstack-protector-guard-reg=, mstack-protector-guard-offset=): New options. * doc/invoke.texi (Option Summary) [RS/6000 and PowerPC Options]: Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and -mstack-protector-guard-offset=. (RS/6000 and PowerPC Options): Ditto. gcc/testsuite/ * gcc.target/powerpc/ssp-1.c: New testcase. * gcc.target/powerpc/ssp-2.c: New testcase. From-SVN: r244556 --- gcc/ChangeLog | 17 ++++++++++++ gcc/config/rs6000/rs6000-opts.h | 6 ++++ gcc/config/rs6000/rs6000.c | 48 ++++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000.md | 49 +++++++++++++++++++-------------- gcc/config/rs6000/rs6000.opt | 28 +++++++++++++++++++ gcc/doc/invoke.texi | 19 +++++++++++++ gcc/testsuite/ChangeLog | 6 ++++ 7 files changed, 153 insertions(+), 20 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 15a07182aa4..e2ea014ca28 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2017-01-17 Segher Boessenkool + + PR target/78875 + * config/rs6000/rs6000-opts.h (stack_protector_guard): New enum. + * config/rs6000/rs6000.c (rs6000_option_override_internal): Handle + the new options. + * config/rs6000/rs6000.md (stack_protect_set): Handle the new more + flexible settings. + (stack_protect_test): Ditto. + * config/rs6000/rs6000.opt (mstack-protector-guard=, + mstack-protector-guard-reg=, mstack-protector-guard-offset=): New + options. + * doc/invoke.texi (Option Summary) [RS/6000 and PowerPC Options]: + Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and + -mstack-protector-guard-offset=. + (RS/6000 and PowerPC Options): Ditto. + 2017-01-17 Uros Bizjak * config/i386/i386.h (MASK_CLASS_P): New define. diff --git a/gcc/config/rs6000/rs6000-opts.h b/gcc/config/rs6000/rs6000-opts.h index d58b98031d1..086217a37f7 100644 --- a/gcc/config/rs6000/rs6000-opts.h +++ b/gcc/config/rs6000/rs6000-opts.h @@ -154,6 +154,12 @@ enum rs6000_vector { VECTOR_OTHER /* Some other vector unit */ }; +/* Where to get the canary for the stack protector. */ +enum stack_protector_guard { + SSP_TLS, /* per-thread canary in TLS block */ + SSP_GLOBAL /* global canary */ +}; + /* No enumeration is defined to index the -mcpu= values (entries in processor_target_table), with the type int being used instead, but we need to distinguish the special "native" value. */ diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 63c62c39c49..72ef8e1e433 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -4942,6 +4942,54 @@ rs6000_option_override_internal (bool global_init_p) atoi (rs6000_sched_insert_nops_str)); } + /* Handle stack protector */ + if (!global_options_set.x_rs6000_stack_protector_guard) +#ifdef TARGET_THREAD_SSP_OFFSET + rs6000_stack_protector_guard = SSP_TLS; +#else + rs6000_stack_protector_guard = SSP_GLOBAL; +#endif + +#ifdef TARGET_THREAD_SSP_OFFSET + rs6000_stack_protector_guard_offset = TARGET_THREAD_SSP_OFFSET; + rs6000_stack_protector_guard_reg = TARGET_64BIT ? 13 : 2; +#endif + + if (global_options_set.x_rs6000_stack_protector_guard_offset_str) + { + char *endp; + const char *str = rs6000_stack_protector_guard_offset_str; + + errno = 0; + long offset = strtol (str, &endp, 0); + if (!*str || *endp || errno) + error ("%qs is not a valid number " + "in -mstack-protector-guard-offset=", str); + + if (!IN_RANGE (offset, -0x8000, 0x7fff) + || (TARGET_64BIT && (offset & 3))) + error ("%qs is not a valid offset " + "in -mstack-protector-guard-offset=", str); + + rs6000_stack_protector_guard_offset = offset; + } + + if (global_options_set.x_rs6000_stack_protector_guard_reg_str) + { + const char *str = rs6000_stack_protector_guard_reg_str; + int reg = decode_reg_name (str); + + if (!IN_RANGE (reg, 1, 31)) + error ("%qs is not a valid base register " + "in -mstack-protector-guard-reg=", str); + + rs6000_stack_protector_guard_reg = reg; + } + + if (rs6000_stack_protector_guard == SSP_TLS + && !IN_RANGE (rs6000_stack_protector_guard_reg, 1, 31)) + error ("-mstack-protector-guard=tls needs a valid base register"); + if (global_init_p) { #ifdef TARGET_REGNAMES diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index f00334a1d09..ff602fa2f93 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -11681,19 +11681,23 @@ (define_expand "stack_protect_set" - [(match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" "")] + [(match_operand 0 "memory_operand") + (match_operand 1 "memory_operand")] "" { -#ifdef TARGET_THREAD_SSP_OFFSET - rtx tlsreg = gen_rtx_REG (Pmode, TARGET_64BIT ? 13 : 2); - rtx addr = gen_rtx_PLUS (Pmode, tlsreg, GEN_INT (TARGET_THREAD_SSP_OFFSET)); - operands[1] = gen_rtx_MEM (Pmode, addr); -#endif + if (rs6000_stack_protector_guard == SSP_TLS) + { + rtx reg = gen_rtx_REG (Pmode, rs6000_stack_protector_guard_reg); + rtx offset = GEN_INT (rs6000_stack_protector_guard_offset); + rtx addr = gen_rtx_PLUS (Pmode, reg, offset); + operands[1] = gen_rtx_MEM (Pmode, addr); + } + if (TARGET_64BIT) emit_insn (gen_stack_protect_setdi (operands[0], operands[1])); else emit_insn (gen_stack_protect_setsi (operands[0], operands[1])); + DONE; }) @@ -11716,21 +11720,26 @@ (set_attr "length" "12")]) (define_expand "stack_protect_test" - [(match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" "") - (match_operand 2 "" "")] + [(match_operand 0 "memory_operand") + (match_operand 1 "memory_operand") + (match_operand 2 "")] "" { - rtx test, op0, op1; -#ifdef TARGET_THREAD_SSP_OFFSET - rtx tlsreg = gen_rtx_REG (Pmode, TARGET_64BIT ? 13 : 2); - rtx addr = gen_rtx_PLUS (Pmode, tlsreg, GEN_INT (TARGET_THREAD_SSP_OFFSET)); - operands[1] = gen_rtx_MEM (Pmode, addr); -#endif - op0 = operands[0]; - op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, operands[1]), UNSPEC_SP_TEST); - test = gen_rtx_EQ (VOIDmode, op0, op1); - emit_jump_insn (gen_cbranchsi4 (test, op0, op1, operands[2])); + rtx guard = operands[1]; + + if (rs6000_stack_protector_guard == SSP_TLS) + { + rtx reg = gen_rtx_REG (Pmode, rs6000_stack_protector_guard_reg); + rtx offset = GEN_INT (rs6000_stack_protector_guard_offset); + rtx addr = gen_rtx_PLUS (Pmode, reg, offset); + guard = gen_rtx_MEM (Pmode, addr); + } + + operands[1] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, guard), UNSPEC_SP_TEST); + rtx test = gen_rtx_EQ (VOIDmode, operands[0], operands[1]); + rtx jump = gen_cbranchsi4 (test, operands[0], operands[1], operands[2]); + emit_jump_insn (jump); + DONE; }) diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt index c806bf77b68..803753e627f 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -672,3 +672,31 @@ Enable default conversions between __float128 & long double. mvsx-small-integer Target Report Mask(VSX_SMALL_INTEGER) Var(rs6000_isa_flags) Enable small integers to be in VSX registers. + +mstack-protector-guard= +Target RejectNegative Joined Enum(stack_protector_guard) Var(rs6000_stack_protector_guard) Init(SSP_TLS) +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_TLS) + +EnumValue +Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL) + +mstack-protector-guard-reg= +Target RejectNegative Joined Var(rs6000_stack_protector_guard_reg_str) +Use the given base register for addressing the stack-protector guard. + +TargetVariable +int rs6000_stack_protector_guard_reg = 0 + +mstack-protector-guard-offset= +Target RejectNegative Joined Integer Var(rs6000_stack_protector_guard_offset_str) +Use the given offset for addressing the stack-protector guard. + +TargetVariable +long rs6000_stack_protector_guard_offset = 0 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e0624dac0d7..cac3d8bc65e 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1041,6 +1041,8 @@ See RS/6000 and PowerPC Options. -mupper-regs -mno-upper-regs @gol -mfloat128 -mno-float128 -mfloat128-hardware -mno-float128-hardware @gol -mgnu-attribute -mno-gnu-attribute @gol +-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} @gol +-mstack-protector-guard-offset=@var{offset} @gol -mlra -mno-lra} @emph{RX Options} @@ -22202,6 +22204,23 @@ that is compatible with functions compiled with older versions of GCC. The @option{-mno-compat-align-parm} option 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 global canary or @samp{tls} for per-thread +canary in the TLS block (the default with GNU libc version 2.4 or later). + +With the latter choice the options +@option{-mstack-protector-guard-reg=@var{reg}} and +@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify +which register to use as base register for reading the canary, and from what +offset from that base register. The default for those is as specified in the +relevant ABI. @end table @node RX Options diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index eb1e3cc56b5..ea74ebd2e03 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2017-01-17 Segher Boessenkool + + PR target/78875 + * gcc.target/powerpc/ssp-1.c: New testcase. + * gcc.target/powerpc/ssp-2.c: New testcase. + 2017-01-17 Wilco Dijkstra * gcc.target/aarch64/eh_return.c: New test. -- 2.30.2