https://gcc.gnu.org/g:0cd1f03939d57a71bcfaad6ad051e16aadd4d58d

commit r16-5192-g0cd1f03939d57a71bcfaad6ad051e16aadd4d58d
Author: Stefan Schulze Frielinghaus <[email protected]>
Date:   Wed Nov 12 11:24:38 2025 +0100

    s390: Support global stack protector
    
    So far only a per thread canary in the TLS block is supported.  This
    patch adds support for a global canary, too.  For this the new option
    -mstack-protector-guard={global,tls} is added which defaults to tls.
    
    The global canary is expected at symbol __stack_chk_guard which means
    for a function prologue instructions larl/l(g)fr + mvc are emitted and
    for an epilogue larl/l(g)fr + clc.
    
    Furthermore, option -mstack-protector-guard-record is added which is
    inspired by -mrecord-mcount and generates section __stack_protector_loc
    containing pointers to all instructions which load the address of the
    global guard.  Thus, this option has only an effect in conjunction with
    -mstack-protector-guard=global.  The intended use is for the Linux
    kernel in order to support run-time patching.  In each task_struct of
    the kernel a canary is held which will be copied into the lowcore.
    Since the kernel supports migration of the lowcore at boot time,
    addresses are not necessarily constant.  Therefore, the kernel expects
    that all instructions loading the address of the canary to be of format
    RIL or more precisely are either larl or lgrl and that the instructions
    addresses are recorded in section __stack_protector_loc.  The kernel is
    then required to patch those instructions e.g. to llilf during boot.
    
    In total this means -mstack-protector-guard=global emits code suitable
    for user and kernel space.
    
    gcc/ChangeLog:
    
            * config/s390/s390-opts.h (enum stack_protector_guard): Define
            SP_TLS and SP_GLOBAL.
            * config/s390/s390.h (TARGET_SP_GLOBAL_GUARD): Define predicate.
            (TARGET_SP_TLS_GUARD): Define predicate.
            * config/s390/s390.md (stack_protect_global_guard_addr<mode>):
            New insn.
            (stack_protect_set): Also deal with a global guard.
            (stack_protect_test): Also deal with a global guard.
            * config/s390/s390.opt (-mstack-protector-guard={global,tls}):
            New option.
            (-mstack-protector-guard-record) New option.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/s390/stack-protector-guard-global-1.c: New test.
            * gcc.target/s390/stack-protector-guard-global-2.c: New test.
            * gcc.target/s390/stack-protector-guard-global-3.c: New test.
            * gcc.target/s390/stack-protector-guard-global-4.c: New test.

Diff:
---
 gcc/config/s390/s390-opts.h                        |  8 ++
 gcc/config/s390/s390.h                             |  3 +
 gcc/config/s390/s390.md                            | 87 ++++++++++++++++++----
 gcc/config/s390/s390.opt                           | 18 +++++
 .../s390/stack-protector-guard-global-1.c          | 27 +++++++
 .../s390/stack-protector-guard-global-2.c          |  5 ++
 .../s390/stack-protector-guard-global-3.c          |  6 ++
 .../s390/stack-protector-guard-global-4.c          |  6 ++
 8 files changed, 144 insertions(+), 16 deletions(-)

diff --git a/gcc/config/s390/s390-opts.h b/gcc/config/s390/s390-opts.h
index 9cacb2c29d1c..29dd4a5f77f6 100644
--- a/gcc/config/s390/s390-opts.h
+++ b/gcc/config/s390/s390-opts.h
@@ -53,4 +53,12 @@ enum indirect_branch {
   indirect_branch_thunk_inline,
   indirect_branch_thunk_extern
 };
+
+
+/* Where to get the canary for the stack protector.  */
+enum stack_protector_guard
+{
+  SP_TLS,       /* per-thread canary in TLS block */
+  SP_GLOBAL     /* global canary */
+};
 #endif
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 6478be8c7acd..a5a3db0bb21d 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -251,6 +251,9 @@ enum processor_flags
    && (s390_tune < PROCESSOR_2964_Z13 || (VAL) != const0_rtx)          \
    && (!CONST_INT_P (LEN) || INTVAL ((LEN)) > TARGET_SETMEM_PREFETCH_DISTANCE))
 
