From fa22fac534c6eb5c499d3fbbaa728a7ff1111b83 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Thu, 1 Feb 2018 09:32:34 -0700 Subject: [PATCH] - fix -fstack-clash-protection codegen issue on 32 bit x86 (#1540221, PR target/84128) --- gcc.spec | 8 +- gcc8-pr84128.patch | 180 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 gcc8-pr84128.patch diff --git a/gcc.spec b/gcc.spec index 21eb279..889d67d 100644 --- a/gcc.spec +++ b/gcc.spec @@ -4,7 +4,7 @@ %global gcc_major 8 # Note, gcc_release must be integer, if you want to add suffixes to # %{release}, append them after %{gcc_release} on Release: line. -%global gcc_release 0.8 +%global gcc_release 0.9 %global nvptx_tools_gitrev c28050f60193b3b95a18866a96f03334e874e78f %global nvptx_newlib_gitrev aadc8eb0ec43b7cd0dd2dfb484bae63c8b05ef24 %global _unpackaged_files_terminate_build 0 @@ -236,6 +236,7 @@ Patch10: gcc8-foffload-default.patch Patch11: gcc8-Wno-format-security.patch Patch12: gcc8-rh1512529-aarch64.patch Patch13: gcc8-pr84146.patch +Patch14: gcc8-pr84128.patch Patch1000: nvptx-tools-no-ptxas.patch Patch1001: nvptx-tools-build.patch @@ -775,6 +776,7 @@ to NVidia PTX capable devices if available. %patch11 -p0 -b .Wno-format-security~ %patch12 -p0 -b .rh1512529-aarch64~ %patch13 -p0 -b .pr84146~ +%patch14 -p0 -b .pr84128~ cd nvptx-tools-%{nvptx_tools_gitrev} %patch1000 -p1 -b .nvptx-tools-no-ptxas~ @@ -3036,6 +3038,10 @@ fi %endif %changelog +* Thu Feb 1 2018 Jeff Law 8.0.1-0.9 +- fix -fstack-clash-protection codegen issue on 32 bit x86 + (#1540221, PR target/84128) + * Wed Jan 31 2018 Jakub Jelinek 8.0.1-0.8 - update from the trunk - PRs c++/83993, c++/84092, c++/84138, c/84100, fortran/84088, diff --git a/gcc8-pr84128.patch b/gcc8-pr84128.patch new file mode 100644 index 0000000..454fc09 --- /dev/null +++ b/gcc8-pr84128.patch @@ -0,0 +1,180 @@ + + PR target/84128 + * config/i386/i386.c (release_scratch_register_on_entry): Add new + OFFSET and RELEASE_VIA_POP arguments. Use SP+OFFSET to restore + the scratch if RELEASE_VIA_POP is false. + (ix86_adjust_stack_and_probe_stack_clash): Un-constify SIZE. + If we have to save a temporary register, decrement SIZE appropriately. + Pass new arguments to release_scratch_register_on_entry. + (ix86_adjust_stack_and_probe): Likewise. + (ix86_emit_probe_stack_range): Pass new arguments to + release_scratch_register_on_entry. + + PR target/84128 + * gcc.target/i386/pr84128.c: New test. + +diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c +index fef34a1..3196ac4 100644 +--- gcc/config/i386/i386.c ++++ gcc/config/i386/i386.c +@@ -12567,22 +12567,39 @@ get_scratch_register_on_entry (struct scratch_reg *sr) + } + } + +-/* Release a scratch register obtained from the preceding function. */ ++/* Release a scratch register obtained from the preceding function. ++ ++ If RELEASE_VIA_POP is true, we just pop the register off the stack ++ to release it. This is what non-Linux systems use with -fstack-check. ++ ++ Otherwise we use OFFSET to locate the saved register and the ++ allocated stack space becomes part of the local frame and is ++ deallocated by the epilogue. */ + + static void +-release_scratch_register_on_entry (struct scratch_reg *sr) ++release_scratch_register_on_entry (struct scratch_reg *sr, HOST_WIDE_INT offset, ++ bool release_via_pop) + { + if (sr->saved) + { +- struct machine_function *m = cfun->machine; +- rtx x, insn = emit_insn (gen_pop (sr->reg)); ++ if (release_via_pop) ++ { ++ struct machine_function *m = cfun->machine; ++ rtx x, insn = emit_insn (gen_pop (sr->reg)); + +- /* The RTX_FRAME_RELATED_P mechanism doesn't know about pop. */ +- RTX_FRAME_RELATED_P (insn) = 1; +- x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (UNITS_PER_WORD)); +- x = gen_rtx_SET (stack_pointer_rtx, x); +- add_reg_note (insn, REG_FRAME_RELATED_EXPR, x); +- m->fs.sp_offset -= UNITS_PER_WORD; ++ /* The RX FRAME_RELATED_P mechanism doesn't know about pop. */ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (UNITS_PER_WORD)); ++ x = gen_rtx_SET (stack_pointer_rtx, x); ++ add_reg_note (insn, REG_FRAME_RELATED_EXPR, x); ++ m->fs.sp_offset -= UNITS_PER_WORD; ++ } ++ else ++ { ++ rtx x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)); ++ x = gen_rtx_SET (sr->reg, gen_rtx_MEM (word_mode, x)); ++ emit_insn (x); ++ } + } + } + +@@ -12597,7 +12614,7 @@ release_scratch_register_on_entry (struct scratch_reg *sr) + pushed on the stack. */ + + static void +-ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, ++ix86_adjust_stack_and_probe_stack_clash (HOST_WIDE_INT size, + const bool int_registers_saved) + { + struct machine_function *m = cfun->machine; +@@ -12713,6 +12730,12 @@ ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, + struct scratch_reg sr; + get_scratch_register_on_entry (&sr); + ++ /* If we needed to save a register, then account for any space ++ that was pushed (we are not going to pop the register when ++ we do the restore). */ ++ if (sr.saved) ++ size -= UNITS_PER_WORD; ++ + /* Step 1: round SIZE down to a multiple of the interval. */ + HOST_WIDE_INT rounded_size = size & -probe_interval; + +@@ -12761,7 +12784,9 @@ ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, + m->fs.cfa_reg == stack_pointer_rtx); + dump_stack_clash_frame_info (PROBE_LOOP, size != rounded_size); + +- release_scratch_register_on_entry (&sr); ++ /* This does not deallocate the space reserved for the scratch ++ register. That will be deallocated in the epilogue. */ ++ release_scratch_register_on_entry (&sr, size, false); + } + + /* Make sure nothing is scheduled before we are done. */ +@@ -12774,7 +12799,7 @@ ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, + pushed on the stack. */ + + static void +-ix86_adjust_stack_and_probe (const HOST_WIDE_INT size, ++ix86_adjust_stack_and_probe (HOST_WIDE_INT size, + const bool int_registers_saved) + { + /* We skip the probe for the first interval + a small dope of 4 words and +@@ -12847,6 +12872,11 @@ ix86_adjust_stack_and_probe (const HOST_WIDE_INT size, + + get_scratch_register_on_entry (&sr); + ++ /* If we needed to save a register, then account for any space ++ that was pushed (we are not going to pop the register when ++ we do the restore). */ ++ if (sr.saved) ++ size -= UNITS_PER_WORD; + + /* Step 1: round SIZE to the previous multiple of the interval. */ + +@@ -12906,7 +12936,9 @@ ix86_adjust_stack_and_probe (const HOST_WIDE_INT size, + (get_probe_interval () + + dope)))); + +- release_scratch_register_on_entry (&sr); ++ /* This does not deallocate the space reserved for the scratch ++ register. That will be deallocated in the epilogue. */ ++ release_scratch_register_on_entry (&sr, size, false); + } + + /* Even if the stack pointer isn't the CFA register, we need to correctly +@@ -13055,7 +13087,7 @@ ix86_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size, + sr.reg), + rounded_size - size)); + +- release_scratch_register_on_entry (&sr); ++ release_scratch_register_on_entry (&sr, size, true); + } + + /* Make sure nothing is scheduled before we are done. */ + +diff --git a/gcc/testsuite/gcc.target/i386/pr84128.c b/gcc/testsuite/gcc.target/i386/pr84128.c +new file mode 100644 +index 0000000..a8323fd6 +--- /dev/null ++++ gcc/testsuite/gcc.target/i386/pr84128.c +@@ -0,0 +1,30 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 -march=i686 -mtune=generic -fstack-clash-protection" } */ ++/* { dg-require-effective-target ia32 } */ ++ ++__attribute__ ((noinline, noclone, weak, regparm (3))) ++int ++f1 (long arg0, int (*pf) (long, void *)) ++{ ++ unsigned char buf[32768]; ++ return pf (arg0, buf); ++} ++ ++__attribute__ ((noinline, noclone, weak)) ++int ++f2 (long arg0, void *ignored) ++{ ++ if (arg0 != 17) ++ __builtin_abort (); ++ return 19; ++} ++ ++int ++main (void) ++{ ++ if (f1 (17, f2) != 19) ++ __builtin_abort (); ++ return 0; ++} ++ ++