Update gcc/testsuite/c-c++-common/fcf-protection-[1-7].c.
On Wed, Jan 15, 2025 at 3:54 PM Monk Chiang <monk.chiang@sifive.com> wrote:
> gcc/ChangeLog:
> * gcc/config/riscv/riscv.cc
> (is_zicfilp_p): New function.
> (is_zicfiss_p): New function.
> * gcc/config/riscv/riscv-zicfilp.cc: Update.
> * gcc/config/riscv/riscv.h: Update.
> * gcc/config/riscv/riscv.md: Update.
>
> gcc/testsuite/ChangeLog:
> * gcc/testsuite/c-c++-common/fcf-protection-1.c: Update.
> * gcc/testsuite/c-c++-common/fcf-protection-2.c: Update.
> * gcc/testsuite/c-c++-common/fcf-protection-3.c: Update.
> * gcc/testsuite/c-c++-common/fcf-protection-4.c: Update.
> * gcc/testsuite/c-c++-common/fcf-protection-5.c: Update.
> * gcc/testsuite/c-c++-common/fcf-protection-6.c: Update.
> * gcc/testsuite/c-c++-common/fcf-protection-7.c: Update.
> * gcc/testsuite/gcc.target/riscv/ssp-1.c: Update.
> * gcc/testsuite/gcc.target/riscv/ssp-2.c: Update.
> * gcc/testsuite/gcc.target/riscv/zicfilp-call.c: Update.
> * gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c: Update.
> ---
> gcc/config/riscv/riscv-zicfilp.cc | 2 +-
> gcc/config/riscv/riscv.cc | 52 +++++++++++++++----
> gcc/config/riscv/riscv.h | 8 +--
> gcc/config/riscv/riscv.md | 10 ++--
> gcc/testsuite/c-c++-common/fcf-protection-1.c | 1 +
> gcc/testsuite/c-c++-common/fcf-protection-2.c | 1 +
> gcc/testsuite/c-c++-common/fcf-protection-3.c | 1 +
> gcc/testsuite/c-c++-common/fcf-protection-4.c | 1 +
> gcc/testsuite/c-c++-common/fcf-protection-5.c | 1 +
> gcc/testsuite/c-c++-common/fcf-protection-6.c | 1 +
> gcc/testsuite/c-c++-common/fcf-protection-7.c | 1 +
> .../gcc.target/riscv/interrupt-no-lpad.c | 2 +-
> gcc/testsuite/gcc.target/riscv/ssp-1.c | 2 +-
> gcc/testsuite/gcc.target/riscv/ssp-2.c | 2 +-
> gcc/testsuite/gcc.target/riscv/zicfilp-call.c | 2 +-
> 15 files changed, 63 insertions(+), 24 deletions(-)
>
> diff --git a/gcc/config/riscv/riscv-zicfilp.cc
> b/gcc/config/riscv/riscv-zicfilp.cc
> index b30869ae297..4ded9032ea5 100644
> --- a/gcc/config/riscv/riscv-zicfilp.cc
> +++ b/gcc/config/riscv/riscv-zicfilp.cc
> @@ -150,7 +150,7 @@ public:
> /* opt_pass methods: */
> virtual bool gate (function *)
> {
> - return TARGET_ZICFILP;
> + return is_zicfilp_p ();
> }
>
> virtual unsigned int execute (function *)
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index fa4a706bf56..7f5ef7dae34 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -6682,7 +6682,7 @@ riscv_legitimize_call_address (rtx addr)
> rtx reg = RISCV_CALL_ADDRESS_TEMP (Pmode);
> riscv_emit_move (reg, addr);
>
> - if (TARGET_ZICFILP)
> + if (is_zicfilp_p ())
> {
> rtx sw_guarded = RISCV_CALL_ADDRESS_LPAD (Pmode);
> emit_insn (gen_set_guarded (Pmode, reg));
> @@ -6692,7 +6692,7 @@ riscv_legitimize_call_address (rtx addr)
> return reg;
> }
>
> - if (TARGET_ZICFILP && REG_P (addr))
> + if (is_zicfilp_p () && REG_P (addr))
> emit_insn (gen_set_lpl (Pmode, const0_rtx));
>
> return addr;
> @@ -7508,7 +7508,7 @@ riscv_save_reg_p (unsigned int regno)
> if (regno == GP_REGNUM || regno == THREAD_POINTER_REGNUM)
> return false;
>
> - if (regno == RETURN_ADDR_REGNUM && TARGET_ZICFISS)
> + if (regno == RETURN_ADDR_REGNUM && is_zicfiss_p ())
> return true;
>
> /* We must save every register used in this function. If this is
> not a
> @@ -10341,10 +10341,10 @@ riscv_file_end_indicate_exec_stack ()
> long GNU_PROPERTY_RISCV_FEATURE_1_AND = 0;
> unsigned long feature_1_and = 0;
>
> - if (TARGET_ZICFISS)
> + if (is_zicfilp_p ())
> feature_1_and |= 0x1 << 0;
>
> - if (TARGET_ZICFILP)
> + if (is_zicfiss_p ())
> feature_1_and |= 0x1 << 1;
>
> if (feature_1_and)
> @@ -10404,7 +10404,7 @@ riscv_output_mi_thunk (FILE *file, tree
> thunk_fndecl ATTRIBUTE_UNUSED,
> /* Mark the end of the (empty) prologue. */
> emit_note (NOTE_INSN_PROLOGUE_END);
>
> - if (TARGET_ZICFILP)
> + if (is_zicfilp_p ())
> emit_insn(gen_lpad (const0_rtx));
>
> /* Determine if we can use a sibcall to call FUNCTION directly. */
> @@ -10631,6 +10631,20 @@ riscv_override_options_internal (struct
> gcc_options *opts)
>
> /* Convert -march and -mrvv-vector-bits to a chunks count. */
> riscv_vector_chunks = riscv_convert_vector_chunks (opts);
> +
> + if (opts->x_flag_cf_protection != CF_NONE)
> + {
> + if ((opts->x_flag_cf_protection & CF_RETURN) == CF_RETURN
> + && !TARGET_ZICFISS)
> + error ("%<-fcf-protection%> is not compatible with this target");
> +
> + if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> + && !TARGET_ZICFILP)
> + error ("%<-fcf-protection%> is not compatible with this target");
> +
> + opts->x_flag_cf_protection
> + = (cf_protection_level) (opts->x_flag_cf_protection | CF_SET);
> + }
> }
>
> /* Implement TARGET_OPTION_OVERRIDE. */
> @@ -10925,7 +10939,7 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl,
> rtx chain_value)
>
> /* Work out the offsets of the pointers from the start of the
> trampoline code. */
> - if (!TARGET_ZICFILP)
> + if (!is_zicfilp_p ())
> gcc_assert (ARRAY_SIZE (trampoline) * 4 == TRAMPOLINE_CODE_SIZE);
> else
> gcc_assert (ARRAY_SIZE (trampoline_cfi) * 4 == TRAMPOLINE_CODE_SIZE);
> @@ -10953,7 +10967,7 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl,
> rtx chain_value)
> unsigned insn_count = 0;
>
> /* Insert lpad, if zicfilp is enabled. */
> - if (TARGET_ZICFILP)
> + if (is_zicfilp_p ())
> {
> unsigned HOST_WIDE_INT lpad_code;
> lpad_code = OPCODE_AUIPC | (0 << SHIFT_RD) | (lp_value <<
> IMM_BITS);
> @@ -11015,7 +11029,7 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl,
> rtx chain_value)
> insn_count++;
>
> /* For zicfilp only, insert lui t2, 1, because use jr t0. */
> - if (TARGET_ZICFILP)
> + if (is_zicfilp_p ())
> {
> unsigned HOST_WIDE_INT set_lpl_code;
> set_lpl_code = OPCODE_LUI
> @@ -11045,7 +11059,7 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl,
> rtx chain_value)
> static_chain_offset = TRAMPOLINE_CODE_SIZE;
> target_function_offset = static_chain_offset + GET_MODE_SIZE
> (ptr_mode);
>
> - if (!TARGET_ZICFILP)
> + if (!is_zicfilp_p ())
> {
> /* auipc t2, 0
> l[wd] t0, (target_function_offset)(t2)
> @@ -13960,9 +13974,25 @@ expand_reversed_crc_using_clmul (scalar_mode
> crc_mode, scalar_mode data_mode,
> riscv_emit_move (operands[0], gen_lowpart (crc_mode, a0));
> }
>
> +bool is_zicfiss_p ()
> +{
> + if (TARGET_ZICFISS && (flag_cf_protection & CF_RETURN))
> + return true;
> +
> + return false;
> +}
> +
> +bool is_zicfilp_p ()
> +{
> + if (TARGET_ZICFILP && (flag_cf_protection & CF_BRANCH))
> + return true;
> +
> + return false;
> +}
> +
> bool need_shadow_stack_push_pop_p ()
> {
> - return TARGET_ZICFISS && riscv_save_return_addr_reg_p ();
> + return is_zicfiss_p () && riscv_save_return_addr_reg_p ();
> }
>
> /* Initialize the GCC target structure. */
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index 073b9e4f2bd..2bcabd03517 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -191,7 +191,7 @@ ASM_MISA_SPEC
>
> /* Allocation boundary (in *bits*) for the code of a function. */
> #define FUNCTION_BOUNDARY \
> - (((TARGET_RVC || TARGET_ZCA) && !TARGET_ZICFILP) ? 16 : 32)
> + (((TARGET_RVC || TARGET_ZCA) && !is_zicfilp_p ()) ? 16 : 32)
>
> /* The smallest supported stack boundary the calling convention
> supports. */
> #define STACK_BOUNDARY \
> @@ -415,7 +415,7 @@ ASM_MISA_SPEC
>
> /* Register in which static-chain is passed to a function. */
> #define STATIC_CHAIN_REGNUM \
> - ((TARGET_ZICFILP) ? (GP_TEMP_FIRST + 23) : (GP_TEMP_FIRST + 2))
> + ((is_zicfilp_p ()) ? (GP_TEMP_FIRST + 23) : (GP_TEMP_FIRST + 2))
>
> /* Registers used as temporaries in prologue/epilogue code.
>
> @@ -827,7 +827,7 @@ extern enum riscv_cc get_riscv_cc (const rtx use);
>
> /* Trampolines are a block of code followed by two pointers. */
>
> -#define TRAMPOLINE_CODE_SIZE ((TARGET_ZICFILP) ? 24 : 16)
> +#define TRAMPOLINE_CODE_SIZE ((is_zicfilp_p ()) ? 24 : 16)
>
> #define TRAMPOLINE_SIZE \
> ((Pmode == SImode) \
> @@ -1196,6 +1196,8 @@ extern poly_int64 riscv_v_adjust_nunits (enum
> machine_mode, int);
> extern poly_int64 riscv_v_adjust_nunits (machine_mode, bool, int, int);
> extern poly_int64 riscv_v_adjust_precision (enum machine_mode, int);
> extern poly_int64 riscv_v_adjust_bytesize (enum machine_mode, int);
> +extern bool is_zicfiss_p ();
> +extern bool is_zicfilp_p ();
> extern bool need_shadow_stack_push_pop_p ();
> /* The number of bits and bytes in a RVV vector. */
> #define BITS_PER_RISCV_VECTOR (poly_uint16 (riscv_vector_chunks *
> riscv_bytes_per_vector_chunk * 8))
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 5b4c81bb9e0..d626a350ee4 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -3716,11 +3716,11 @@
> [(set (pc) (match_operand 0 "register_operand"))]
> ""
> {
> - if (TARGET_ZICFILP)
> + if (is_zicfilp_p ())
> emit_insn (gen_set_lpl (Pmode, const0_rtx));
>
> operands[0] = force_reg (Pmode, operands[0]);
> - if (TARGET_ZICFILP)
> + if (is_zicfilp_p ())
> emit_use (gen_rtx_REG (Pmode, T2_REGNUM));
>
> if (Pmode == SImode)
> @@ -3748,7 +3748,7 @@
> gen_rtx_LABEL_REF (Pmode,
> operands[1]),
> NULL_RTX, 0, OPTAB_DIRECT);
>
> - if (TARGET_ZICFILP)
> + if (is_zicfilp_p ())
> {
> rtx t2 = RISCV_CALL_ADDRESS_LPAD (GET_MODE (operands[0]));
> emit_move_insn (t2, operands[0]);
> @@ -3771,7 +3771,7 @@
> (define_insn "tablejump<mode>"
> [(set (pc) (match_operand:GPR 0 "register_operand" "l"))
> (use (label_ref (match_operand 1 "" "")))]
> - "!TARGET_ZICFILP"
> + "!is_zicfilp_p ()"
> "jr\t%0"
> [(set_attr "type" "jalr")
> (set_attr "mode" "none")])
> @@ -3779,7 +3779,7 @@
> (define_insn "tablejump_cfi<mode>"
> [(set (pc) (reg:GPR T2_REGNUM))
> (use (label_ref (match_operand 0 "")))]
> - "TARGET_ZICFILP"
> + "is_zicfilp_p ()"
> "jr\tt2"
> [(set_attr "type" "jalr")
> (set_attr "mode" "none")])
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-1.c
> b/gcc/testsuite/c-c++-common/fcf-protection-1.c
> index f59a8fbdfdc..cc30c921a16 100644
> --- a/gcc/testsuite/c-c++-common/fcf-protection-1.c
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-1.c
> @@ -1,3 +1,4 @@
> /* { dg-do compile } */
> /* { dg-options "-fcf-protection=full" } */
> +/* { dg-skip-if "" { "riscv*-*-*" } } */
> /* { dg-error "'-fcf-protection=full' is not supported for this target"
> "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-2.c
> b/gcc/testsuite/c-c++-common/fcf-protection-2.c
> index 61059725af6..e318989f290 100644
> --- a/gcc/testsuite/c-c++-common/fcf-protection-2.c
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-2.c
> @@ -1,3 +1,4 @@
> /* { dg-do compile } */
> /* { dg-options "-fcf-protection=branch" } */
> +/* { dg-skip-if "" { "riscv*-*-*" } } */
> /* { dg-error "'-fcf-protection=branch' is not supported for this target"
> "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-3.c
> b/gcc/testsuite/c-c++-common/fcf-protection-3.c
> index 257e944c4a6..dd60017dde0 100644
> --- a/gcc/testsuite/c-c++-common/fcf-protection-3.c
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-3.c
> @@ -1,3 +1,4 @@
> /* { dg-do compile } */
> /* { dg-options "-fcf-protection=return" } */
> +/* { dg-skip-if "" { "riscv*-*-*" } } */
> /* { dg-error "'-fcf-protection=return' is not supported for this target"
> "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-4.c
> b/gcc/testsuite/c-c++-common/fcf-protection-4.c
> index af4fc0b2812..2bde6e1e767 100644
> --- a/gcc/testsuite/c-c++-common/fcf-protection-4.c
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-4.c
> @@ -1,2 +1,3 @@
> /* { dg-do compile } */
> +/* { dg-skip-if "" { "riscv*-*-*" } } */
> /* { dg-options "-fcf-protection=none" } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-5.c
> b/gcc/testsuite/c-c++-common/fcf-protection-5.c
> index dc317f84b07..8c675c5f483 100644
> --- a/gcc/testsuite/c-c++-common/fcf-protection-5.c
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-5.c
> @@ -1,3 +1,4 @@
> /* { dg-do compile } */
> /* { dg-options "-fcf-protection" } */
> +/* { dg-skip-if "" { "riscv*-*-*" } } */
> /* { dg-error "'-fcf-protection=full' is not supported for this target"
> "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-6.c
> b/gcc/testsuite/c-c++-common/fcf-protection-6.c
> index 61059725af6..e318989f290 100644
> --- a/gcc/testsuite/c-c++-common/fcf-protection-6.c
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-6.c
> @@ -1,3 +1,4 @@
> /* { dg-do compile } */
> /* { dg-options "-fcf-protection=branch" } */
> +/* { dg-skip-if "" { "riscv*-*-*" } } */
> /* { dg-error "'-fcf-protection=branch' is not supported for this target"
> "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fcf-protection-7.c
> b/gcc/testsuite/c-c++-common/fcf-protection-7.c
> index 257e944c4a6..dd60017dde0 100644
> --- a/gcc/testsuite/c-c++-common/fcf-protection-7.c
> +++ b/gcc/testsuite/c-c++-common/fcf-protection-7.c
> @@ -1,3 +1,4 @@
> /* { dg-do compile } */
> /* { dg-options "-fcf-protection=return" } */
> +/* { dg-skip-if "" { "riscv*-*-*" } } */
> /* { dg-error "'-fcf-protection=return' is not supported for this target"
> "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
> diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c
> b/gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c
> index ff512b98c61..1290b373f08 100644
> --- a/gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c
> +++ b/gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c
> @@ -1,5 +1,5 @@
> /* { dg-do compile { target { riscv64*-*-* } } } */
> -/* { dg-options "-march=rv64gc_zicfilp -mabi=lp64d" } */
> +/* { dg-options "-march=rv64gc_zicfilp -mabi=lp64d
> -fcf-protection=branch" } */
> void __attribute__ ((interrupt))
> foo (void)
> {
> diff --git a/gcc/testsuite/gcc.target/riscv/ssp-1.c
> b/gcc/testsuite/gcc.target/riscv/ssp-1.c
> index abf47ec6442..24e3010c3cc 100644
> --- a/gcc/testsuite/gcc.target/riscv/ssp-1.c
> +++ b/gcc/testsuite/gcc.target/riscv/ssp-1.c
> @@ -1,5 +1,5 @@
> /* { dg-do compile { target { riscv64*-*-* } } } */
> -/* { dg-options "-O2 -march=rv64gc_zicfiss -mabi=lp64d" } */
> +/* { dg-options "-O2 -march=rv64gc_zicfiss -mabi=lp64d
> -fcf-protection=return" } */
> /* { dg-skip-if "" { *-*-* } { "-O0" } } */
> struct ad {
> void *ae;
> diff --git a/gcc/testsuite/gcc.target/riscv/ssp-2.c
> b/gcc/testsuite/gcc.target/riscv/ssp-2.c
> index 7c6098357e9..9d3d6b27038 100644
> --- a/gcc/testsuite/gcc.target/riscv/ssp-2.c
> +++ b/gcc/testsuite/gcc.target/riscv/ssp-2.c
> @@ -1,5 +1,5 @@
> /* { dg-do compile { target { riscv64*-*-* } } } */
> -/* { dg-options "-O0 -march=rv64gc_zicfiss -mabi=lp64d" } */
> +/* { dg-options "-O0 -march=rv64gc_zicfiss -mabi=lp64d
> -fcf-protection=return" } */
>
> void __attribute__ ((interrupt))
> foo (void)
> diff --git a/gcc/testsuite/gcc.target/riscv/zicfilp-call.c
> b/gcc/testsuite/gcc.target/riscv/zicfilp-call.c
> index 75c8b32faa3..eb9e1468e7f 100644
> --- a/gcc/testsuite/gcc.target/riscv/zicfilp-call.c
> +++ b/gcc/testsuite/gcc.target/riscv/zicfilp-call.c
> @@ -1,5 +1,5 @@
> /* { dg-do compile { target { riscv64*-*-* } } } */
> -/* { dg-options "-O2 -fPIE -march=rv64gc_zicfilp -mabi=lp64d" } */
> +/* { dg-options "-O2 -fPIE -march=rv64gc_zicfilp -mabi=lp64d
> -fcf-protection=branch" } */
> /* { dg-skip-if "" { *-*-* } { "-O0" } } */
>
> extern void _dl_find_object_init (void);
> --
> 2.47.1
>
>
@@ -111,6 +111,9 @@ static const riscv_implied_info_t riscv_implied_info[] =
{"zfinx", "zicsr"},
{"zdinx", "zicsr"},
+ {"zicfiss", "zicsr"},
+ {"zicfiss", "zimop"},
+
{"zk", "zkn"},
{"zk", "zkr"},
{"zk", "zkt"},
@@ -325,6 +328,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"zicclsm", ISA_SPEC_CLASS_NONE, 1, 0},
{"ziccrse", ISA_SPEC_CLASS_NONE, 1, 0},
+ {"zicfiss", ISA_SPEC_CLASS_NONE, 1, 0},
+
{"zimop", ISA_SPEC_CLASS_NONE, 1, 0},
{"zcmop", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1647,6 +1652,8 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
RISCV_EXT_FLAG_ENTRY ("zicbop", x_riscv_zicmo_subext, MASK_ZICBOP),
RISCV_EXT_FLAG_ENTRY ("zic64b", x_riscv_zicmo_subext, MASK_ZIC64B),
+ RISCV_EXT_FLAG_ENTRY ("zicfiss", x_riscv_zi_subext, MASK_ZICFISS),
+
RISCV_EXT_FLAG_ENTRY ("zimop", x_riscv_mop_subext, MASK_ZIMOP),
RISCV_EXT_FLAG_ENTRY ("zcmop", x_riscv_mop_subext, MASK_ZCMOP),
@@ -679,3 +679,9 @@
return (riscv_symbolic_constant_p (op, &type)
&& type == SYMBOL_PCREL);
})
+
+;; Shadow stack operands only allow x1, x5 registers
+(define_predicate "x1x5_operand"
+ (and (match_operand 0 "register_operand")
+ (match_test "REGNO (op) == RETURN_ADDR_REGNUM
+ || REGNO (op) == T0_REGNUM")))
@@ -7496,6 +7496,9 @@ riscv_save_reg_p (unsigned int regno)
if (regno == GP_REGNUM || regno == THREAD_POINTER_REGNUM)
return false;
+ if (regno == RETURN_ADDR_REGNUM && TARGET_ZICFISS)
+ return true;
+
/* We must save every register used in this function. If this is not a
leaf function, then we must save all temporary registers. */
if (df_regs_ever_live_p (regno)
@@ -8049,7 +8052,7 @@ riscv_is_eh_return_data_register (unsigned int regno)
static void
riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
- bool epilogue, bool maybe_eh_return)
+ bool epilogue, bool maybe_eh_return, bool sibcall_p)
{
HOST_WIDE_INT offset, first_fp_offset;
unsigned int regno, num_masked_fp = 0;
@@ -8135,7 +8138,14 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
}
}
- riscv_save_restore_reg (word_mode, regno, offset, fn);
+ if (need_shadow_stack_push_pop_p () && epilogue && !sibcall_p
+ && !(maybe_eh_return && crtl->calls_eh_return)
+ && (regno == RETURN_ADDR_REGNUM)
+ && !cfun->machine->interrupt_handler_p)
+ riscv_save_restore_reg (word_mode, RISCV_PROLOGUE_TEMP_REGNUM,
+ offset, fn);
+ else
+ riscv_save_restore_reg (word_mode, regno, offset, fn);
}
/* This loop must iterate over the same space as its companion in
@@ -8729,6 +8739,9 @@ riscv_expand_prologue (void)
if (cfun->machine->naked_p)
return;
+ if (need_shadow_stack_push_pop_p ())
+ emit_insn (gen_sspush (Pmode, gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM)));
+
/* prefer multi-push to save-restore libcall. */
if (riscv_use_multi_push (frame))
{
@@ -8772,7 +8785,7 @@ riscv_expand_prologue (void)
= get_multi_push_fpr_mask (multi_push_additional / UNITS_PER_WORD);
frame->fmask &= mask_fprs_push;
riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false,
- false);
+ false, false);
frame->fmask = fmask & ~mask_fprs_push; /* mask for the rest FPRs. */
}
}
@@ -8823,7 +8836,8 @@ riscv_expand_prologue (void)
GEN_INT (-step1));
RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
}
- riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false, false);
+ riscv_for_each_saved_reg (remaining_size, riscv_save_reg,
+ false, false, false);
}
/* Undo the above fib. */
@@ -8985,6 +8999,7 @@ riscv_expand_epilogue (int style)
= use_multi_pop ? frame->multi_push_adj_base + frame->multi_push_adj_addi
: 0;
rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
+ rtx t0 = gen_rtx_REG (Pmode, RISCV_PROLOGUE_TEMP_REGNUM);
unsigned th_int_mask = 0;
rtx insn;
@@ -9194,7 +9209,8 @@ riscv_expand_epilogue (int style)
riscv_for_each_saved_v_reg (step2, riscv_restore_reg, false);
riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size
- multipop_size,
- riscv_restore_reg, true, style == EXCEPTION_RETURN);
+ riscv_restore_reg, true, style == EXCEPTION_RETURN,
+ style == SIBCALL_RETURN);
if (th_int_mask && TH_INT_INTERRUPT (cfun))
{
@@ -9234,7 +9250,8 @@ riscv_expand_epilogue (int style)
riscv_for_each_saved_reg (frame->total_size - libcall_size
- multipop_size,
riscv_restore_reg, true,
- style == EXCEPTION_RETURN);
+ style == EXCEPTION_RETURN, false);
+
/* Undo the above fib. */
frame->mask = mask;
frame->fmask = fmask;
@@ -9259,6 +9276,17 @@ riscv_expand_epilogue (int style)
emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
EH_RETURN_STACKADJ_RTX));
+ if (need_shadow_stack_push_pop_p ()
+ && !((style == EXCEPTION_RETURN) && crtl->calls_eh_return))
+ {
+ if (BITSET_P (cfun->machine->frame.mask, RETURN_ADDR_REGNUM)
+ && style != SIBCALL_RETURN
+ && !cfun->machine->interrupt_handler_p)
+ emit_insn (gen_sspopchk (Pmode, t0));
+ else
+ emit_insn (gen_sspopchk (Pmode, ra));
+ }
+
/* Return from interrupt. */
if (cfun->machine->interrupt_handler_p)
{
@@ -9276,7 +9304,15 @@ riscv_expand_epilogue (int style)
emit_jump_insn (gen_riscv_uret ());
}
else if (style != SIBCALL_RETURN)
- emit_jump_insn (gen_simple_return_internal (ra));
+ {
+ if (need_shadow_stack_push_pop_p ()
+ && !((style == EXCEPTION_RETURN) && crtl->calls_eh_return)
+ && BITSET_P (cfun->machine->frame.mask, RETURN_ADDR_REGNUM)
+ && !cfun->machine->interrupt_handler_p)
+ emit_jump_insn (gen_simple_return_internal (t0));
+ else
+ emit_jump_insn (gen_simple_return_internal (ra));
+ }
}
/* Implement EPILOGUE_USES. */
@@ -9473,7 +9509,8 @@ bool
riscv_can_use_return_insn (void)
{
return (reload_completed && known_eq (cfun->machine->frame.total_size, 0)
- && ! cfun->machine->interrupt_handler_p);
+ && ! cfun->machine->interrupt_handler_p
+ && ! need_shadow_stack_push_pop_p ());
}
/* Given that there exists at least one variable that is set (produced)
@@ -13786,6 +13823,11 @@ expand_reversed_crc_using_clmul (scalar_mode crc_mode, scalar_mode data_mode,
riscv_emit_move (operands[0], gen_lowpart (crc_mode, a0));
}
+bool need_shadow_stack_push_pop_p ()
+{
+ return TARGET_ZICFISS && riscv_save_return_addr_reg_p ();
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -1189,6 +1189,7 @@ extern poly_int64 riscv_v_adjust_nunits (enum machine_mode, int);
extern poly_int64 riscv_v_adjust_nunits (machine_mode, bool, int, int);
extern poly_int64 riscv_v_adjust_precision (enum machine_mode, int);
extern poly_int64 riscv_v_adjust_bytesize (enum machine_mode, int);
+extern bool need_shadow_stack_push_pop_p ();
/* The number of bits and bytes in a RVV vector. */
#define BITS_PER_RISCV_VECTOR (poly_uint16 (riscv_vector_chunks * riscv_bytes_per_vector_chunk * 8))
#define BYTES_PER_RISCV_VECTOR (poly_uint16 (riscv_vector_chunks * riscv_bytes_per_vector_chunk))
@@ -99,6 +99,12 @@
;; CRC unspecs
UNSPEC_CRC
UNSPEC_CRC_REV
+
+ ;; ZICFISS
+ UNSPECV_SSPUSH
+ UNSPECV_SSPOPCHK
+ UNSPECV_SSRDP
+ UNSPECV_SSP
])
(define_c_enum "unspecv" [
@@ -4116,6 +4122,30 @@
(set_attr "length" "0")]
)
+(define_expand "save_stack_nonlocal"
+ [(set (match_operand 0 "memory_operand")
+ (match_operand 1 "register_operand"))]
+ ""
+{
+ rtx stack_slot;
+
+ if (need_shadow_stack_push_pop_p ())
+ {
+ /* Copy shadow stack pointer to the first slot
+ and stack pointer to the second slot. */
+ rtx ssp_slot = adjust_address (operands[0], word_mode, 0);
+ stack_slot = adjust_address (operands[0], Pmode, UNITS_PER_WORD);
+
+ rtx reg_ssp = force_reg (word_mode, const0_rtx);
+ emit_insn (gen_ssrdp (word_mode, reg_ssp));
+ emit_move_insn (ssp_slot, reg_ssp);
+ }
+ else
+ stack_slot = adjust_address (operands[0], Pmode, 0);
+ emit_move_insn (stack_slot, operands[1]);
+ DONE;
+})
+
;; This fixes a failure with gcc.c-torture/execute/pr64242.c at -O2 for a
;; 32-bit target when using -mtune=sifive-7-series. The first sched pass
;; runs before register elimination, and we have a non-obvious dependency
@@ -4126,7 +4156,70 @@
(match_operand 1 "memory_operand")]
""
{
- emit_move_insn (operands[0], operands[1]);
+ rtx stack_slot;
+
+ if (need_shadow_stack_push_pop_p ())
+ {
+ rtx t0 = gen_rtx_REG (Pmode, RISCV_PROLOGUE_TEMP_REGNUM);
+ /* Restore shadow stack pointer from the first slot
+ and stack pointer from the second slot. */
+ rtx ssp_slot = adjust_address (operands[1], word_mode, 0);
+ stack_slot = adjust_address (operands[1], Pmode, UNITS_PER_WORD);
+
+ /* Get the current shadow stack pointer. */
+ rtx cur_ssp = force_reg (word_mode, const0_rtx);
+ emit_insn (gen_ssrdp (word_mode, cur_ssp));
+
+ /* Compare and jump over adjustment code. */
+ rtx noadj_label = gen_label_rtx ();
+ emit_cmp_and_jump_insns (cur_ssp, const0_rtx, EQ, NULL_RTX,
+ word_mode, 1, noadj_label);
+
+ rtx loop_label = gen_label_rtx ();
+ emit_label (loop_label);
+ LABEL_NUSES (loop_label) = 1;
+
+ /* Check if current ssp less than jump buffer ssp,
+ so no loop is needed. */
+ emit_cmp_and_jump_insns (ssp_slot, cur_ssp, LE, NULL_RTX,
+ ptr_mode, 1, noadj_label);
+
+ /* Advance by a maximum of 4K at a time to avoid unwinding
+ past bounds of the shadow stack. */
+ rtx reg_4096 = force_reg (word_mode, GEN_INT (4096));
+ rtx cmp_ssp = gen_reg_rtx (word_mode);
+ cmp_ssp = expand_simple_binop (ptr_mode, MINUS,
+ ssp_slot, cur_ssp,
+ cmp_ssp, 1, OPTAB_DIRECT);
+
+ /* Update curr_ssp from jump buffer ssp. */
+ emit_move_insn (cur_ssp, ssp_slot);
+ emit_insn (gen_write_ssp (word_mode, cur_ssp));
+ emit_jump_insn (gen_jump (loop_label));
+ emit_barrier ();
+
+ /* Adjust the ssp in a loop. */
+ rtx cmp_4k_label = gen_label_rtx ();
+ emit_label (cmp_4k_label);
+ LABEL_NUSES (cmp_4k_label) = 1;
+
+ /* Add 4k for curr_ssp. */
+ cur_ssp = expand_simple_binop (ptr_mode, PLUS,
+ cur_ssp, reg_4096,
+ cur_ssp, 1, OPTAB_DIRECT);
+ emit_insn (gen_write_ssp (word_mode, cur_ssp));
+ emit_insn (gen_sspush (Pmode, t0));
+ emit_insn (gen_sspopchk (Pmode, t0));
+ emit_jump_insn (gen_jump (loop_label));
+ emit_barrier ();
+
+ emit_label (noadj_label);
+ LABEL_NUSES (noadj_label) = 1;
+ }
+ else
+ stack_slot = adjust_address (operands[1], Pmode, 0);
+
+ emit_move_insn (operands[0], stack_slot);
/* Prevent the following hard fp restore from being moved before the move
insn above which uses a copy of the soft fp reg. */
emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
@@ -4594,6 +4687,36 @@
}"
[(set_attr "type" "arith")])
+;; Shadow stack
+
+(define_insn "@sspush<mode>"
+ [(unspec_volatile [(match_operand:P 0 "x1x5_operand" "r")] UNSPECV_SSPUSH)]
+ "TARGET_ZICFISS"
+ "sspush\t%0"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "@sspopchk<mode>"
+ [(unspec_volatile [(match_operand:P 0 "x1x5_operand" "r")] UNSPECV_SSPOPCHK)]
+ "TARGET_ZICFISS"
+ "sspopchk\t%0"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "@ssrdp<mode>"
+ [(set (match_operand:P 0 "register_operand" "=r")
+ (unspec_volatile [(const_int 0)] UNSPECV_SSRDP))]
+ "TARGET_ZICFISS"
+ "ssrdp\t%0"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "@write_ssp<mode>"
+ [(unspec_volatile [(match_operand:P 0 "register_operand" "r")] UNSPECV_SSP)]
+ "TARGET_ZICFISS"
+ "csrw\tssp, %0"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "<MODE>")])
(include "bitmanip.md")
(include "crypto.md")
@@ -253,6 +253,8 @@ Mask(ZICCLSM) Var(riscv_zi_subext)
Mask(ZICCRSE) Var(riscv_zi_subext)
+Mask(ZICFISS) Var(riscv_zi_subext)
+
TargetVariable
int riscv_za_subext
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile { target { riscv64*-*-* } } } */
+/* { dg-options "-O2 -march=rv64gc_zicfiss -mabi=lp64d" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+struct ad {
+ void *ae;
+};
+struct af {
+ union {
+ int *ai;
+ int *aj;
+ struct ad *ak;
+ } u;
+ struct {
+ struct {
+ long al : 1;
+ long am : 1;
+ long : 21;
+ } b;
+ long i;
+ } s;
+};
+void fdes (struct af *, void *, long *);
+
+void foo (struct af *bv, long *bw) {
+ bw[0] = bw[1] = 0;
+ if (bv->s.b.al)
+ fdes (bv, bv->u.ak->ae, bw);
+ else if (bv->s.b.am) {
+ int **p = (int**)bv->u.aj;
+ for (; *p; ++p)
+ fdes (bv, *p, bw);
+ } else
+ fdes (bv, bv->u.ai, bw);
+}
+
+/* { dg-final { scan-assembler-times "ld\tt0" 1 } } */
+/* { dg-final { scan-assembler-times "sspopchk\tt0" 1 } } */
+/* { dg-final { scan-assembler-times "jr\tt0" 1 } } */
+/* { dg-final { scan-assembler-times "ld\tra" 2 } } */
+/* { dg-final { scan-assembler-times "sspopchk\tra" 2 } } */
+/* { dg-final { scan-assembler-times "tail" 2 } } */
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile { target { riscv64*-*-* } } } */
+/* { dg-options "-O0 -march=rv64gc_zicfiss -mabi=lp64d" } */
+
+void __attribute__ ((interrupt))
+foo (void)
+{
+}
+/* { dg-final { scan-assembler-times "sd\tra" 1 } } */
+/* { dg-final { scan-assembler-times "ld\tra" 1 } } */
+/* { dg-final { scan-assembler-times "sspopchk\tra" 1 } } */
@@ -19,6 +19,11 @@
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
+/* Unwind shadow stack. */
+#if defined(__riscv_zicfiss)
+# include "config/riscv/shadow-stack-unwind.h"
+#endif
+
#ifndef inhibit_libc
#include <signal.h>
new file mode 100644
@@ -0,0 +1,74 @@
+/* _Unwind_Frames_Extra with shadow stack.
+ Copyright (C) 2016-2024 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#define LIBGCC2_UNITS_PER_WORD (__riscv_xlen / 8)
+
+/* Unwind the shadow stack for EH. */
+#undef _Unwind_Frames_Extra
+#define _Unwind_Frames_Extra(x) \
+ do \
+ { \
+ _Unwind_Word ssp = 0; \
+ asm volatile ("ssrdp %0" : "=r"(ssp)); \
+ if (ssp != 0) \
+ { \
+ _Unwind_Word tmp = (x); \
+ tmp = tmp * LIBGCC2_UNITS_PER_WORD; \
+ while (tmp > 4096) \
+ { \
+ ssp += 4096; \
+ tmp -= 4096; \
+ asm volatile ("csrw ssp, %0" :: "r"(ssp)); \
+ asm volatile ("sspush x5\n" \
+ "sspopchk x5" : : : "x5"); \
+ } \
+ \
+ if (tmp > 0) \
+ { \
+ ssp += tmp; \
+ asm volatile ("csrw ssp, %0" :: "r"(ssp)); \
+ } \
+ } \
+ } \
+ while (0)
+
+#undef _Unwind_Frames_Increment
+#define _Unwind_Frames_Increment(exc, context, frames) \
+ { \
+ frames++; \
+ if (exc->exception_class != 0 \
+ && _Unwind_GetIP (context) != 0 \
+ && !_Unwind_IsSignalFrame (context)) \
+ { \
+ _Unwind_Word ssp; \
+ asm volatile ("ssrdp %0" : "=r"(ssp)); \
+ if (ssp != 0) \
+ { \
+ ssp += LIBGCC2_UNITS_PER_WORD * frames; \
+ _Unwind_Word ra = *(_Unwind_Word *) ssp; \
+ if (ra != _Unwind_GetIP (context)) \
+ return _URC_FATAL_PHASE2_ERROR; \
+ } \
+ } \
+ }