diff mbox

-mstack-protector-guard and friends (PR78875)

Message ID eafa4ee2738cd103ac7854943616a06ad072652c.1484673719.git.segher@kernel.crashing.org
State New
Headers show

Commit Message

Segher Boessenkool Jan. 17, 2017, 5:43 p.m. UTC
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=<reg>
-mstack-protector-offset=<offset>
Load the canary from offset <off> from base register <reg>.


Bootstrap and test running.  Is this okay for trunk?


Segher


2017-01-17  Segher Boessenkool  <segher@kernel.crashing.org>

	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.

---
 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/gcc.target/powerpc/ssp-1.c |  6 ++++
 gcc/testsuite/gcc.target/powerpc/ssp-2.c |  6 ++++
 7 files changed, 142 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/ssp-1.c
 create mode 100644 gcc/testsuite/gcc.target/powerpc/ssp-2.c

Comments

Segher Boessenkool Jan. 17, 2017, 8:59 p.m. UTC | #1
On Tue, Jan 17, 2017 at 05:43:54PM +0000, Segher Boessenkool wrote:
> 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=<reg>
> -mstack-protector-offset=<offset>
> Load the canary from offset <off> from base register <reg>.
> 
> 
> Bootstrap and test running.  Is this okay for trunk?

No problems found on powerpc64-linux {-m32,-m64}.


Segher
David Edelsohn Jan. 17, 2017, 9:49 p.m. UTC | #2
On Tue, Jan 17, 2017 at 12:43 PM, Segher Boessenkool
<segher@kernel.crashing.org> wrote:
> 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=<reg>
> -mstack-protector-offset=<offset>
> Load the canary from offset <off> from base register <reg>.
>
>
> Bootstrap and test running.  Is this okay for trunk?
>
>
> Segher
>
>
> 2017-01-17  Segher Boessenkool  <segher@kernel.crashing.org>
>
>         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.

Okay.

Thanks, David
diff mbox

Patch

diff --git a/gcc/config/rs6000/rs6000-opts.h b/gcc/config/rs6000/rs6000-opts.h
index d58b980..086217a 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 d17a719..10632d6 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -4935,6 +4935,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 f7c1ab2..eb4eb29 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -11685,19 +11685,23 @@  (define_expand "cstore<mode>4"
 
 
 (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;
 })
 
@@ -11720,21 +11724,26 @@  (define_insn "stack_protect_setdi"
    (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 c806bf7..803753e 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 9fc0753..abee46d 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}
@@ -22191,6 +22193,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/gcc.target/powerpc/ssp-1.c b/gcc/testsuite/gcc.target/powerpc/ssp-1.c
new file mode 100644
index 0000000..018f690
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ssp-1.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+
+/* { dg-final { scan-assembler "__stack_chk_guard" } } */
+
+void f(void) { }
diff --git a/gcc/testsuite/gcc.target/powerpc/ssp-2.c b/gcc/testsuite/gcc.target/powerpc/ssp-2.c
new file mode 100644
index 0000000..6fa91f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ssp-2.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=tls -mstack-protector-guard-reg=r18 -mstack-protector-guard-offset=0x3038" } */
+
+/* { dg-final { scan-assembler {\m12344\(r?18\)} } } */
+
+void f(void) { }