Committed as r16-5192-g0cd1f03939d and also mentioned in www docs in
commit 87741e98fd7b6ecc5b51aff9be2629e147d01724.

On Thu, Jul 10, 2025 at 04:16:44PM +0200, Stefan Schulze Frielinghaus wrote:
> 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, 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, prior first
> execution or whenever the lowcore moves.
> 
> 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.
> ---
>  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(-)
>  create mode 100644 
> gcc/testsuite/gcc.target/s390/stack-protector-guard-global-1.c
>  create mode 100644 
> gcc/testsuite/gcc.target/s390/stack-protector-guard-global-2.c
>  create mode 100644 
> gcc/testsuite/gcc.target/s390/stack-protector-guard-global-3.c
>  create mode 100644 
> gcc/testsuite/gcc.target/s390/stack-protector-guard-global-4.c
> 
> diff --git a/gcc/config/s390/s390-opts.h b/gcc/config/s390/s390-opts.h
> index 9cacb2c29d1..29dd4a5f77f 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 8b04bc9a755..2631788df4c 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 02bc149b0fb..2d3027e1574 100644
> --- a/gcc/config/s390/s390.md
> +++ b/gcc/config/s390/s390.md
> @@ -311,6 +311,7 @@
>  
>     ; Stack Protector
>     UNSPECV_SP_GET_TP
> +   UNSPECV_SP_GLOBAL_GUARD_ADDR
>    ])
>  
>  ;;
> @@ -11930,6 +11931,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.
> @@ -11958,16 +11989,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
> @@ -11991,16 +12034,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 6753a9326be..a82992ef7ef 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 00000000000..f276645adcb
> --- /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 00000000000..7441a87adf7
> --- /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 00000000000..4ef379aa8f7
> --- /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 00000000000..d57fc79bd83
> --- /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"
> -- 
> 2.49.0
> 

Reply via email to