+#define TARGET_SP_GLOBAL_GUARD (s390_stack_protector_guard == SP_GLOBAL)
+#define TARGET_SP_TLS_GUARD    (s390_stack_protector_guard == SP_TLS)
+
 /* Run-time target specification.  */
 
 /* Defaults for option flags defined only on some subtargets.  */
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 06876a5563a9..db02bd425d74 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -312,6 +312,7 @@
 
    ; Stack Protector
    UNSPECV_SP_GET_TP
+   UNSPECV_SP_GLOBAL_GUARD_ADDR
   ])
 
 ;;
@@ -12059,6 +12060,36 @@
 ; Stack Protector Patterns
 ;
 
+(define_insn "stack_protect_global_guard_addr<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+       (unspec_volatile:P [(const_int 0)] UNSPECV_SP_GLOBAL_GUARD_ADDR))]
+  ""
+{
+  if (flag_s390_stack_protector_guard_record)
+    fprintf (asm_out_file, "1:\n");
+  if (flag_pic)
+    {
+      if (TARGET_Z10)
+       output_asm_insn ("l<g>rl\t%0,__stack_chk_guard@GOTENT", operands);
+      else
+       {
+         output_asm_insn ("larl\t%0,__stack_chk_guard@GOTENT", operands);
+         output_asm_insn ("l<g>\t%0,0(%0)", operands);
+       }
+    }
+  else
+    output_asm_insn ("larl\t%0,__stack_chk_guard", operands);
+  if (flag_s390_stack_protector_guard_record)
+    fprintf (asm_out_file, "\t.section 
__stack_protector_loc,\\"a\\",@progbits\n"
+                          "\t.%s 1b\n"
+                          "\t.previous\n", TARGET_64BIT ? "quad" : "long");
+  return "";
+}
+  [(set (attr "mnemonic")
+       (cond [(match_test "flag_pic &&  TARGET_Z10") (const_string "l<g>rl")
+              (match_test "flag_pic && !TARGET_Z10") (const_string "*")]
+             (const_string "larl")))])
+
 ; Insns stack_protect_get_tp{si,di} are similar to *get_tp_{31,64} but still
 ; distinct in the sense that they force recomputation of the thread pointer
 ; instead of potentially reloading it from stack.
@@ -12087,16 +12118,28 @@
        (match_operand 1 "memory_operand" ""))]
   ""
 {
-#ifdef TARGET_THREAD_SSP_OFFSET
-  rtx tp = gen_reg_rtx (Pmode);
-  if (TARGET_64BIT)
-    emit_insn (gen_stack_protect_get_tpdi (tp));
+  if (TARGET_SP_GLOBAL_GUARD)
+    {
+      rtx addr = gen_reg_rtx (Pmode);
+      if (TARGET_64BIT)
+       emit_insn (gen_stack_protect_global_guard_addrdi (addr));
+      else
+       emit_insn (gen_stack_protect_global_guard_addrsi (addr));
+      operands[1] = gen_rtx_MEM (Pmode, addr);
+    }
   else
-    emit_insn (gen_stack_protect_get_tpsi (tp));
-  operands[1]
-    = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tp,
-                                       GEN_INT (TARGET_THREAD_SSP_OFFSET)));
+    {
+#ifdef TARGET_THREAD_SSP_OFFSET
+      rtx tp = gen_reg_rtx (Pmode);
+      if (TARGET_64BIT)
+       emit_insn (gen_stack_protect_get_tpdi (tp));
+      else
+       emit_insn (gen_stack_protect_get_tpsi (tp));
+      operands[1]
+       = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tp,
+                                           GEN_INT 
(TARGET_THREAD_SSP_OFFSET)));
 #endif
+    }
   if (TARGET_64BIT)
     emit_insn (gen_stack_protect_setdi (operands[0], operands[1]));
   else
