aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Schulze Frielinghaus <stefansf@gcc.gnu.org>2025-07-08 16:40:34 +0200
committerStefan Schulze Frielinghaus <stefansf@gcc.gnu.org>2025-07-08 16:40:34 +0200
commitbb6075e7115208bab3d9c8b2c54e0bd6a5c808b7 (patch)
treea0900efaf76e5ba19981ff8c93ea2ce75045df3d
parenta543fcbb72f014f146f5804c963bb9dfd936e50b (diff)
downloadgcc-master.zip
gcc-master.tar.gz
gcc-master.tar.bz2
s390: Always compute address of stack protector guardHEADtrunkmaster
Computing the address of the thread pointer on s390 involves multiple instructions and therefore bears the risk that the address of the canary or intermediate values of it are spilled after prologue in order to be reloaded for the epilogue. Since there exists no mechanism to ensure that a value is not coming from stack, as a precaution compute the address always twice, i.e., one time for the prologue and one time for the epilogue. Note, even if there were such a mechanism, emitting optimal code is non-trivial since there exist cases with opposing requirements as e.g. if the thread pointer is not only computed for the TLS guard but also for other TLS objects. For the latter accesses it is desired to spill and reload the thread pointer instead of recomputing it whereas for the former it is not. gcc/ChangeLog: * config/s390/s390.md (stack_protect_get_tpsi): New insn. (stack_protect_get_tpdi): New insn. (stack_protect_set): Use new insn. (stack_protect_test): Use new insn. gcc/testsuite/ChangeLog: * gcc.target/s390/stack-protector-guard-tls-1.c: New test.
-rw-r--r--gcc/config/s390/s390.md47
-rw-r--r--gcc/testsuite/gcc.target/s390/stack-protector-guard-tls-1.c39
2 files changed, 82 insertions, 4 deletions
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index f6db36e..02bc149 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -308,6 +308,9 @@
UNSPECV_SPLIT_STACK_CALL
UNSPECV_OSC_BREAK
+
+ ; Stack Protector
+ UNSPECV_SP_GET_TP
])
;;
@@ -365,6 +368,9 @@
(VR23_REGNUM 45)
(VR24_REGNUM 46)
(VR31_REGNUM 53)
+ ; Access registers
+ (AR0_REGNUM 36)
+ (AR1_REGNUM 37)
])
; Rounding modes for binary floating point numbers
@@ -11924,15 +11930,43 @@
; Stack Protector Patterns
;
+; 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.
+
+(define_insn_and_split "stack_protect_get_tpsi"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (unspec_volatile:SI [(const_int 0)] UNSPECV_SP_GET_TP))]
+ ""
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0) (reg:SI AR0_REGNUM))])
+
+(define_insn_and_split "stack_protect_get_tpdi"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (unspec_volatile:DI [(const_int 0)] UNSPECV_SP_GET_TP))]
+ ""
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 1) (reg:SI AR0_REGNUM))
+ (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32)))
+ (set (strict_low_part (match_dup 1)) (reg:SI AR1_REGNUM))]
+ "operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]));")
+
(define_expand "stack_protect_set"
[(set (match_operand 0 "memory_operand" "")
(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));
+ else
+ emit_insn (gen_stack_protect_get_tpsi (tp));
operands[1]
- = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (),
- GEN_INT (TARGET_THREAD_SSP_OFFSET)));
+ = 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]));
@@ -11958,9 +11992,14 @@
{
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));
+ else
+ emit_insn (gen_stack_protect_get_tpsi (tp));
operands[1]
- = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (),
- GEN_INT (TARGET_THREAD_SSP_OFFSET)));
+ = 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]));
diff --git a/gcc/testsuite/gcc.target/s390/stack-protector-guard-tls-1.c b/gcc/testsuite/gcc.target/s390/stack-protector-guard-tls-1.c
new file mode 100644
index 0000000..1efd245
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/stack-protector-guard-tls-1.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-protector-all" } */
+/* { dg-final { scan-assembler-times {\tear\t%r[0-9]+,%a[01]} 8 { target lp64 } } } */
+/* { dg-final { scan-assembler-times {\tsllg\t%r[0-9]+,%r[0-9]+,32} 4 { target lp64 } } } */
+/* { dg-final { scan-assembler-times {\tear\t%r[0-9]+,%a[01]} 3 { target { ! lp64 } } } } */
+/* { dg-final { scan-assembler-times {\tmvc\t160\(8,%r15\),40\(%r[0-9]+\)} 2 { target lp64 } } } */
+/* { dg-final { scan-assembler-times {\tmvc\t100\(4,%r15\),20\(%r[0-9]+\)} 2 { target { ! lp64 } } } } */
+/* { dg-final { scan-assembler-times {\tclc\t160\(8,%r15\),40\(%r[0-9]+\)} 2 { target lp64 } } } */
+/* { dg-final { scan-assembler-times {\tclc\t100\(4,%r15\),20\(%r[0-9]+\)} 2 { target { ! lp64 } } } } */
+
+/* Computing the address of the thread pointer on s390 involves multiple
+ instructions and therefore bears the risk that the address of the canary or
+ intermediate values of it are spilled and reloaded. Therefore, as a
+ precaution compute the address always twice, i.e., one time for the prologue
+ and one time for the epilogue. */
+
+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");
+}