]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/arm/aarch-bti-insert.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / config / arm / aarch-bti-insert.cc
1 /* Branch Target Identification for AArch64 architecture.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Contributed by Arm Ltd.
4
5 This file is part of GCC.
6
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)
10 any later version.
11
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.
16
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/>. */
20
21 #define IN_TARGET_CODE 1
22
23 #include "config.h"
24 #define INCLUDE_STRING
25 #include "system.h"
26 #include "coretypes.h"
27 #include "backend.h"
28 #include "target.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "memmodel.h"
32 #include "gimple.h"
33 #include "tm_p.h"
34 #include "stringpool.h"
35 #include "attribs.h"
36 #include "emit-rtl.h"
37 #include "gimplify.h"
38 #include "gimple-iterator.h"
39 #include "dumpfile.h"
40 #include "rtl-iter.h"
41 #include "cfgrtl.h"
42 #include "tree-pass.h"
43 #include "cgraph.h"
44
45 /* This pass enables the support for Branch Target Identification Mechanism for
46 Arm/AArch64. This is a security feature introduced in ARMv8.5-A
47 architecture and ARMv8.1-M. A BTI instruction is used to guard against the
48 execution of instructions which are not the intended target of an indirect
49 branch.
50
51 Outside of a guarded memory region, a BTI instruction executes as a NOP.
52 Within a guarded memory region any target of an indirect branch must be
53 a compatible BTI or BRK, HLT, PACIASP, PACIBASP instruction (even if the
54 branch is triggered in a non-guarded memory region). An incompatibility
55 generates a Branch Target Exception.
56
57 The compatibility of the BTI instruction is as follows (AArch64
58 examples):
59 BTI j : Can be a target of any indirect jump (BR Xn).
60 BTI c : Can be a target of any indirect call (BLR Xn and BR X16/X17).
61 BTI jc: Can be a target of any indirect call or indirect jump.
62 BTI : Can not be a target of any indirect call or indirect jump.
63
64 In order to enable this mechanism, this pass iterates through the
65 control flow of the code and adds appropriate BTI instructions :
66 * Add a new "BTI C" at the beginning of a function, unless its already
67 protected by a "PACIASP/PACIBSP". We exempt the functions that are only
68 called directly.
69 * Add a new "BTI J" for every target of an indirect jump, jump table targets,
70 non-local goto targets or labels that might be referenced by variables,
71 constant pools, etc (NOTE_INSN_DELETED_LABEL)
72
73 Since we have already changed the use of indirect tail calls to only x16
74 and x17, we do not have to use "BTI JC".
75
76 This pass is triggered by the command line option -mbranch-protection=bti or
77 -mbranch-protection=standard. Since all the BTI instructions are in the HINT
78 space, this pass does not require any minimum architecture version. */
79
80 namespace {
81
82 const pass_data pass_data_insert_bti =
83 {
84 RTL_PASS, /* type. */
85 "bti", /* name. */
86 OPTGROUP_NONE, /* optinfo_flags. */
87 TV_MACH_DEP, /* tv_id. */
88 0, /* properties_required. */
89 0, /* properties_provided. */
90 0, /* properties_destroyed. */
91 0, /* todo_flags_start. */
92 0, /* todo_flags_finish. */
93 };
94
95 /* Insert the BTI instruction. */
96 /* This is implemented as a late RTL pass that runs before branch
97 shortening and does the following. */
98 static unsigned int
99 rest_of_insert_bti (void)
100 {
101 timevar_push (TV_MACH_DEP);
102
103 rtx bti_insn;
104 rtx_insn *insn;
105 basic_block bb;
106
107 bb = 0;
108 FOR_EACH_BB_FN (bb, cfun)
109 {
110 for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
111 insn = NEXT_INSN (insn))
112 {
113 /* If a label is marked to be preserved or can be a non-local goto
114 target, it must be protected with a BTI J. */
115 if (LABEL_P (insn)
116 && (LABEL_PRESERVE_P (insn)
117 || bb->flags & BB_NON_LOCAL_GOTO_TARGET))
118 {
119 bti_insn = aarch_gen_bti_j ();
120 emit_insn_after (bti_insn, insn);
121 continue;
122 }
123
124 /* There could still be more labels that are valid targets of a
125 BTI J instuction. To find them we start looking through the
126 JUMP_INSN. If it jumps to a jump table, then we find all labels
127 of the jump table to protect with a BTI J. */
128 if (JUMP_P (insn))
129 {
130 rtx_jump_table_data *table;
131 if (tablejump_p (insn, NULL, &table))
132 {
133 rtvec vec = table->get_labels ();
134 int j;
135 rtx_insn *label;
136
137 for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
138 {
139 label = as_a <rtx_insn *> (XEXP (RTVEC_ELT (vec, j), 0));
140 rtx_insn *next = next_nonnote_nondebug_insn (label);
141 if (aarch_bti_j_insn_p (next))
142 continue;
143
144 bti_insn = aarch_gen_bti_j ();
145 emit_insn_after (bti_insn, label);
146 }
147 }
148 }
149
150 /* Also look for calls to setjmp () which would be marked with
151 REG_SETJMP note and put a BTI J after. This is where longjump ()
152 will return. */
153 if (CALL_P (insn) && (find_reg_note (insn, REG_SETJMP, NULL)))
154 {
155 bti_insn = aarch_gen_bti_j ();
156 emit_insn_after (bti_insn, insn);
157 continue;
158 }
159 }
160 }
161
162 /* Since a Branch Target Exception can only be triggered by an indirect call,
163 we exempt function that are only called directly. We also exempt
164 functions that are already protected by Return Address Signing (PACIASP/
165 PACIBSP). For all other cases insert a BTI C at the beginning of the
166 function. */
167 if (!cgraph_node::get (cfun->decl)->only_called_directly_p ())
168 {
169 bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
170 insn = BB_HEAD (bb);
171 if (!aarch_pac_insn_p (get_first_nonnote_insn ()))
172 {
173 bti_insn = aarch_gen_bti_c ();
174 emit_insn_before (bti_insn, insn);
175 }
176 }
177
178 timevar_pop (TV_MACH_DEP);
179 return 0;
180 }
181
182
183 class pass_insert_bti : public rtl_opt_pass
184 {
185 public:
186 pass_insert_bti (gcc::context *ctxt)
187 : rtl_opt_pass (pass_data_insert_bti, ctxt)
188 {}
189
190 /* opt_pass methods: */
191 virtual bool gate (function *)
192 {
193 if (aarch_bti_enabled ())
194 {
195 aarch_bti_arch_check ();
196 return true;
197 }
198 return false;
199 }
200
201 virtual unsigned int execute (function *)
202 {
203 return rest_of_insert_bti ();
204 }
205
206 }; // class pass_insert_bti
207
208 } // anon namespace
209
210 rtl_opt_pass *
211 make_pass_insert_bti (gcc::context *ctxt)
212 {
213 return new pass_insert_bti (ctxt);
214 }