@@ -12120,16 +12163,28 @@
   ""
 {
   rtx cc_reg, test;
-#ifdef TARGET_THREAD_SSP_OFFSET
-  rtx tp = gen_reg_rtx (Pmode);
-  if (TARGET_64BIT)
-    emit_insn (gen_stack_protect_get_tpdi (tp));
+  if (TARGET_SP_GLOBAL_GUARD)
+    {
+      rtx addr = gen_reg_rtx (Pmode);
+      if (TARGET_64BIT)
+       emit_insn (gen_stack_protect_global_guard_addrdi (addr));
+      else
+       emit_insn (gen_stack_protect_global_guard_addrsi (addr));
+      operands[1] = gen_rtx_MEM (Pmode, addr);
+    }
   else
-    emit_insn (gen_stack_protect_get_tpsi (tp));
-  operands[1]
-    = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tp,
-                                       GEN_INT (TARGET_THREAD_SSP_OFFSET)));
+    {
+#ifdef TARGET_THREAD_SSP_OFFSET
+      rtx tp = gen_reg_rtx (Pmode);
+      if (TARGET_64BIT)
+       emit_insn (gen_stack_protect_get_tpdi (tp));
+      else
+       emit_insn (gen_stack_protect_get_tpsi (tp));
+      operands[1]
+       = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tp,
+                                           GEN_INT 
(TARGET_THREAD_SSP_OFFSET)));
 #endif
+    }
   if (TARGET_64BIT)
     emit_insn (gen_stack_protect_testdi (operands[0], operands[1]));
   else
diff --git a/gcc/config/s390/s390.opt b/gcc/config/s390/s390.opt
index 6753a9326be2..a82992ef7efb 100644
--- a/gcc/config/s390/s390.opt
+++ b/gcc/config/s390/s390.opt
@@ -196,6 +196,24 @@ mno-stack-guard
 Target RejectNegative Alias(mstack-guard=,0) Negative(mstack-guard=)
 Switches off the -mstack-guard= option.
 
+mstack-protector-guard=
+Target RejectNegative Joined Enum(stack_protector_guard) 
Var(s390_stack_protector_guard) Init(SP_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(SP_TLS)
+
+EnumValue
+Enum(stack_protector_guard) String(global) Value(SP_GLOBAL)
+
+mstack-protector-guard-record
+Target Var(flag_s390_stack_protector_guard_record)
+Generate section __stack_protector_loc containing pointers to all instructions 
which load the address of the global guard.
+
 mstack-size=
 Target RejectNegative Joined UInteger Var(s390_stack_size) Save
 Emit extra code in the function prologue in order to trap if the stack size 
exceeds the given limit.
diff --git a/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-1.c 
b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-1.c
new file mode 100644
index 000000000000..f276645adcb1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-1.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global 
-mstack-protector-guard-record" } */
+/* { dg-final { scan-assembler-times 
{\n1:\n\tlarl\t%r[0-9]+,__stack_chk_guard\n} 4 } } */
+
+void test_0 (void) { }
+
+void test_1 (void)
+{
+  __asm__ __volatile ("" :::
+      "r0",
+      "r1",
+      "r2",
+      "r3",
+      "r4",
+      "r5",
+      "r6",
+      "r7",
+      "r8",
+      "r9",
+      "r10",
+      "r11",
+#ifndef __PIC__
+      "r12",
+#endif
+      "r13",
+      "r14");
+}
diff --git a/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-2.c 
b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-2.c
new file mode 100644
index 000000000000..7441a87adf7a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-2.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global 
-mstack-protector-guard-record -fPIC" } */
+/* { dg-final { scan-assembler-times 
{\n1:\n\t(larl|lg?rl)\t%r[0-9]+,__stack_chk_guard@GOTENT\n} 4 } } */
+
+#include "stack-protector-guard-global-1.c"
diff --git a/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-3.c 
b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-3.c
new file mode 100644
index 000000000000..4ef379aa8f7e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-3.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global" } */
+/* { dg-final { scan-assembler-times {\tlarl\t%r[0-9]+,__stack_chk_guard\n} 4 
} } */
+/* { dg-final { scan-assembler-not {\n1:\n} } } */
+
+#include "stack-protector-guard-global-1.c"
diff --git a/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-4.c 
b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-4.c
new file mode 100644
index 000000000000..d57fc79bd833
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/stack-protector-guard-global-4.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-protector-all -mstack-protector-guard=global 
-fPIC" } */
+/* { dg-final { scan-assembler-times 
{\t(larl|lg?rl)\t%r[0-9]+,__stack_chk_guard@GOTENT\n} 4 } } */
+/* { dg-final { scan-assembler-not {\n1:\n} } } */
+
+#include "stack-protector-guard-global-1.c"

Reply via email to