1 /* Branch Target Identification for RISCV architecture.
2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #define IN_TARGET_CODE 1
24 #define INCLUDE_STRING
26 #include "coretypes.h"
34 #include "stringpool.h"
39 #include "gimple-iterator.h"
43 #include "tree-pass.h"
47 /* This pass implements forward-CFI landing pad checks for RISCV. This is
48 a security feature similar to BTI (branch target identification) in
49 AArch64 and IBT (indirect branch tracking)in X86. A LPAD (landing-pad
50 check) instruction is used to guard against the execution of
51 instructions which are not the intended target of an indirect branch.
53 When forward-CFI is disabled or unimplemented in the CPU, the
54 landing-pad check label instructions behave as NOP. When implemented in
55 the CPU, and enabled, the destination of an indirect branch must be
56 LPAD insn. Otherwise, the CPU reaises an exception.
58 In order to enable this mechanism, this pass iterates through the
59 control flow of the code and adds appropriate LPAD instructions at the
60 beginning of any function that can be called indirectly, and for targets
61 of indirect jumps, i.e., jump table targets, non-local goto targets, and
62 labels that might be referenced by variables, constant pools, etc
63 (NOTE_INSN_DELETED_LABEL). */
67 const pass_data pass_data_insert_landing_pad
=
70 "zisslpcfi", /* name. */
71 OPTGROUP_NONE
, /* optinfo_flags. */
72 TV_MACH_DEP
, /* tv_id. */
73 0, /* properties_required. */
74 0, /* properties_provided. */
75 0, /* properties_destroyed. */
76 0, /* todo_flags_start. */
77 0, /* todo_flags_finish. */
81 is_interrupt_handler_p (tree type
)
83 return lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type
)) != NULL
;
86 /* Insert landing-pad check instructions. This is a late RTL pass that runs
87 before branch shortening. */
89 rest_of_insert_landing_pad (void)
91 timevar_push (TV_MACH_DEP
);
93 struct cgraph_node
*c_node
;
99 FOR_EACH_BB_FN (bb
, cfun
)
101 for (insn
= BB_HEAD (bb
); insn
!= NEXT_INSN (BB_END (bb
));
102 insn
= NEXT_INSN (insn
))
104 /* If a label is marked to be preserved or can be a non-local goto
105 target, it must be protected with a lpad instruction. */
107 && (LABEL_PRESERVE_P (insn
)
108 || bb
->flags
& BB_NON_LOCAL_GOTO_TARGET
))
110 emit_insn_before (gen_lpad_align (), insn
);
111 emit_insn_after (gen_lpad (const0_rtx
), insn
);
115 if (INSN_P (insn
) && INSN_CODE (insn
) == CODE_FOR_gpr_save
)
117 emit_move_insn (RISCV_CALL_ADDRESS_LPAD (Pmode
), const0_rtx
);
118 emit_insn_before (gen_lpad_align (), insn
);
119 emit_insn_after (gen_lpad (const0_rtx
), insn
);
123 if (INSN_P (insn
) && INSN_CODE (insn
) == CODE_FOR_gpr_restore
)
124 emit_move_insn (RISCV_CALL_ADDRESS_LPAD (Pmode
), const0_rtx
);
129 c_node
= cgraph_node::get (cfun
->decl
);
130 if (!c_node
->only_called_directly_p ()
131 && !is_interrupt_handler_p (TREE_TYPE (cfun
->decl
)))
133 bb
= ENTRY_BLOCK_PTR_FOR_FN (cfun
)->next_bb
;
135 lpad_insn
= gen_lpad (const0_rtx
);
136 emit_insn_before (lpad_insn
, insn
);
139 timevar_pop (TV_MACH_DEP
);
143 class pass_insert_landing_pad
: public rtl_opt_pass
146 pass_insert_landing_pad (gcc::context
*ctxt
)
147 : rtl_opt_pass (pass_data_insert_landing_pad
, ctxt
)
150 /* opt_pass methods: */
151 virtual bool gate (function
*)
153 return is_zicfilp_p ();
156 virtual unsigned int execute (function
*)
158 return rest_of_insert_landing_pad ();
161 }; // class pass_insert_landing_pad
166 make_pass_insert_landing_pad (gcc::context
*ctxt
)
168 return new pass_insert_landing_pad (ctxt
);