diff options
author | Raphael Moreira Zinsly <rzinsly@ventanamicro.com> | 2024-07-22 11:23:27 -0300 |
---|---|---|
committer | Raphael Moreira Zinsly <rzinsly@ventanamicro.com> | 2024-08-09 11:09:12 -0300 |
commit | 180ede3543e98ade8f809afe8be5af0eeaeff7bb (patch) | |
tree | 276bfe6c4de59f75e6e86aeb9852f613d19c270e | |
parent | 2862d99bfdae96a1d4b275fa3f3daad6206ff761 (diff) | |
download | gcc-180ede3543e98ade8f809afe8be5af0eeaeff7bb.zip gcc-180ede3543e98ade8f809afe8be5af0eeaeff7bb.tar.gz gcc-180ede3543e98ade8f809afe8be5af0eeaeff7bb.tar.bz2 |
RISC-V: Enable stack clash in alloca
Add the TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE to riscv in
order to enable stack clash protection when using alloca.
The code and tests are the same used by aarch64.
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_compute_frame_info): Update
outgoing args size.
(riscv_stack_clash_protection_alloca_probe_range): New.
(TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE): New.
* config/riscv/riscv.h
(STACK_CLASH_MIN_BYTES_OUTGOING_ARGS): New.
(STACK_DYNAMIC_OFFSET): New.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/stack-check-14.c: New test.
* gcc.target/riscv/stack-check-15.c: New test.
* gcc.target/riscv/stack-check-alloca-1.c: New test.
* gcc.target/riscv/stack-check-alloca-2.c: New test.
* gcc.target/riscv/stack-check-alloca-3.c: New test.
* gcc.target/riscv/stack-check-alloca-4.c: New test.
* gcc.target/riscv/stack-check-alloca-5.c: New test.
* gcc.target/riscv/stack-check-alloca-6.c: New test.
* gcc.target/riscv/stack-check-alloca-7.c: New test.
* gcc.target/riscv/stack-check-alloca-8.c: New test.
* gcc.target/riscv/stack-check-alloca-9.c: New test.
* gcc.target/riscv/stack-check-alloca-10.c: New test.
* gcc.target/riscv/stack-check-alloca.h: New.
-rw-r--r-- | gcc/config/riscv/riscv.cc | 17 | ||||
-rw-r--r-- | gcc/config/riscv/riscv.h | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-14.c | 24 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-15.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c | 15 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/stack-check-alloca.h | 15 |
15 files changed, 219 insertions, 0 deletions
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 0342906..a1b09e8 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -7248,6 +7248,10 @@ riscv_compute_frame_info (void) frame = &cfun->machine->frame; + /* Adjust the outgoing arguments size if required. Keep it in sync with what + the mid-end is doing. */ + crtl->outgoing_args_size = STACK_DYNAMIC_OFFSET (cfun); + /* In an interrupt function, there are two cases in which t0 needs to be used: 1, If we have a large frame, then we need to save/restore t0. We check for this before clearing the frame struct. @@ -11939,6 +11943,15 @@ riscv_c_mode_for_floating_type (enum tree_index ti) return default_mode_for_floating_type (ti); } +/* On riscv we have an ABI defined safe buffer. This constant is used to + determining the probe offset for alloca. */ + +static HOST_WIDE_INT +riscv_stack_clash_protection_alloca_probe_range (void) +{ + return STACK_CLASH_CALLER_GUARD; +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" @@ -12247,6 +12260,10 @@ riscv_c_mode_for_floating_type (enum tree_index ti) #define TARGET_VECTORIZE_PREFERRED_VECTOR_ALIGNMENT \ riscv_vectorize_preferred_vector_alignment +#undef TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE +#define TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE \ + riscv_stack_clash_protection_alloca_probe_range + /* Mode switching hooks. */ #undef TARGET_MODE_EMIT diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 58e1717..ead9786 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -1271,4 +1271,21 @@ extern void riscv_remove_unneeded_save_restore_calls (void); generating stack clash probes. */ #define STACK_CLASH_MAX_UNROLL_PAGES 4 +/* This value represents the minimum amount of bytes we expect the function's + outgoing arguments to be when stack-clash is enabled. */ +#define STACK_CLASH_MIN_BYTES_OUTGOING_ARGS 8 + +/* Allocate a minimum of STACK_CLASH_MIN_BYTES_OUTGOING_ARGS bytes for the + outgoing arguments if stack clash protection is enabled. This is essential + as the extra arg space allows us to skip a check in alloca. */ +#undef STACK_DYNAMIC_OFFSET +#define STACK_DYNAMIC_OFFSET(FUNDECL) \ + ((flag_stack_clash_protection \ + && cfun->calls_alloca \ + && known_lt (crtl->outgoing_args_size, \ + STACK_CLASH_MIN_BYTES_OUTGOING_ARGS)) \ + ? ROUND_UP (STACK_CLASH_MIN_BYTES_OUTGOING_ARGS, \ + STACK_BOUNDARY / BITS_PER_UNIT) \ + : (crtl->outgoing_args_size + STACK_POINTER_OFFSET)) + #endif /* ! GCC_RISCV_H */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-14.c b/gcc/testsuite/gcc.target/riscv/stack-check-14.c new file mode 100644 index 0000000..8ca0488 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-14.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ + +int t1(int); + +int t2(int x) +{ + char *p = __builtin_alloca (2048); + x = t1 (x); + return p[x]; +} + + +/* This test has a constant sized alloca that is smaller than the + probe interval. Only one probe is required since the value is larger + than 1024 bytes but smaller than page size. + + The form can change quite a bit so we just check for one + probe without looking at the actual address. */ +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */ + + + diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-15.c b/gcc/testsuite/gcc.target/riscv/stack-check-15.c new file mode 100644 index 0000000..a44b257 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-15.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ + +int t1(int); + +int t2(int x) +{ + char *p = __builtin_alloca (x); + x = t1 (x); + return p[x]; +} + + +/* This test has a variable sized alloca. It requires 3 probes. + One in the loop, one for the residual, one for when it's < 1024 and one for + when it's not. + + The form can change quite a bit so we just check for three + probes without looking at the actual address. */ +/* { dg-final { scan-assembler-times {sd\tzero,} 3 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c new file mode 100644 index 0000000..642840f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE y +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 2 } } */ +/* { dg-final { scan-assembler-times {sd\tzero,0\(sp\)} 1 } } */ + +/* Dynamic alloca, expect loop, and 2 probes with 1kB offset and 1 at sp. + 1st probe is inside the loop for the full guard-size allocations, second + probe is for the case where residual is zero and the final probe for when + residiual is > 1024 bytes. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c new file mode 100644 index 0000000..11844aa --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-10.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 127.5 * 3 * 1024 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 2 } } */ + +/* Large alloca of an amount which isn't a multiple of a guard-size, and + residiual is more than 1kB. Loop expected with one 1Kb probe offset and + one residual probe at offset 1kB. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c new file mode 100644 index 0000000..5c7a158 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 0 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-not {sd\tzero,} } } */ + +/* Alloca of 0 should emit no probes, boundary condition. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c new file mode 100644 index 0000000..a5db267 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-3.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 100 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,8\(sp\)} 1 } } */ + +/* Alloca is less than 1kB, 1 probe expected at word offset. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c new file mode 100644 index 0000000..1841412 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-4.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 1.5 * 1024 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */ + +/* Alloca is more than 1kB, but less than guard-size, 1 probe expected at + 1kB offset. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c new file mode 100644 index 0000000..f8f9d94 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-5.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 2 * 1024 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */ + +/* Alloca is more than 1kB, but less than guard-size, 1 probe expected at + 1kB offset. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c new file mode 100644 index 0000000..d937e92 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-6.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 2.5 * 1024 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */ + +/* Alloca is more than 1kB, but less than guard-size, 1 probe expected at 1kB + offset. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c new file mode 100644 index 0000000..cbb32f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-7.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 3 * 1024 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */ + +/* Alloca is exactly one guard-size, 1 probe expected at 1kB offset. + Boundary condition. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c new file mode 100644 index 0000000..3cc3450 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-8.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection --param stack-clash-protection-guard-size=16" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 65 * 1024 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */ +/* { dg-final { scan-assembler-times {sd\tzero,8\(sp\)} 1 } } */ + +/* Alloca is more than one guard-page, and residual is exactly 1Kb. 2 probes + expected. One at 1kB offset for the guard-size allocation and one at word + offset for the residual. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c new file mode 100644 index 0000000..3646693 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca-9.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc -mabi=lp64d -fstack-clash-protection" } */ +/* { dg-require-effective-target supports_stack_clash_protection } */ +/* { dg-require-effective-target alloca } */ + +#define SIZE 127 * 3 * 1024 +#include "stack-check-alloca.h" + +/* { dg-final { scan-assembler-times {sd\tzero,1024\(sp\)} 1 } } */ + +/* Large alloca of a constant amount which is a multiple of a guard-size, + no residiual. Loop expected with one 1Kb probe offset and no residual probe + because residual is at compile time known to be zero. */ diff --git a/gcc/testsuite/gcc.target/riscv/stack-check-alloca.h b/gcc/testsuite/gcc.target/riscv/stack-check-alloca.h new file mode 100644 index 0000000..8c75f6c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-check-alloca.h @@ -0,0 +1,15 @@ + +/* Avoid inclusion of alloca.h, unavailable on some systems. */ +#define alloca __builtin_alloca + +__attribute__((noinline, noipa)) +void g (char* ptr, int y) +{ + ptr[y] = '\0'; +} + +void f_caller (int y) +{ + char* pStr = alloca(SIZE); + g (pStr, y); +} |