]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/aarch64/aarch64-bti-insert.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / aarch64 / aarch64-bti-insert.c
CommitLineData
b5f794b4 1/* Branch Target Identification for AArch64 architecture.
8d9254fc 2 Copyright (C) 2019-2020 Free Software Foundation, Inc.
b5f794b4
SD
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
46 for AArch64. This is a new security feature introduced in ARMv8.5-A
47 archtitecture. A BTI instruction is used to guard against the execution
48 of instructions which are not the intended target of an indirect branch.
49
50 Outside of a guarded memory region, a BTI instruction executes as a NOP.
51 Within a guarded memory region any target of an indirect branch must be
52 a compatible BTI or BRK, HLT, PACIASP, PACIBASP instruction (even if the
53 branch is triggered in a non-guarded memory region). An incompatibility
54 generates a Branch Target Exception.
55
56 The compatibility of the BTI instruction is as follows:
57 BTI j : Can be a target of any indirect jump (BR Xn).
58 BTI c : Can be a target of any indirect call (BLR Xn and BR X16/X17).
59 BTI jc: Can be a target of any indirect call or indirect jump.
60 BTI : Can not be a target of any indirect call or indirect jump.
61
62 In order to enable this mechanism, this pass iterates through the
63 control flow of the code and adds appropriate BTI instructions :
64 * Add a new "BTI C" at the beginning of a function, unless its already
65 protected by a "PACIASP/PACIBSP". We exempt the functions that are only
66 called directly.
67 * Add a new "BTI J" for every target of an indirect jump, jump table targets,
68 non-local goto targets or labels that might be referenced by variables,
69 constant pools, etc (NOTE_INSN_DELETED_LABEL)
70
71 Since we have already changed the use of indirect tail calls to only x16
72 and x17, we do not have to use "BTI JC".
73
74 This pass is triggered by the command line option -mbranch-protection=bti or
75 -mbranch-protection=standard. Since all the BTI instructions are in the HINT
76 space, this pass does not require any minimum architecture version. */
77
78namespace {
79
80const pass_data pass_data_insert_bti =
81{
82 RTL_PASS, /* type. */
83 "bti", /* name. */
84 OPTGROUP_NONE, /* optinfo_flags. */
85 TV_MACH_DEP, /* tv_id. */
86 0, /* properties_required. */
87 0, /* properties_provided. */
88 0, /* properties_destroyed. */
89 0, /* todo_flags_start. */
90 0, /* todo_flags_finish. */
91};
92
93/* Check if X (or any sub-rtx of X) is a PACIASP/PACIBSP instruction. */
94static bool
95aarch64_pac_insn_p (rtx x)
96{
97 if (!INSN_P (x))
98 return x;
99
100 subrtx_var_iterator::array_type array;
101 FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (x), ALL)
102 {
103 rtx sub = *iter;
104 if (sub && GET_CODE (sub) == UNSPEC)
105 {
106 int unspec_val = XINT (sub, 1);
107 switch (unspec_val)
108 {
8fc16d72
ST
109 case UNSPEC_PACIASP:
110 /* fall-through. */
111 case UNSPEC_PACIBSP:
b5f794b4
SD
112 return true;
113
114 default:
115 return false;
116 }
117 iter.skip_subrtxes ();
118 }
119 }
120 return false;
121}
122
123/* Insert the BTI instruction. */
124/* This is implemented as a late RTL pass that runs before branch
125 shortening and does the following. */
126static unsigned int
127rest_of_insert_bti (void)
128{
129 timevar_push (TV_MACH_DEP);
130
131 rtx bti_insn;
132 rtx_insn *insn;
133 basic_block bb;
134
135 /* Since a Branch Target Exception can only be triggered by an indirect call,
136 we exempt function that are only called directly. We also exempt
137 functions that are already protected by Return Address Signing (PACIASP/
138 PACIBSP). For all other cases insert a BTI C at the beginning of the
139 function. */
140 if (!cgraph_node::get (cfun->decl)->only_called_directly_p ())
141 {
142 bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
143 insn = BB_HEAD (bb);
144 if (!aarch64_pac_insn_p (get_first_nonnote_insn ()))
145 {
146 bti_insn = gen_bti_c ();
147 emit_insn_before (bti_insn, insn);
148 }
149 }
150
151 bb = 0;
152 FOR_EACH_BB_FN (bb, cfun)
153 {
154 for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
155 insn = NEXT_INSN (insn))
156 {
157 /* If a label is marked to be preserved or can be a non-local goto
158 target, it must be protected with a BTI J. The same applies to
159 NOTE_INSN_DELETED_LABEL since they are basically labels that might
160 be referenced via variables or constant pool. */
161 if ((LABEL_P (insn)
162 && (LABEL_PRESERVE_P (insn)
163 || bb->flags & BB_NON_LOCAL_GOTO_TARGET))
164 || (NOTE_P (insn)
165 && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))
166 {
167 bti_insn = gen_bti_j ();
168 emit_insn_after (bti_insn, insn);
169 continue;
170 }
171
172 /* There could still be more labels that are valid targets of a
173 BTI J instuction. To find them we start looking through the
174 JUMP_INSN. If it jumps to a jump table, then we find all labels
175 of the jump table to protect with a BTI J. */
176 if (JUMP_P (insn))
177 {
178 rtx_jump_table_data *table;
179 if (tablejump_p (insn, NULL, &table))
180 {
181 rtvec vec = table->get_labels ();
182 int j;
183 rtx_insn *label;
184
185 for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
186 {
187 label = as_a <rtx_insn *> (XEXP (RTVEC_ELT (vec, j), 0));
188 bti_insn = gen_bti_j ();
189 emit_insn_after (bti_insn, label);
190 }
191 }
192 }
193
194 /* Also look for calls to setjmp () which would be marked with
195 REG_SETJMP note and put a BTI J after. This is where longjump ()
196 will return. */
197 if (CALL_P (insn) && (find_reg_note (insn, REG_SETJMP, NULL)))
198 {
199 bti_insn = gen_bti_j ();
200 emit_insn_after (bti_insn, insn);
201 continue;
202 }
203 }
204 }
205
206 timevar_pop (TV_MACH_DEP);
207 return 0;
208}
209
210
211class pass_insert_bti : public rtl_opt_pass
212{
213public:
214 pass_insert_bti (gcc::context *ctxt)
215 : rtl_opt_pass (pass_data_insert_bti, ctxt)
216 {}
217
218 /* opt_pass methods: */
219 virtual bool gate (function *)
220 {
221 return aarch64_bti_enabled ();
222 }
223
224 virtual unsigned int execute (function *)
225 {
226 return rest_of_insert_bti ();
227 }
228
229}; // class pass_insert_bti
230
231} // anon namespace
232
233rtl_opt_pass *
234make_pass_insert_bti (gcc::context *ctxt)
235{
236 return new pass_insert_bti (ctxt);
237}