diff options
Diffstat (limited to 'meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch')
-rw-r--r-- | meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch | 2154 |
1 files changed, 2154 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch new file mode 100644 index 0000000000..a9d6e5ff2d --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch | |||
@@ -0,0 +1,2154 @@ | |||
1 | From 6140c2c0bb2b61e69d0da84315e0433ff3520aaa Mon Sep 17 00:00:00 2001 | ||
2 | From: "H.J. Lu" <hjl.tools@gmail.com> | ||
3 | Date: Sat, 6 Jan 2018 22:29:55 -0800 | ||
4 | Subject: [PATCH 04/12] x86: Add -mindirect-branch= | ||
5 | |||
6 | Add -mindirect-branch= option to convert indirect call and jump to call | ||
7 | and return thunks. The default is 'keep', which keeps indirect call and | ||
8 | jump unmodified. 'thunk' converts indirect call and jump to call and | ||
9 | return thunk. 'thunk-inline' converts indirect call and jump to inlined | ||
10 | call and return thunk. 'thunk-extern' converts indirect call and jump to | ||
11 | external call and return thunk provided in a separate object file. You | ||
12 | can control this behavior for a specific function by using the function | ||
13 | attribute indirect_branch. | ||
14 | |||
15 | 2 kinds of thunks are geneated. Memory thunk where the function address | ||
16 | is at the top of the stack: | ||
17 | |||
18 | __x86_indirect_thunk: | ||
19 | call L2 | ||
20 | L1: | ||
21 | pause | ||
22 | lfence | ||
23 | jmp L1 | ||
24 | L2: | ||
25 | lea 8(%rsp), %rsp|lea 4(%esp), %esp | ||
26 | ret | ||
27 | |||
28 | Indirect jmp via memory, "jmp mem", is converted to | ||
29 | |||
30 | push memory | ||
31 | jmp __x86_indirect_thunk | ||
32 | |||
33 | Indirect call via memory, "call mem", is converted to | ||
34 | |||
35 | jmp L2 | ||
36 | L1: | ||
37 | push [mem] | ||
38 | jmp __x86_indirect_thunk | ||
39 | L2: | ||
40 | call L1 | ||
41 | |||
42 | Register thunk where the function address is in a register, reg: | ||
43 | |||
44 | __x86_indirect_thunk_reg: | ||
45 | call L2 | ||
46 | L1: | ||
47 | pause | ||
48 | lfence | ||
49 | jmp L1 | ||
50 | L2: | ||
51 | movq %reg, (%rsp)|movl %reg, (%esp) | ||
52 | ret | ||
53 | |||
54 | where reg is one of (r|e)ax, (r|e)dx, (r|e)cx, (r|e)bx, (r|e)si, (r|e)di, | ||
55 | (r|e)bp, r8, r9, r10, r11, r12, r13, r14 and r15. | ||
56 | |||
57 | Indirect jmp via register, "jmp reg", is converted to | ||
58 | |||
59 | jmp __x86_indirect_thunk_reg | ||
60 | |||
61 | Indirect call via register, "call reg", is converted to | ||
62 | |||
63 | call __x86_indirect_thunk_reg | ||
64 | |||
65 | gcc/ | ||
66 | |||
67 | Backport from mainline | ||
68 | 2018-01-14 H.J. Lu <hongjiu.lu@intel.com> | ||
69 | |||
70 | * config/i386/i386-opts.h (indirect_branch): New. | ||
71 | * config/i386/i386-protos.h (ix86_output_indirect_jmp): Likewise. | ||
72 | * config/i386/i386.c (ix86_using_red_zone): Disallow red-zone | ||
73 | with local indirect jump when converting indirect call and jump. | ||
74 | (ix86_set_indirect_branch_type): New. | ||
75 | (ix86_set_current_function): Call ix86_set_indirect_branch_type. | ||
76 | (indirectlabelno): New. | ||
77 | (indirect_thunk_needed): Likewise. | ||
78 | (indirect_thunk_bnd_needed): Likewise. | ||
79 | (indirect_thunks_used): Likewise. | ||
80 | (indirect_thunks_bnd_used): Likewise. | ||
81 | (INDIRECT_LABEL): Likewise. | ||
82 | (indirect_thunk_name): Likewise. | ||
83 | (output_indirect_thunk): Likewise. | ||
84 | (output_indirect_thunk_function): Likewise. | ||
85 | (ix86_output_indirect_branch_via_reg): Likewise. | ||
86 | (ix86_output_indirect_branch_via_push): Likewise. | ||
87 | (ix86_output_indirect_branch): Likewise. | ||
88 | (ix86_output_indirect_jmp): Likewise. | ||
89 | (ix86_code_end): Call output_indirect_thunk_function if needed. | ||
90 | (ix86_output_call_insn): Call ix86_output_indirect_branch if | ||
91 | needed. | ||
92 | (ix86_handle_fndecl_attribute): Handle indirect_branch. | ||
93 | (ix86_attribute_table): Add indirect_branch. | ||
94 | * config/i386/i386.h (machine_function): Add indirect_branch_type | ||
95 | and has_local_indirect_jump. | ||
96 | * config/i386/i386.md (indirect_jump): Set has_local_indirect_jump | ||
97 | to true. | ||
98 | (tablejump): Likewise. | ||
99 | (*indirect_jump): Use ix86_output_indirect_jmp. | ||
100 | (*tablejump_1): Likewise. | ||
101 | (simple_return_indirect_internal): Likewise. | ||
102 | * config/i386/i386.opt (mindirect-branch=): New option. | ||
103 | (indirect_branch): New. | ||
104 | (keep): Likewise. | ||
105 | (thunk): Likewise. | ||
106 | (thunk-inline): Likewise. | ||
107 | (thunk-extern): Likewise. | ||
108 | * doc/extend.texi: Document indirect_branch function attribute. | ||
109 | * doc/invoke.texi: Document -mindirect-branch= option. | ||
110 | |||
111 | gcc/testsuite/ | ||
112 | |||
113 | Backport from mainline | ||
114 | 2018-01-14 H.J. Lu <hongjiu.lu@intel.com> | ||
115 | |||
116 | * gcc.target/i386/indirect-thunk-1.c: New test. | ||
117 | * gcc.target/i386/indirect-thunk-2.c: Likewise. | ||
118 | * gcc.target/i386/indirect-thunk-3.c: Likewise. | ||
119 | * gcc.target/i386/indirect-thunk-4.c: Likewise. | ||
120 | * gcc.target/i386/indirect-thunk-5.c: Likewise. | ||
121 | * gcc.target/i386/indirect-thunk-6.c: Likewise. | ||
122 | * gcc.target/i386/indirect-thunk-7.c: Likewise. | ||
123 | * gcc.target/i386/indirect-thunk-attr-1.c: Likewise. | ||
124 | * gcc.target/i386/indirect-thunk-attr-2.c: Likewise. | ||
125 | * gcc.target/i386/indirect-thunk-attr-3.c: Likewise. | ||
126 | * gcc.target/i386/indirect-thunk-attr-4.c: Likewise. | ||
127 | * gcc.target/i386/indirect-thunk-attr-5.c: Likewise. | ||
128 | * gcc.target/i386/indirect-thunk-attr-6.c: Likewise. | ||
129 | * gcc.target/i386/indirect-thunk-attr-7.c: Likewise. | ||
130 | * gcc.target/i386/indirect-thunk-attr-8.c: Likewise. | ||
131 | * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise. | ||
132 | * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise. | ||
133 | * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise. | ||
134 | * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise. | ||
135 | * gcc.target/i386/indirect-thunk-extern-1.c: Likewise. | ||
136 | * gcc.target/i386/indirect-thunk-extern-2.c: Likewise. | ||
137 | * gcc.target/i386/indirect-thunk-extern-3.c: Likewise. | ||
138 | * gcc.target/i386/indirect-thunk-extern-4.c: Likewise. | ||
139 | * gcc.target/i386/indirect-thunk-extern-5.c: Likewise. | ||
140 | * gcc.target/i386/indirect-thunk-extern-6.c: Likewise. | ||
141 | * gcc.target/i386/indirect-thunk-extern-7.c: Likewise. | ||
142 | * gcc.target/i386/indirect-thunk-inline-1.c: Likewise. | ||
143 | * gcc.target/i386/indirect-thunk-inline-2.c: Likewise. | ||
144 | * gcc.target/i386/indirect-thunk-inline-3.c: Likewise. | ||
145 | * gcc.target/i386/indirect-thunk-inline-4.c: Likewise. | ||
146 | * gcc.target/i386/indirect-thunk-inline-5.c: Likewise. | ||
147 | * gcc.target/i386/indirect-thunk-inline-6.c: Likewise. | ||
148 | * gcc.target/i386/indirect-thunk-inline-7.c: Likewise. | ||
149 | |||
150 | Upstream-Status: Pending | ||
151 | |||
152 | Signed-off-by: Juro Bystricky <juro.bystricky@intel.com> | ||
153 | |||
154 | --- | ||
155 | gcc/config/i386/i386-opts.h | 13 + | ||
156 | gcc/config/i386/i386-protos.h | 1 + | ||
157 | gcc/config/i386/i386.c | 639 ++++++++++++++++++++- | ||
158 | gcc/config/i386/i386.h | 7 + | ||
159 | gcc/config/i386/i386.md | 26 +- | ||
160 | gcc/config/i386/i386.opt | 20 + | ||
161 | gcc/doc/extend.texi | 10 + | ||
162 | gcc/doc/invoke.texi | 13 +- | ||
163 | gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 20 + | ||
164 | gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 20 + | ||
165 | gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 21 + | ||
166 | gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 21 + | ||
167 | gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 17 + | ||
168 | gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 18 + | ||
169 | gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 44 ++ | ||
170 | .../gcc.target/i386/indirect-thunk-attr-1.c | 23 + | ||
171 | .../gcc.target/i386/indirect-thunk-attr-2.c | 21 + | ||
172 | .../gcc.target/i386/indirect-thunk-attr-3.c | 23 + | ||
173 | .../gcc.target/i386/indirect-thunk-attr-4.c | 22 + | ||
174 | .../gcc.target/i386/indirect-thunk-attr-5.c | 22 + | ||
175 | .../gcc.target/i386/indirect-thunk-attr-6.c | 21 + | ||
176 | .../gcc.target/i386/indirect-thunk-attr-7.c | 44 ++ | ||
177 | .../gcc.target/i386/indirect-thunk-attr-8.c | 42 ++ | ||
178 | .../gcc.target/i386/indirect-thunk-bnd-1.c | 20 + | ||
179 | .../gcc.target/i386/indirect-thunk-bnd-2.c | 21 + | ||
180 | .../gcc.target/i386/indirect-thunk-bnd-3.c | 19 + | ||
181 | .../gcc.target/i386/indirect-thunk-bnd-4.c | 20 + | ||
182 | .../gcc.target/i386/indirect-thunk-extern-1.c | 19 + | ||
183 | .../gcc.target/i386/indirect-thunk-extern-2.c | 19 + | ||
184 | .../gcc.target/i386/indirect-thunk-extern-3.c | 20 + | ||
185 | .../gcc.target/i386/indirect-thunk-extern-4.c | 20 + | ||
186 | .../gcc.target/i386/indirect-thunk-extern-5.c | 16 + | ||
187 | .../gcc.target/i386/indirect-thunk-extern-6.c | 17 + | ||
188 | .../gcc.target/i386/indirect-thunk-extern-7.c | 43 ++ | ||
189 | .../gcc.target/i386/indirect-thunk-inline-1.c | 20 + | ||
190 | .../gcc.target/i386/indirect-thunk-inline-2.c | 20 + | ||
191 | .../gcc.target/i386/indirect-thunk-inline-3.c | 21 + | ||
192 | .../gcc.target/i386/indirect-thunk-inline-4.c | 21 + | ||
193 | .../gcc.target/i386/indirect-thunk-inline-5.c | 17 + | ||
194 | .../gcc.target/i386/indirect-thunk-inline-6.c | 18 + | ||
195 | .../gcc.target/i386/indirect-thunk-inline-7.c | 44 ++ | ||
196 | 41 files changed, 1486 insertions(+), 17 deletions(-) | ||
197 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | ||
198 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | ||
199 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | ||
200 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | ||
201 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | ||
202 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | ||
203 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | ||
204 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c | ||
205 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c | ||
206 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c | ||
207 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c | ||
208 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c | ||
209 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c | ||
210 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c | ||
211 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c | ||
212 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c | ||
213 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c | ||
214 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c | ||
215 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c | ||
216 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c | ||
217 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c | ||
218 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c | ||
219 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c | ||
220 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c | ||
221 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c | ||
222 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c | ||
223 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c | ||
224 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c | ||
225 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c | ||
226 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c | ||
227 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c | ||
228 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c | ||
229 | create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c | ||
230 | |||
231 | diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h | ||
232 | index b7f92e3..cc21152 100644 | ||
233 | --- a/gcc/config/i386/i386-opts.h | ||
234 | +++ b/gcc/config/i386/i386-opts.h | ||
235 | @@ -99,4 +99,17 @@ enum stack_protector_guard { | ||
236 | SSP_GLOBAL /* global canary */ | ||
237 | }; | ||
238 | |||
239 | +/* This is used to mitigate variant #2 of the speculative execution | ||
240 | + vulnerabilities on x86 processors identified by CVE-2017-5715, aka | ||
241 | + Spectre. They convert indirect branches and function returns to | ||
242 | + call and return thunks to avoid speculative execution via indirect | ||
243 | + call, jmp and ret. */ | ||
244 | +enum indirect_branch { | ||
245 | + indirect_branch_unset = 0, | ||
246 | + indirect_branch_keep, | ||
247 | + indirect_branch_thunk, | ||
248 | + indirect_branch_thunk_inline, | ||
249 | + indirect_branch_thunk_extern | ||
250 | +}; | ||
251 | + | ||
252 | #endif | ||
253 | diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h | ||
254 | index ff47bc1..eca4cbf 100644 | ||
255 | --- a/gcc/config/i386/i386-protos.h | ||
256 | +++ b/gcc/config/i386/i386-protos.h | ||
257 | @@ -311,6 +311,7 @@ extern enum attr_cpu ix86_schedule; | ||
258 | #endif | ||
259 | |||
260 | extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op); | ||
261 | +extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p); | ||
262 | extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load, | ||
263 | enum machine_mode mode); | ||
264 | |||
265 | diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c | ||
266 | index 6c98f75..0b9fc4d 100644 | ||
267 | --- a/gcc/config/i386/i386.c | ||
268 | +++ b/gcc/config/i386/i386.c | ||
269 | @@ -3662,12 +3662,23 @@ make_pass_stv (gcc::context *ctxt) | ||
270 | return new pass_stv (ctxt); | ||
271 | } | ||
272 | |||
273 | -/* Return true if a red-zone is in use. */ | ||
274 | +/* Return true if a red-zone is in use. We can't use red-zone when | ||
275 | + there are local indirect jumps, like "indirect_jump" or "tablejump", | ||
276 | + which jumps to another place in the function, since "call" in the | ||
277 | + indirect thunk pushes the return address onto stack, destroying | ||
278 | + red-zone. | ||
279 | + | ||
280 | + TODO: If we can reserve the first 2 WORDs, for PUSH and, another | ||
281 | + for CALL, in red-zone, we can allow local indirect jumps with | ||
282 | + indirect thunk. */ | ||
283 | |||
284 | bool | ||
285 | ix86_using_red_zone (void) | ||
286 | { | ||
287 | - return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI; | ||
288 | + return (TARGET_RED_ZONE | ||
289 | + && !TARGET_64BIT_MS_ABI | ||
290 | + && (!cfun->machine->has_local_indirect_jump | ||
291 | + || cfun->machine->indirect_branch_type == indirect_branch_keep)); | ||
292 | } | ||
293 | |||
294 | /* Return a string that documents the current -m options. The caller is | ||
295 | @@ -6350,6 +6361,37 @@ ix86_reset_previous_fndecl (void) | ||
296 | ix86_previous_fndecl = NULL_TREE; | ||
297 | } | ||
298 | |||
299 | +/* Set the indirect_branch_type field from the function FNDECL. */ | ||
300 | + | ||
301 | +static void | ||
302 | +ix86_set_indirect_branch_type (tree fndecl) | ||
303 | +{ | ||
304 | + if (cfun->machine->indirect_branch_type == indirect_branch_unset) | ||
305 | + { | ||
306 | + tree attr = lookup_attribute ("indirect_branch", | ||
307 | + DECL_ATTRIBUTES (fndecl)); | ||
308 | + if (attr != NULL) | ||
309 | + { | ||
310 | + tree args = TREE_VALUE (attr); | ||
311 | + if (args == NULL) | ||
312 | + gcc_unreachable (); | ||
313 | + tree cst = TREE_VALUE (args); | ||
314 | + if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0) | ||
315 | + cfun->machine->indirect_branch_type = indirect_branch_keep; | ||
316 | + else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0) | ||
317 | + cfun->machine->indirect_branch_type = indirect_branch_thunk; | ||
318 | + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0) | ||
319 | + cfun->machine->indirect_branch_type = indirect_branch_thunk_inline; | ||
320 | + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0) | ||
321 | + cfun->machine->indirect_branch_type = indirect_branch_thunk_extern; | ||
322 | + else | ||
323 | + gcc_unreachable (); | ||
324 | + } | ||
325 | + else | ||
326 | + cfun->machine->indirect_branch_type = ix86_indirect_branch; | ||
327 | + } | ||
328 | +} | ||
329 | + | ||
330 | /* Establish appropriate back-end context for processing the function | ||
331 | FNDECL. The argument might be NULL to indicate processing at top | ||
332 | level, outside of any function scope. */ | ||
333 | @@ -6360,7 +6402,13 @@ ix86_set_current_function (tree fndecl) | ||
334 | several times in the course of compiling a function, and we don't want to | ||
335 | slow things down too much or call target_reinit when it isn't safe. */ | ||
336 | if (fndecl == ix86_previous_fndecl) | ||
337 | - return; | ||
338 | + { | ||
339 | + /* There may be 2 function bodies for the same function FNDECL, | ||
340 | + one is extern inline and one isn't. */ | ||
341 | + if (fndecl != NULL_TREE) | ||
342 | + ix86_set_indirect_branch_type (fndecl); | ||
343 | + return; | ||
344 | + } | ||
345 | |||
346 | tree old_tree; | ||
347 | if (ix86_previous_fndecl == NULL_TREE) | ||
348 | @@ -6377,6 +6425,8 @@ ix86_set_current_function (tree fndecl) | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | + ix86_set_indirect_branch_type (fndecl); | ||
353 | + | ||
354 | tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl); | ||
355 | if (new_tree == NULL_TREE) | ||
356 | new_tree = target_option_default_node; | ||
357 | @@ -10962,6 +11012,220 @@ ix86_setup_frame_addresses (void) | ||
358 | # endif | ||
359 | #endif | ||
360 | |||
361 | +/* Label count for call and return thunks. It is used to make unique | ||
362 | + labels in call and return thunks. */ | ||
363 | +static int indirectlabelno; | ||
364 | + | ||
365 | +/* True if call and return thunk functions are needed. */ | ||
366 | +static bool indirect_thunk_needed = false; | ||
367 | +/* True if call and return thunk functions with the BND prefix are | ||
368 | + needed. */ | ||
369 | +static bool indirect_thunk_bnd_needed = false; | ||
370 | + | ||
371 | +/* Bit masks of integer registers, which contain branch target, used | ||
372 | + by call and return thunks functions. */ | ||
373 | +static int indirect_thunks_used; | ||
374 | +/* Bit masks of integer registers, which contain branch target, used | ||
375 | + by call and return thunks functions with the BND prefix. */ | ||
376 | +static int indirect_thunks_bnd_used; | ||
377 | + | ||
378 | +#ifndef INDIRECT_LABEL | ||
379 | +# define INDIRECT_LABEL "LIND" | ||
380 | +#endif | ||
381 | + | ||
382 | +/* Fills in the label name that should be used for the indirect thunk. */ | ||
383 | + | ||
384 | +static void | ||
385 | +indirect_thunk_name (char name[32], int regno, bool need_bnd_p) | ||
386 | +{ | ||
387 | + if (USE_HIDDEN_LINKONCE) | ||
388 | + { | ||
389 | + const char *bnd = need_bnd_p ? "_bnd" : ""; | ||
390 | + if (regno >= 0) | ||
391 | + { | ||
392 | + const char *reg_prefix; | ||
393 | + if (LEGACY_INT_REGNO_P (regno)) | ||
394 | + reg_prefix = TARGET_64BIT ? "r" : "e"; | ||
395 | + else | ||
396 | + reg_prefix = ""; | ||
397 | + sprintf (name, "__x86_indirect_thunk%s_%s%s", | ||
398 | + bnd, reg_prefix, reg_names[regno]); | ||
399 | + } | ||
400 | + else | ||
401 | + sprintf (name, "__x86_indirect_thunk%s", bnd); | ||
402 | + } | ||
403 | + else | ||
404 | + { | ||
405 | + if (regno >= 0) | ||
406 | + { | ||
407 | + if (need_bnd_p) | ||
408 | + ASM_GENERATE_INTERNAL_LABEL (name, "LITBR", regno); | ||
409 | + else | ||
410 | + ASM_GENERATE_INTERNAL_LABEL (name, "LITR", regno); | ||
411 | + } | ||
412 | + else | ||
413 | + { | ||
414 | + if (need_bnd_p) | ||
415 | + ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0); | ||
416 | + else | ||
417 | + ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0); | ||
418 | + } | ||
419 | + } | ||
420 | +} | ||
421 | + | ||
422 | +/* Output a call and return thunk for indirect branch. If BND_P is | ||
423 | + true, the BND prefix is needed. If REGNO != -1, the function | ||
424 | + address is in REGNO and the call and return thunk looks like: | ||
425 | + | ||
426 | + call L2 | ||
427 | + L1: | ||
428 | + pause | ||
429 | + jmp L1 | ||
430 | + L2: | ||
431 | + mov %REG, (%sp) | ||
432 | + ret | ||
433 | + | ||
434 | + Otherwise, the function address is on the top of stack and the | ||
435 | + call and return thunk looks like: | ||
436 | + | ||
437 | + call L2 | ||
438 | + L1: | ||
439 | + pause | ||
440 | + jmp L1 | ||
441 | + L2: | ||
442 | + lea WORD_SIZE(%sp), %sp | ||
443 | + ret | ||
444 | + */ | ||
445 | + | ||
446 | +static void | ||
447 | +output_indirect_thunk (bool need_bnd_p, int regno) | ||
448 | +{ | ||
449 | + char indirectlabel1[32]; | ||
450 | + char indirectlabel2[32]; | ||
451 | + | ||
452 | + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL, | ||
453 | + indirectlabelno++); | ||
454 | + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL, | ||
455 | + indirectlabelno++); | ||
456 | + | ||
457 | + /* Call */ | ||
458 | + if (need_bnd_p) | ||
459 | + fputs ("\tbnd call\t", asm_out_file); | ||
460 | + else | ||
461 | + fputs ("\tcall\t", asm_out_file); | ||
462 | + assemble_name_raw (asm_out_file, indirectlabel2); | ||
463 | + fputc ('\n', asm_out_file); | ||
464 | + | ||
465 | + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); | ||
466 | + | ||
467 | + /* Pause + lfence. */ | ||
468 | + fprintf (asm_out_file, "\tpause\n\tlfence\n"); | ||
469 | + | ||
470 | + /* Jump. */ | ||
471 | + fputs ("\tjmp\t", asm_out_file); | ||
472 | + assemble_name_raw (asm_out_file, indirectlabel1); | ||
473 | + fputc ('\n', asm_out_file); | ||
474 | + | ||
475 | + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); | ||
476 | + | ||
477 | + if (regno >= 0) | ||
478 | + { | ||
479 | + /* MOV. */ | ||
480 | + rtx xops[2]; | ||
481 | + xops[0] = gen_rtx_MEM (word_mode, stack_pointer_rtx); | ||
482 | + xops[1] = gen_rtx_REG (word_mode, regno); | ||
483 | + output_asm_insn ("mov\t{%1, %0|%0, %1}", xops); | ||
484 | + } | ||
485 | + else | ||
486 | + { | ||
487 | + /* LEA. */ | ||
488 | + rtx xops[2]; | ||
489 | + xops[0] = stack_pointer_rtx; | ||
490 | + xops[1] = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD); | ||
491 | + output_asm_insn ("lea\t{%E1, %0|%0, %E1}", xops); | ||
492 | + } | ||
493 | + | ||
494 | + if (need_bnd_p) | ||
495 | + fputs ("\tbnd ret\n", asm_out_file); | ||
496 | + else | ||
497 | + fputs ("\tret\n", asm_out_file); | ||
498 | +} | ||
499 | + | ||
500 | +/* Output a funtion with a call and return thunk for indirect branch. | ||
501 | + If BND_P is true, the BND prefix is needed. If REGNO != -1, the | ||
502 | + function address is in REGNO. Otherwise, the function address is | ||
503 | + on the top of stack. */ | ||
504 | + | ||
505 | +static void | ||
506 | +output_indirect_thunk_function (bool need_bnd_p, int regno) | ||
507 | +{ | ||
508 | + char name[32]; | ||
509 | + tree decl; | ||
510 | + | ||
511 | + /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */ | ||
512 | + indirect_thunk_name (name, regno, need_bnd_p); | ||
513 | + decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, | ||
514 | + get_identifier (name), | ||
515 | + build_function_type_list (void_type_node, NULL_TREE)); | ||
516 | + DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL, | ||
517 | + NULL_TREE, void_type_node); | ||
518 | + TREE_PUBLIC (decl) = 1; | ||
519 | + TREE_STATIC (decl) = 1; | ||
520 | + DECL_IGNORED_P (decl) = 1; | ||
521 | + | ||
522 | +#if TARGET_MACHO | ||
523 | + if (TARGET_MACHO) | ||
524 | + { | ||
525 | + switch_to_section (darwin_sections[picbase_thunk_section]); | ||
526 | + fputs ("\t.weak_definition\t", asm_out_file); | ||
527 | + assemble_name (asm_out_file, name); | ||
528 | + fputs ("\n\t.private_extern\t", asm_out_file); | ||
529 | + assemble_name (asm_out_file, name); | ||
530 | + putc ('\n', asm_out_file); | ||
531 | + ASM_OUTPUT_LABEL (asm_out_file, name); | ||
532 | + DECL_WEAK (decl) = 1; | ||
533 | + } | ||
534 | + else | ||
535 | +#endif | ||
536 | + if (USE_HIDDEN_LINKONCE) | ||
537 | + { | ||
538 | + cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl)); | ||
539 | + | ||
540 | + targetm.asm_out.unique_section (decl, 0); | ||
541 | + switch_to_section (get_named_section (decl, NULL, 0)); | ||
542 | + | ||
543 | + targetm.asm_out.globalize_label (asm_out_file, name); | ||
544 | + fputs ("\t.hidden\t", asm_out_file); | ||
545 | + assemble_name (asm_out_file, name); | ||
546 | + putc ('\n', asm_out_file); | ||
547 | + ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl); | ||
548 | + } | ||
549 | + else | ||
550 | + { | ||
551 | + switch_to_section (text_section); | ||
552 | + ASM_OUTPUT_LABEL (asm_out_file, name); | ||
553 | + } | ||
554 | + | ||
555 | + DECL_INITIAL (decl) = make_node (BLOCK); | ||
556 | + current_function_decl = decl; | ||
557 | + allocate_struct_function (decl, false); | ||
558 | + init_function_start (decl); | ||
559 | + /* We're about to hide the function body from callees of final_* by | ||
560 | + emitting it directly; tell them we're a thunk, if they care. */ | ||
561 | + cfun->is_thunk = true; | ||
562 | + first_function_block_is_cold = false; | ||
563 | + /* Make sure unwind info is emitted for the thunk if needed. */ | ||
564 | + final_start_function (emit_barrier (), asm_out_file, 1); | ||
565 | + | ||
566 | + output_indirect_thunk (need_bnd_p, regno); | ||
567 | + | ||
568 | + final_end_function (); | ||
569 | + init_insn_lengths (); | ||
570 | + free_after_compilation (cfun); | ||
571 | + set_cfun (NULL); | ||
572 | + current_function_decl = NULL; | ||
573 | +} | ||
574 | + | ||
575 | static int pic_labels_used; | ||
576 | |||
577 | /* Fills in the label name that should be used for a pc thunk for | ||
578 | @@ -10988,11 +11252,32 @@ ix86_code_end (void) | ||
579 | rtx xops[2]; | ||
580 | int regno; | ||
581 | |||
582 | + if (indirect_thunk_needed) | ||
583 | + output_indirect_thunk_function (false, -1); | ||
584 | + if (indirect_thunk_bnd_needed) | ||
585 | + output_indirect_thunk_function (true, -1); | ||
586 | + | ||
587 | + for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++) | ||
588 | + { | ||
589 | + int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1; | ||
590 | + if ((indirect_thunks_used & (1 << i))) | ||
591 | + output_indirect_thunk_function (false, regno); | ||
592 | + | ||
593 | + if ((indirect_thunks_bnd_used & (1 << i))) | ||
594 | + output_indirect_thunk_function (true, regno); | ||
595 | + } | ||
596 | + | ||
597 | for (regno = AX_REG; regno <= SP_REG; regno++) | ||
598 | { | ||
599 | char name[32]; | ||
600 | tree decl; | ||
601 | |||
602 | + if ((indirect_thunks_used & (1 << regno))) | ||
603 | + output_indirect_thunk_function (false, regno); | ||
604 | + | ||
605 | + if ((indirect_thunks_bnd_used & (1 << regno))) | ||
606 | + output_indirect_thunk_function (true, regno); | ||
607 | + | ||
608 | if (!(pic_labels_used & (1 << regno))) | ||
609 | continue; | ||
610 | |||
611 | @@ -27369,12 +27654,292 @@ ix86_nopic_noplt_attribute_p (rtx call_op) | ||
612 | return false; | ||
613 | } | ||
614 | |||
615 | +/* Output indirect branch via a call and return thunk. CALL_OP is a | ||
616 | + register which contains the branch target. XASM is the assembly | ||
617 | + template for CALL_OP. Branch is a tail call if SIBCALL_P is true. | ||
618 | + A normal call is converted to: | ||
619 | + | ||
620 | + call __x86_indirect_thunk_reg | ||
621 | + | ||
622 | + and a tail call is converted to: | ||
623 | + | ||
624 | + jmp __x86_indirect_thunk_reg | ||
625 | + */ | ||
626 | + | ||
627 | +static void | ||
628 | +ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) | ||
629 | +{ | ||
630 | + char thunk_name_buf[32]; | ||
631 | + char *thunk_name; | ||
632 | + bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn); | ||
633 | + int regno = REGNO (call_op); | ||
634 | + | ||
635 | + if (cfun->machine->indirect_branch_type | ||
636 | + != indirect_branch_thunk_inline) | ||
637 | + { | ||
638 | + if (cfun->machine->indirect_branch_type == indirect_branch_thunk) | ||
639 | + { | ||
640 | + int i = regno; | ||
641 | + if (i >= FIRST_REX_INT_REG) | ||
642 | + i -= (FIRST_REX_INT_REG - LAST_INT_REG - 1); | ||
643 | + if (need_bnd_p) | ||
644 | + indirect_thunks_bnd_used |= 1 << i; | ||
645 | + else | ||
646 | + indirect_thunks_used |= 1 << i; | ||
647 | + } | ||
648 | + indirect_thunk_name (thunk_name_buf, regno, need_bnd_p); | ||
649 | + thunk_name = thunk_name_buf; | ||
650 | + } | ||
651 | + else | ||
652 | + thunk_name = NULL; | ||
653 | + | ||
654 | + if (sibcall_p) | ||
655 | + { | ||
656 | + if (thunk_name != NULL) | ||
657 | + { | ||
658 | + if (need_bnd_p) | ||
659 | + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); | ||
660 | + else | ||
661 | + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); | ||
662 | + } | ||
663 | + else | ||
664 | + output_indirect_thunk (need_bnd_p, regno); | ||
665 | + } | ||
666 | + else | ||
667 | + { | ||
668 | + if (thunk_name != NULL) | ||
669 | + { | ||
670 | + if (need_bnd_p) | ||
671 | + fprintf (asm_out_file, "\tbnd call\t%s\n", thunk_name); | ||
672 | + else | ||
673 | + fprintf (asm_out_file, "\tcall\t%s\n", thunk_name); | ||
674 | + return; | ||
675 | + } | ||
676 | + | ||
677 | + char indirectlabel1[32]; | ||
678 | + char indirectlabel2[32]; | ||
679 | + | ||
680 | + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, | ||
681 | + INDIRECT_LABEL, | ||
682 | + indirectlabelno++); | ||
683 | + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, | ||
684 | + INDIRECT_LABEL, | ||
685 | + indirectlabelno++); | ||
686 | + | ||
687 | + /* Jump. */ | ||
688 | + if (need_bnd_p) | ||
689 | + fputs ("\tbnd jmp\t", asm_out_file); | ||
690 | + else | ||
691 | + fputs ("\tjmp\t", asm_out_file); | ||
692 | + assemble_name_raw (asm_out_file, indirectlabel2); | ||
693 | + fputc ('\n', asm_out_file); | ||
694 | + | ||
695 | + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); | ||
696 | + | ||
697 | + if (thunk_name != NULL) | ||
698 | + { | ||
699 | + if (need_bnd_p) | ||
700 | + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); | ||
701 | + else | ||
702 | + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); | ||
703 | + } | ||
704 | + else | ||
705 | + output_indirect_thunk (need_bnd_p, regno); | ||
706 | + | ||
707 | + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); | ||
708 | + | ||
709 | + /* Call. */ | ||
710 | + if (need_bnd_p) | ||
711 | + fputs ("\tbnd call\t", asm_out_file); | ||
712 | + else | ||
713 | + fputs ("\tcall\t", asm_out_file); | ||
714 | + assemble_name_raw (asm_out_file, indirectlabel1); | ||
715 | + fputc ('\n', asm_out_file); | ||
716 | + } | ||
717 | +} | ||
718 | + | ||
719 | +/* Output indirect branch via a call and return thunk. CALL_OP is | ||
720 | + the branch target. XASM is the assembly template for CALL_OP. | ||
721 | + Branch is a tail call if SIBCALL_P is true. A normal call is | ||
722 | + converted to: | ||
723 | + | ||
724 | + jmp L2 | ||
725 | + L1: | ||
726 | + push CALL_OP | ||
727 | + jmp __x86_indirect_thunk | ||
728 | + L2: | ||
729 | + call L1 | ||
730 | + | ||
731 | + and a tail call is converted to: | ||
732 | + | ||
733 | + push CALL_OP | ||
734 | + jmp __x86_indirect_thunk | ||
735 | + */ | ||
736 | + | ||
737 | +static void | ||
738 | +ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm, | ||
739 | + bool sibcall_p) | ||
740 | +{ | ||
741 | + char thunk_name_buf[32]; | ||
742 | + char *thunk_name; | ||
743 | + char push_buf[64]; | ||
744 | + bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn); | ||
745 | + int regno = -1; | ||
746 | + | ||
747 | + if (cfun->machine->indirect_branch_type | ||
748 | + != indirect_branch_thunk_inline) | ||
749 | + { | ||
750 | + if (cfun->machine->indirect_branch_type == indirect_branch_thunk) | ||
751 | + { | ||
752 | + if (need_bnd_p) | ||
753 | + indirect_thunk_bnd_needed = true; | ||
754 | + else | ||
755 | + indirect_thunk_needed = true; | ||
756 | + } | ||
757 | + indirect_thunk_name (thunk_name_buf, regno, need_bnd_p); | ||
758 | + thunk_name = thunk_name_buf; | ||
759 | + } | ||
760 | + else | ||
761 | + thunk_name = NULL; | ||
762 | + | ||
763 | + snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s", | ||
764 | + TARGET_64BIT ? 'q' : 'l', xasm); | ||
765 | + | ||
766 | + if (sibcall_p) | ||
767 | + { | ||
768 | + output_asm_insn (push_buf, &call_op); | ||
769 | + if (thunk_name != NULL) | ||
770 | + { | ||
771 | + if (need_bnd_p) | ||
772 | + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); | ||
773 | + else | ||
774 | + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); | ||
775 | + } | ||
776 | + else | ||
777 | + output_indirect_thunk (need_bnd_p, regno); | ||
778 | + } | ||
779 | + else | ||
780 | + { | ||
781 | + char indirectlabel1[32]; | ||
782 | + char indirectlabel2[32]; | ||
783 | + | ||
784 | + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, | ||
785 | + INDIRECT_LABEL, | ||
786 | + indirectlabelno++); | ||
787 | + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, | ||
788 | + INDIRECT_LABEL, | ||
789 | + indirectlabelno++); | ||
790 | + | ||
791 | + /* Jump. */ | ||
792 | + if (need_bnd_p) | ||
793 | + fputs ("\tbnd jmp\t", asm_out_file); | ||
794 | + else | ||
795 | + fputs ("\tjmp\t", asm_out_file); | ||
796 | + assemble_name_raw (asm_out_file, indirectlabel2); | ||
797 | + fputc ('\n', asm_out_file); | ||
798 | + | ||
799 | + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); | ||
800 | + | ||
801 | + /* An external function may be called via GOT, instead of PLT. */ | ||
802 | + if (MEM_P (call_op)) | ||
803 | + { | ||
804 | + struct ix86_address parts; | ||
805 | + rtx addr = XEXP (call_op, 0); | ||
806 | + if (ix86_decompose_address (addr, &parts) | ||
807 | + && parts.base == stack_pointer_rtx) | ||
808 | + { | ||
809 | + /* Since call will adjust stack by -UNITS_PER_WORD, | ||
810 | + we must convert "disp(stack, index, scale)" to | ||
811 | + "disp+UNITS_PER_WORD(stack, index, scale)". */ | ||
812 | + if (parts.index) | ||
813 | + { | ||
814 | + addr = gen_rtx_MULT (Pmode, parts.index, | ||
815 | + GEN_INT (parts.scale)); | ||
816 | + addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, | ||
817 | + addr); | ||
818 | + } | ||
819 | + else | ||
820 | + addr = stack_pointer_rtx; | ||
821 | + | ||
822 | + rtx disp; | ||
823 | + if (parts.disp != NULL_RTX) | ||
824 | + disp = plus_constant (Pmode, parts.disp, | ||
825 | + UNITS_PER_WORD); | ||
826 | + else | ||
827 | + disp = GEN_INT (UNITS_PER_WORD); | ||
828 | + | ||
829 | + addr = gen_rtx_PLUS (Pmode, addr, disp); | ||
830 | + call_op = gen_rtx_MEM (GET_MODE (call_op), addr); | ||
831 | + } | ||
832 | + } | ||
833 | + | ||
834 | + output_asm_insn (push_buf, &call_op); | ||
835 | + | ||
836 | + if (thunk_name != NULL) | ||
837 | + { | ||
838 | + if (need_bnd_p) | ||
839 | + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); | ||
840 | + else | ||
841 | + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); | ||
842 | + } | ||
843 | + else | ||
844 | + output_indirect_thunk (need_bnd_p, regno); | ||
845 | + | ||
846 | + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); | ||
847 | + | ||
848 | + /* Call. */ | ||
849 | + if (need_bnd_p) | ||
850 | + fputs ("\tbnd call\t", asm_out_file); | ||
851 | + else | ||
852 | + fputs ("\tcall\t", asm_out_file); | ||
853 | + assemble_name_raw (asm_out_file, indirectlabel1); | ||
854 | + fputc ('\n', asm_out_file); | ||
855 | + } | ||
856 | +} | ||
857 | + | ||
858 | +/* Output indirect branch via a call and return thunk. CALL_OP is | ||
859 | + the branch target. XASM is the assembly template for CALL_OP. | ||
860 | + Branch is a tail call if SIBCALL_P is true. */ | ||
861 | + | ||
862 | +static void | ||
863 | +ix86_output_indirect_branch (rtx call_op, const char *xasm, | ||
864 | + bool sibcall_p) | ||
865 | +{ | ||
866 | + if (REG_P (call_op)) | ||
867 | + ix86_output_indirect_branch_via_reg (call_op, sibcall_p); | ||
868 | + else | ||
869 | + ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p); | ||
870 | +} | ||
871 | +/* Output indirect jump. CALL_OP is the jump target. Jump is a | ||
872 | + function return if RET_P is true. */ | ||
873 | + | ||
874 | +const char * | ||
875 | +ix86_output_indirect_jmp (rtx call_op, bool ret_p) | ||
876 | +{ | ||
877 | + if (cfun->machine->indirect_branch_type != indirect_branch_keep) | ||
878 | + { | ||
879 | + /* We can't have red-zone if this isn't a function return since | ||
880 | + "call" in the indirect thunk pushes the return address onto | ||
881 | + stack, destroying red-zone. */ | ||
882 | + if (!ret_p && ix86_red_zone_size != 0) | ||
883 | + gcc_unreachable (); | ||
884 | + | ||
885 | + ix86_output_indirect_branch (call_op, "%0", true); | ||
886 | + return ""; | ||
887 | + } | ||
888 | + else | ||
889 | + return "%!jmp\t%A0"; | ||
890 | +} | ||
891 | + | ||
892 | /* Output the assembly for a call instruction. */ | ||
893 | |||
894 | const char * | ||
895 | ix86_output_call_insn (rtx_insn *insn, rtx call_op) | ||
896 | { | ||
897 | bool direct_p = constant_call_address_operand (call_op, VOIDmode); | ||
898 | + bool output_indirect_p | ||
899 | + = (!TARGET_SEH | ||
900 | + && cfun->machine->indirect_branch_type != indirect_branch_keep); | ||
901 | bool seh_nop_p = false; | ||
902 | const char *xasm; | ||
903 | |||
904 | @@ -27383,7 +27948,13 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) | ||
905 | if (direct_p) | ||
906 | { | ||
907 | if (ix86_nopic_noplt_attribute_p (call_op)) | ||
908 | - xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; | ||
909 | + { | ||
910 | + direct_p = false; | ||
911 | + if (output_indirect_p) | ||
912 | + xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; | ||
913 | + else | ||
914 | + xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; | ||
915 | + } | ||
916 | else | ||
917 | xasm = "%!jmp\t%P0"; | ||
918 | } | ||
919 | @@ -27392,9 +27963,17 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) | ||
920 | else if (TARGET_SEH) | ||
921 | xasm = "%!rex.W jmp\t%A0"; | ||
922 | else | ||
923 | - xasm = "%!jmp\t%A0"; | ||
924 | + { | ||
925 | + if (output_indirect_p) | ||
926 | + xasm = "%0"; | ||
927 | + else | ||
928 | + xasm = "%!jmp\t%A0"; | ||
929 | + } | ||
930 | |||
931 | - output_asm_insn (xasm, &call_op); | ||
932 | + if (output_indirect_p && !direct_p) | ||
933 | + ix86_output_indirect_branch (call_op, xasm, true); | ||
934 | + else | ||
935 | + output_asm_insn (xasm, &call_op); | ||
936 | return ""; | ||
937 | } | ||
938 | |||
939 | @@ -27431,14 +28010,28 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) | ||
940 | if (direct_p) | ||
941 | { | ||
942 | if (ix86_nopic_noplt_attribute_p (call_op)) | ||
943 | - xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; | ||
944 | + { | ||
945 | + direct_p = false; | ||
946 | + if (output_indirect_p) | ||
947 | + xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; | ||
948 | + else | ||
949 | + xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; | ||
950 | + } | ||
951 | else | ||
952 | xasm = "%!call\t%P0"; | ||
953 | } | ||
954 | else | ||
955 | - xasm = "%!call\t%A0"; | ||
956 | + { | ||
957 | + if (output_indirect_p) | ||
958 | + xasm = "%0"; | ||
959 | + else | ||
960 | + xasm = "%!call\t%A0"; | ||
961 | + } | ||
962 | |||
963 | - output_asm_insn (xasm, &call_op); | ||
964 | + if (output_indirect_p && !direct_p) | ||
965 | + ix86_output_indirect_branch (call_op, xasm, false); | ||
966 | + else | ||
967 | + output_asm_insn (xasm, &call_op); | ||
968 | |||
969 | if (seh_nop_p) | ||
970 | return "nop"; | ||
971 | @@ -44836,7 +45429,7 @@ ix86_handle_struct_attribute (tree *node, tree name, tree, int, | ||
972 | } | ||
973 | |||
974 | static tree | ||
975 | -ix86_handle_fndecl_attribute (tree *node, tree name, tree, int, | ||
976 | +ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int, | ||
977 | bool *no_add_attrs) | ||
978 | { | ||
979 | if (TREE_CODE (*node) != FUNCTION_DECL) | ||
980 | @@ -44845,6 +45438,29 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree, int, | ||
981 | name); | ||
982 | *no_add_attrs = true; | ||
983 | } | ||
984 | + | ||
985 | + if (is_attribute_p ("indirect_branch", name)) | ||
986 | + { | ||
987 | + tree cst = TREE_VALUE (args); | ||
988 | + if (TREE_CODE (cst) != STRING_CST) | ||
989 | + { | ||
990 | + warning (OPT_Wattributes, | ||
991 | + "%qE attribute requires a string constant argument", | ||
992 | + name); | ||
993 | + *no_add_attrs = true; | ||
994 | + } | ||
995 | + else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0 | ||
996 | + && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0 | ||
997 | + && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0 | ||
998 | + && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0) | ||
999 | + { | ||
1000 | + warning (OPT_Wattributes, | ||
1001 | + "argument to %qE attribute is not " | ||
1002 | + "(keep|thunk|thunk-inline|thunk-extern)", name); | ||
1003 | + *no_add_attrs = true; | ||
1004 | + } | ||
1005 | + } | ||
1006 | + | ||
1007 | return NULL_TREE; | ||
1008 | } | ||
1009 | |||
1010 | @@ -49072,6 +49688,9 @@ static const struct attribute_spec ix86_attribute_table[] = | ||
1011 | false }, | ||
1012 | { "callee_pop_aggregate_return", 1, 1, false, true, true, | ||
1013 | ix86_handle_callee_pop_aggregate_return, true }, | ||
1014 | + { "indirect_branch", 1, 1, true, false, false, | ||
1015 | + ix86_handle_fndecl_attribute, false }, | ||
1016 | + | ||
1017 | /* End element. */ | ||
1018 | { NULL, 0, 0, false, false, false, NULL, false } | ||
1019 | }; | ||
1020 | diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h | ||
1021 | index 5414416..9dccdb0 100644 | ||
1022 | --- a/gcc/config/i386/i386.h | ||
1023 | +++ b/gcc/config/i386/i386.h | ||
1024 | @@ -2572,6 +2572,13 @@ struct GTY(()) machine_function { | ||
1025 | /* If true, it is safe to not save/restore DRAP register. */ | ||
1026 | BOOL_BITFIELD no_drap_save_restore : 1; | ||
1027 | |||
1028 | + /* How to generate indirec branch. */ | ||
1029 | + ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3; | ||
1030 | + | ||
1031 | + /* If true, the current function has local indirect jumps, like | ||
1032 | + "indirect_jump" or "tablejump". */ | ||
1033 | + BOOL_BITFIELD has_local_indirect_jump : 1; | ||
1034 | + | ||
1035 | /* If true, there is register available for argument passing. This | ||
1036 | is used only in ix86_function_ok_for_sibcall by 32-bit to determine | ||
1037 | if there is scratch register available for indirect sibcall. In | ||
1038 | diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md | ||
1039 | index d2bfe31..153e162 100644 | ||
1040 | --- a/gcc/config/i386/i386.md | ||
1041 | +++ b/gcc/config/i386/i386.md | ||
1042 | @@ -11807,13 +11807,18 @@ | ||
1043 | { | ||
1044 | if (TARGET_X32) | ||
1045 | operands[0] = convert_memory_address (word_mode, operands[0]); | ||
1046 | + cfun->machine->has_local_indirect_jump = true; | ||
1047 | }) | ||
1048 | |||
1049 | (define_insn "*indirect_jump" | ||
1050 | [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))] | ||
1051 | "" | ||
1052 | - "%!jmp\t%A0" | ||
1053 | - [(set_attr "type" "ibr") | ||
1054 | + "* return ix86_output_indirect_jmp (operands[0], false);" | ||
1055 | + [(set (attr "type") | ||
1056 | + (if_then_else (match_test "(cfun->machine->indirect_branch_type | ||
1057 | + != indirect_branch_keep)") | ||
1058 | + (const_string "multi") | ||
1059 | + (const_string "ibr"))) | ||
1060 | (set_attr "length_immediate" "0") | ||
1061 | (set_attr "maybe_prefix_bnd" "1")]) | ||
1062 | |||
1063 | @@ -11856,14 +11861,19 @@ | ||
1064 | |||
1065 | if (TARGET_X32) | ||
1066 | operands[0] = convert_memory_address (word_mode, operands[0]); | ||
1067 | + cfun->machine->has_local_indirect_jump = true; | ||
1068 | }) | ||
1069 | |||
1070 | (define_insn "*tablejump_1" | ||
1071 | [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw")) | ||
1072 | (use (label_ref (match_operand 1)))] | ||
1073 | "" | ||
1074 | - "%!jmp\t%A0" | ||
1075 | - [(set_attr "type" "ibr") | ||
1076 | + "* return ix86_output_indirect_jmp (operands[0], false);" | ||
1077 | + [(set (attr "type") | ||
1078 | + (if_then_else (match_test "(cfun->machine->indirect_branch_type | ||
1079 | + != indirect_branch_keep)") | ||
1080 | + (const_string "multi") | ||
1081 | + (const_string "ibr"))) | ||
1082 | (set_attr "length_immediate" "0") | ||
1083 | (set_attr "maybe_prefix_bnd" "1")]) | ||
1084 | |||
1085 | @@ -12520,8 +12530,12 @@ | ||
1086 | [(simple_return) | ||
1087 | (use (match_operand:SI 0 "register_operand" "r"))] | ||
1088 | "reload_completed" | ||
1089 | - "%!jmp\t%A0" | ||
1090 | - [(set_attr "type" "ibr") | ||
1091 | + "* return ix86_output_indirect_jmp (operands[0], true);" | ||
1092 | + [(set (attr "type") | ||
1093 | + (if_then_else (match_test "(cfun->machine->indirect_branch_type | ||
1094 | + != indirect_branch_keep)") | ||
1095 | + (const_string "multi") | ||
1096 | + (const_string "ibr"))) | ||
1097 | (set_attr "length_immediate" "0") | ||
1098 | (set_attr "maybe_prefix_bnd" "1")]) | ||
1099 | |||
1100 | diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt | ||
1101 | index f304b62..5ffa334 100644 | ||
1102 | --- a/gcc/config/i386/i386.opt | ||
1103 | +++ b/gcc/config/i386/i386.opt | ||
1104 | @@ -897,3 +897,23 @@ Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL) | ||
1105 | mmitigate-rop | ||
1106 | Target Var(flag_mitigate_rop) Init(0) | ||
1107 | Attempt to avoid generating instruction sequences containing ret bytes. | ||
1108 | + | ||
1109 | +mindirect-branch= | ||
1110 | +Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep) | ||
1111 | +Convert indirect call and jump to call and return thunks. | ||
1112 | + | ||
1113 | +Enum | ||
1114 | +Name(indirect_branch) Type(enum indirect_branch) | ||
1115 | +Known indirect branch choices (for use with the -mindirect-branch= option): | ||
1116 | + | ||
1117 | +EnumValue | ||
1118 | +Enum(indirect_branch) String(keep) Value(indirect_branch_keep) | ||
1119 | + | ||
1120 | +EnumValue | ||
1121 | +Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk) | ||
1122 | + | ||
1123 | +EnumValue | ||
1124 | +Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline) | ||
1125 | + | ||
1126 | +EnumValue | ||
1127 | +Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern) | ||
1128 | diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi | ||
1129 | index 8cc4f7e..8668dae 100644 | ||
1130 | --- a/gcc/doc/extend.texi | ||
1131 | +++ b/gcc/doc/extend.texi | ||
1132 | @@ -5419,6 +5419,16 @@ Specify which floating-point unit to use. You must specify the | ||
1133 | @code{target("fpmath=sse,387")} option as | ||
1134 | @code{target("fpmath=sse+387")} because the comma would separate | ||
1135 | different options. | ||
1136 | + | ||
1137 | +@item indirect_branch("@var{choice}") | ||
1138 | +@cindex @code{indirect_branch} function attribute, x86 | ||
1139 | +On x86 targets, the @code{indirect_branch} attribute causes the compiler | ||
1140 | +to convert indirect call and jump with @var{choice}. @samp{keep} | ||
1141 | +keeps indirect call and jump unmodified. @samp{thunk} converts indirect | ||
1142 | +call and jump to call and return thunk. @samp{thunk-inline} converts | ||
1143 | +indirect call and jump to inlined call and return thunk. | ||
1144 | +@samp{thunk-extern} converts indirect call and jump to external call | ||
1145 | +and return thunk provided in a separate object file. | ||
1146 | @end table | ||
1147 | |||
1148 | On the x86, the inliner does not inline a | ||
1149 | diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi | ||
1150 | index b066f7b..ff9a194 100644 | ||
1151 | --- a/gcc/doc/invoke.texi | ||
1152 | +++ b/gcc/doc/invoke.texi | ||
1153 | @@ -1169,7 +1169,7 @@ See RS/6000 and PowerPC Options. | ||
1154 | -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol | ||
1155 | -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol | ||
1156 | -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol | ||
1157 | --mmitigate-rop} | ||
1158 | +-mmitigate-rop -mindirect-branch=@var{choice}} | ||
1159 | |||
1160 | @emph{x86 Windows Options} | ||
1161 | @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol | ||
1162 | @@ -24218,6 +24218,17 @@ opcodes, to mitigate against certain forms of attack. At the moment, | ||
1163 | this option is limited in what it can do and should not be relied | ||
1164 | on to provide serious protection. | ||
1165 | |||
1166 | +@item -mindirect-branch=@var{choice} | ||
1167 | +@opindex -mindirect-branch | ||
1168 | +Convert indirect call and jump with @var{choice}. The default is | ||
1169 | +@samp{keep}, which keeps indirect call and jump unmodified. | ||
1170 | +@samp{thunk} converts indirect call and jump to call and return thunk. | ||
1171 | +@samp{thunk-inline} converts indirect call and jump to inlined call | ||
1172 | +and return thunk. @samp{thunk-extern} converts indirect call and jump | ||
1173 | +to external call and return thunk provided in a separate object file. | ||
1174 | +You can control this behavior for a specific function by using the | ||
1175 | +function attribute @code{indirect_branch}. @xref{Function Attributes}. | ||
1176 | + | ||
1177 | @end table | ||
1178 | |||
1179 | These @samp{-m} switches are supported in addition to the above | ||
1180 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | ||
1181 | new file mode 100644 | ||
1182 | index 0000000..d983e1c | ||
1183 | --- /dev/null | ||
1184 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | ||
1185 | @@ -0,0 +1,20 @@ | ||
1186 | +/* { dg-do compile } */ | ||
1187 | +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ | ||
1188 | + | ||
1189 | +typedef void (*dispatch_t)(long offset); | ||
1190 | + | ||
1191 | +dispatch_t dispatch; | ||
1192 | + | ||
1193 | +void | ||
1194 | +male_indirect_jump (long offset) | ||
1195 | +{ | ||
1196 | + dispatch(offset); | ||
1197 | +} | ||
1198 | + | ||
1199 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1200 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1201 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1202 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1203 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1204 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1205 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1206 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | ||
1207 | new file mode 100644 | ||
1208 | index 0000000..58f09b4 | ||
1209 | --- /dev/null | ||
1210 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | ||
1211 | @@ -0,0 +1,20 @@ | ||
1212 | +/* { dg-do compile } */ | ||
1213 | +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ | ||
1214 | + | ||
1215 | +typedef void (*dispatch_t)(long offset); | ||
1216 | + | ||
1217 | +dispatch_t dispatch[256]; | ||
1218 | + | ||
1219 | +void | ||
1220 | +male_indirect_jump (long offset) | ||
1221 | +{ | ||
1222 | + dispatch[offset](offset); | ||
1223 | +} | ||
1224 | + | ||
1225 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1226 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1227 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1228 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1229 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1230 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1231 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1232 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | ||
1233 | new file mode 100644 | ||
1234 | index 0000000..f20d35c | ||
1235 | --- /dev/null | ||
1236 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | ||
1237 | @@ -0,0 +1,21 @@ | ||
1238 | +/* { dg-do compile } */ | ||
1239 | +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ | ||
1240 | + | ||
1241 | +typedef void (*dispatch_t)(long offset); | ||
1242 | + | ||
1243 | +dispatch_t dispatch; | ||
1244 | + | ||
1245 | +int | ||
1246 | +male_indirect_jump (long offset) | ||
1247 | +{ | ||
1248 | + dispatch(offset); | ||
1249 | + return 0; | ||
1250 | +} | ||
1251 | + | ||
1252 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1253 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1254 | +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1255 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1256 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1257 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1258 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1259 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | ||
1260 | new file mode 100644 | ||
1261 | index 0000000..0eff8fb | ||
1262 | --- /dev/null | ||
1263 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | ||
1264 | @@ -0,0 +1,21 @@ | ||
1265 | +/* { dg-do compile } */ | ||
1266 | +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ | ||
1267 | + | ||
1268 | +typedef void (*dispatch_t)(long offset); | ||
1269 | + | ||
1270 | +dispatch_t dispatch[256]; | ||
1271 | + | ||
1272 | +int | ||
1273 | +male_indirect_jump (long offset) | ||
1274 | +{ | ||
1275 | + dispatch[offset](offset); | ||
1276 | + return 0; | ||
1277 | +} | ||
1278 | + | ||
1279 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1280 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1281 | +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1282 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1283 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1284 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1285 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1286 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | ||
1287 | new file mode 100644 | ||
1288 | index 0000000..a25b20d | ||
1289 | --- /dev/null | ||
1290 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | ||
1291 | @@ -0,0 +1,17 @@ | ||
1292 | +/* { dg-do compile { target *-*-linux* } } */ | ||
1293 | +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */ | ||
1294 | + | ||
1295 | +extern void bar (void); | ||
1296 | + | ||
1297 | +void | ||
1298 | +foo (void) | ||
1299 | +{ | ||
1300 | + bar (); | ||
1301 | +} | ||
1302 | + | ||
1303 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
1304 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ | ||
1305 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1306 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1307 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1308 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1309 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | ||
1310 | new file mode 100644 | ||
1311 | index 0000000..cff114a | ||
1312 | --- /dev/null | ||
1313 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | ||
1314 | @@ -0,0 +1,18 @@ | ||
1315 | +/* { dg-do compile { target *-*-linux* } } */ | ||
1316 | +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */ | ||
1317 | + | ||
1318 | +extern void bar (void); | ||
1319 | + | ||
1320 | +int | ||
1321 | +foo (void) | ||
1322 | +{ | ||
1323 | + bar (); | ||
1324 | + return 0; | ||
1325 | +} | ||
1326 | + | ||
1327 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
1328 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ | ||
1329 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ | ||
1330 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ | ||
1331 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1332 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1333 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | ||
1334 | new file mode 100644 | ||
1335 | index 0000000..afdb600 | ||
1336 | --- /dev/null | ||
1337 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | ||
1338 | @@ -0,0 +1,44 @@ | ||
1339 | +/* { dg-do compile } */ | ||
1340 | +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ | ||
1341 | + | ||
1342 | +void func0 (void); | ||
1343 | +void func1 (void); | ||
1344 | +void func2 (void); | ||
1345 | +void func3 (void); | ||
1346 | +void func4 (void); | ||
1347 | +void func4 (void); | ||
1348 | +void func5 (void); | ||
1349 | + | ||
1350 | +void | ||
1351 | +bar (int i) | ||
1352 | +{ | ||
1353 | + switch (i) | ||
1354 | + { | ||
1355 | + default: | ||
1356 | + func0 (); | ||
1357 | + break; | ||
1358 | + case 1: | ||
1359 | + func1 (); | ||
1360 | + break; | ||
1361 | + case 2: | ||
1362 | + func2 (); | ||
1363 | + break; | ||
1364 | + case 3: | ||
1365 | + func3 (); | ||
1366 | + break; | ||
1367 | + case 4: | ||
1368 | + func4 (); | ||
1369 | + break; | ||
1370 | + case 5: | ||
1371 | + func5 (); | ||
1372 | + break; | ||
1373 | + } | ||
1374 | +} | ||
1375 | + | ||
1376 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ | ||
1377 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1378 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1379 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1380 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1381 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1382 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1383 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c | ||
1384 | new file mode 100644 | ||
1385 | index 0000000..d64d978 | ||
1386 | --- /dev/null | ||
1387 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c | ||
1388 | @@ -0,0 +1,23 @@ | ||
1389 | +/* { dg-do compile } */ | ||
1390 | +/* { dg-options "-O2 -fno-pic" } */ | ||
1391 | + | ||
1392 | +typedef void (*dispatch_t)(long offset); | ||
1393 | + | ||
1394 | +dispatch_t dispatch; | ||
1395 | + | ||
1396 | +extern void male_indirect_jump (long) | ||
1397 | + __attribute__ ((indirect_branch("thunk"))); | ||
1398 | + | ||
1399 | +void | ||
1400 | +male_indirect_jump (long offset) | ||
1401 | +{ | ||
1402 | + dispatch(offset); | ||
1403 | +} | ||
1404 | + | ||
1405 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1406 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1407 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1408 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1409 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1410 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1411 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1412 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c | ||
1413 | new file mode 100644 | ||
1414 | index 0000000..9306745 | ||
1415 | --- /dev/null | ||
1416 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c | ||
1417 | @@ -0,0 +1,21 @@ | ||
1418 | +/* { dg-do compile } */ | ||
1419 | +/* { dg-options "-O2 -fno-pic" } */ | ||
1420 | + | ||
1421 | +typedef void (*dispatch_t)(long offset); | ||
1422 | + | ||
1423 | +dispatch_t dispatch[256]; | ||
1424 | + | ||
1425 | +__attribute__ ((indirect_branch("thunk"))) | ||
1426 | +void | ||
1427 | +male_indirect_jump (long offset) | ||
1428 | +{ | ||
1429 | + dispatch[offset](offset); | ||
1430 | +} | ||
1431 | + | ||
1432 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1433 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1434 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1435 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1436 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1437 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1438 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1439 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c | ||
1440 | new file mode 100644 | ||
1441 | index 0000000..97744d6 | ||
1442 | --- /dev/null | ||
1443 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c | ||
1444 | @@ -0,0 +1,23 @@ | ||
1445 | +/* { dg-do compile } */ | ||
1446 | +/* { dg-options "-O2 -fno-pic" } */ | ||
1447 | + | ||
1448 | +typedef void (*dispatch_t)(long offset); | ||
1449 | + | ||
1450 | +dispatch_t dispatch; | ||
1451 | +extern int male_indirect_jump (long) | ||
1452 | + __attribute__ ((indirect_branch("thunk-inline"))); | ||
1453 | + | ||
1454 | +int | ||
1455 | +male_indirect_jump (long offset) | ||
1456 | +{ | ||
1457 | + dispatch(offset); | ||
1458 | + return 0; | ||
1459 | +} | ||
1460 | + | ||
1461 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1462 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ | ||
1463 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ | ||
1464 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1465 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1466 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
1467 | +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ | ||
1468 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c | ||
1469 | new file mode 100644 | ||
1470 | index 0000000..bfce3ea | ||
1471 | --- /dev/null | ||
1472 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c | ||
1473 | @@ -0,0 +1,22 @@ | ||
1474 | +/* { dg-do compile } */ | ||
1475 | +/* { dg-options "-O2 -fno-pic" } */ | ||
1476 | + | ||
1477 | +typedef void (*dispatch_t)(long offset); | ||
1478 | + | ||
1479 | +dispatch_t dispatch[256]; | ||
1480 | + | ||
1481 | +__attribute__ ((indirect_branch("thunk-inline"))) | ||
1482 | +int | ||
1483 | +male_indirect_jump (long offset) | ||
1484 | +{ | ||
1485 | + dispatch[offset](offset); | ||
1486 | + return 0; | ||
1487 | +} | ||
1488 | + | ||
1489 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1490 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ | ||
1491 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ | ||
1492 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1493 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1494 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
1495 | +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ | ||
1496 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c | ||
1497 | new file mode 100644 | ||
1498 | index 0000000..0833606 | ||
1499 | --- /dev/null | ||
1500 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c | ||
1501 | @@ -0,0 +1,22 @@ | ||
1502 | +/* { dg-do compile } */ | ||
1503 | +/* { dg-options "-O2 -fno-pic" } */ | ||
1504 | + | ||
1505 | +typedef void (*dispatch_t)(long offset); | ||
1506 | + | ||
1507 | +dispatch_t dispatch; | ||
1508 | +extern int male_indirect_jump (long) | ||
1509 | + __attribute__ ((indirect_branch("thunk-extern"))); | ||
1510 | + | ||
1511 | +int | ||
1512 | +male_indirect_jump (long offset) | ||
1513 | +{ | ||
1514 | + dispatch(offset); | ||
1515 | + return 0; | ||
1516 | +} | ||
1517 | + | ||
1518 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1519 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1520 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1521 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1522 | +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1523 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1524 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c | ||
1525 | new file mode 100644 | ||
1526 | index 0000000..2eba0fb | ||
1527 | --- /dev/null | ||
1528 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c | ||
1529 | @@ -0,0 +1,21 @@ | ||
1530 | +/* { dg-do compile } */ | ||
1531 | +/* { dg-options "-O2 -fno-pic" } */ | ||
1532 | + | ||
1533 | +typedef void (*dispatch_t)(long offset); | ||
1534 | + | ||
1535 | +dispatch_t dispatch[256]; | ||
1536 | + | ||
1537 | +__attribute__ ((indirect_branch("thunk-extern"))) | ||
1538 | +int | ||
1539 | +male_indirect_jump (long offset) | ||
1540 | +{ | ||
1541 | + dispatch[offset](offset); | ||
1542 | + return 0; | ||
1543 | +} | ||
1544 | + | ||
1545 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1546 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1547 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1548 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1549 | +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1550 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1551 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c | ||
1552 | new file mode 100644 | ||
1553 | index 0000000..f58427e | ||
1554 | --- /dev/null | ||
1555 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c | ||
1556 | @@ -0,0 +1,44 @@ | ||
1557 | +/* { dg-do compile } */ | ||
1558 | +/* { dg-options "-O2 -fno-pic" } */ | ||
1559 | + | ||
1560 | +void func0 (void); | ||
1561 | +void func1 (void); | ||
1562 | +void func2 (void); | ||
1563 | +void func3 (void); | ||
1564 | +void func4 (void); | ||
1565 | +void func4 (void); | ||
1566 | +void func5 (void); | ||
1567 | + | ||
1568 | +__attribute__ ((indirect_branch("thunk-extern"))) | ||
1569 | +void | ||
1570 | +bar (int i) | ||
1571 | +{ | ||
1572 | + switch (i) | ||
1573 | + { | ||
1574 | + default: | ||
1575 | + func0 (); | ||
1576 | + break; | ||
1577 | + case 1: | ||
1578 | + func1 (); | ||
1579 | + break; | ||
1580 | + case 2: | ||
1581 | + func2 (); | ||
1582 | + break; | ||
1583 | + case 3: | ||
1584 | + func3 (); | ||
1585 | + break; | ||
1586 | + case 4: | ||
1587 | + func4 (); | ||
1588 | + break; | ||
1589 | + case 5: | ||
1590 | + func5 (); | ||
1591 | + break; | ||
1592 | + } | ||
1593 | +} | ||
1594 | + | ||
1595 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ | ||
1596 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1597 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ | ||
1598 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1599 | +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ | ||
1600 | +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ | ||
1601 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c | ||
1602 | new file mode 100644 | ||
1603 | index 0000000..564ed39 | ||
1604 | --- /dev/null | ||
1605 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c | ||
1606 | @@ -0,0 +1,42 @@ | ||
1607 | +/* { dg-do compile } */ | ||
1608 | +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ | ||
1609 | + | ||
1610 | +void func0 (void); | ||
1611 | +void func1 (void); | ||
1612 | +void func2 (void); | ||
1613 | +void func3 (void); | ||
1614 | +void func4 (void); | ||
1615 | +void func4 (void); | ||
1616 | +void func5 (void); | ||
1617 | + | ||
1618 | +__attribute__ ((indirect_branch("keep"))) | ||
1619 | +void | ||
1620 | +bar (int i) | ||
1621 | +{ | ||
1622 | + switch (i) | ||
1623 | + { | ||
1624 | + default: | ||
1625 | + func0 (); | ||
1626 | + break; | ||
1627 | + case 1: | ||
1628 | + func1 (); | ||
1629 | + break; | ||
1630 | + case 2: | ||
1631 | + func2 (); | ||
1632 | + break; | ||
1633 | + case 3: | ||
1634 | + func3 (); | ||
1635 | + break; | ||
1636 | + case 4: | ||
1637 | + func4 (); | ||
1638 | + break; | ||
1639 | + case 5: | ||
1640 | + func5 (); | ||
1641 | + break; | ||
1642 | + } | ||
1643 | +} | ||
1644 | + | ||
1645 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
1646 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1647 | +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ | ||
1648 | +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ | ||
1649 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c | ||
1650 | new file mode 100644 | ||
1651 | index 0000000..50fbee2 | ||
1652 | --- /dev/null | ||
1653 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c | ||
1654 | @@ -0,0 +1,20 @@ | ||
1655 | +/* { dg-do compile { target { ! x32 } } } */ | ||
1656 | +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */ | ||
1657 | + | ||
1658 | +void (*dispatch) (char *); | ||
1659 | +char buf[10]; | ||
1660 | + | ||
1661 | +void | ||
1662 | +foo (void) | ||
1663 | +{ | ||
1664 | + dispatch (buf); | ||
1665 | +} | ||
1666 | + | ||
1667 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1668 | +/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */ | ||
1669 | +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */ | ||
1670 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1671 | +/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */ | ||
1672 | +/* { dg-final { scan-assembler "bnd ret" } } */ | ||
1673 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1674 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1675 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c | ||
1676 | new file mode 100644 | ||
1677 | index 0000000..2976e67 | ||
1678 | --- /dev/null | ||
1679 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c | ||
1680 | @@ -0,0 +1,21 @@ | ||
1681 | +/* { dg-do compile { target { ! x32 } } } */ | ||
1682 | +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */ | ||
1683 | + | ||
1684 | +void (*dispatch) (char *); | ||
1685 | +char buf[10]; | ||
1686 | + | ||
1687 | +int | ||
1688 | +foo (void) | ||
1689 | +{ | ||
1690 | + dispatch (buf); | ||
1691 | + return 0; | ||
1692 | +} | ||
1693 | + | ||
1694 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1695 | +/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */ | ||
1696 | +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */ | ||
1697 | +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */ | ||
1698 | +/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */ | ||
1699 | +/* { dg-final { scan-assembler "bnd ret" } } */ | ||
1700 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1701 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1702 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c | ||
1703 | new file mode 100644 | ||
1704 | index 0000000..da4bc98 | ||
1705 | --- /dev/null | ||
1706 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c | ||
1707 | @@ -0,0 +1,19 @@ | ||
1708 | +/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */ | ||
1709 | +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */ | ||
1710 | + | ||
1711 | +void bar (char *); | ||
1712 | +char buf[10]; | ||
1713 | + | ||
1714 | +void | ||
1715 | +foo (void) | ||
1716 | +{ | ||
1717 | + bar (buf); | ||
1718 | +} | ||
1719 | + | ||
1720 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
1721 | +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */ | ||
1722 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1723 | +/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */ | ||
1724 | +/* { dg-final { scan-assembler "bnd ret" } } */ | ||
1725 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1726 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1727 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c | ||
1728 | new file mode 100644 | ||
1729 | index 0000000..c64d12e | ||
1730 | --- /dev/null | ||
1731 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c | ||
1732 | @@ -0,0 +1,20 @@ | ||
1733 | +/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */ | ||
1734 | +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */ | ||
1735 | + | ||
1736 | +void bar (char *); | ||
1737 | +char buf[10]; | ||
1738 | + | ||
1739 | +int | ||
1740 | +foo (void) | ||
1741 | +{ | ||
1742 | + bar (buf); | ||
1743 | + return 0; | ||
1744 | +} | ||
1745 | + | ||
1746 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
1747 | +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk" } } */ | ||
1748 | +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */ | ||
1749 | +/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 2 } } */ | ||
1750 | +/* { dg-final { scan-assembler "bnd ret" } } */ | ||
1751 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1752 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1753 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c | ||
1754 | new file mode 100644 | ||
1755 | index 0000000..49f27b4 | ||
1756 | --- /dev/null | ||
1757 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c | ||
1758 | @@ -0,0 +1,19 @@ | ||
1759 | +/* { dg-do compile } */ | ||
1760 | +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ | ||
1761 | + | ||
1762 | +typedef void (*dispatch_t)(long offset); | ||
1763 | + | ||
1764 | +dispatch_t dispatch; | ||
1765 | + | ||
1766 | +void | ||
1767 | +male_indirect_jump (long offset) | ||
1768 | +{ | ||
1769 | + dispatch(offset); | ||
1770 | +} | ||
1771 | + | ||
1772 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1773 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1774 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1775 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1776 | +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ | ||
1777 | +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ | ||
1778 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c | ||
1779 | new file mode 100644 | ||
1780 | index 0000000..a1e3eb6 | ||
1781 | --- /dev/null | ||
1782 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c | ||
1783 | @@ -0,0 +1,19 @@ | ||
1784 | +/* { dg-do compile } */ | ||
1785 | +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ | ||
1786 | + | ||
1787 | +typedef void (*dispatch_t)(long offset); | ||
1788 | + | ||
1789 | +dispatch_t dispatch[256]; | ||
1790 | + | ||
1791 | +void | ||
1792 | +male_indirect_jump (long offset) | ||
1793 | +{ | ||
1794 | + dispatch[offset](offset); | ||
1795 | +} | ||
1796 | + | ||
1797 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1798 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1799 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1800 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1801 | +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ | ||
1802 | +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ | ||
1803 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c | ||
1804 | new file mode 100644 | ||
1805 | index 0000000..395634e | ||
1806 | --- /dev/null | ||
1807 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c | ||
1808 | @@ -0,0 +1,20 @@ | ||
1809 | +/* { dg-do compile } */ | ||
1810 | +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ | ||
1811 | + | ||
1812 | +typedef void (*dispatch_t)(long offset); | ||
1813 | + | ||
1814 | +dispatch_t dispatch; | ||
1815 | + | ||
1816 | +int | ||
1817 | +male_indirect_jump (long offset) | ||
1818 | +{ | ||
1819 | + dispatch(offset); | ||
1820 | + return 0; | ||
1821 | +} | ||
1822 | + | ||
1823 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1824 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1825 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1826 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1827 | +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1828 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1829 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c | ||
1830 | new file mode 100644 | ||
1831 | index 0000000..fd3f633 | ||
1832 | --- /dev/null | ||
1833 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c | ||
1834 | @@ -0,0 +1,20 @@ | ||
1835 | +/* { dg-do compile } */ | ||
1836 | +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ | ||
1837 | + | ||
1838 | +typedef void (*dispatch_t)(long offset); | ||
1839 | + | ||
1840 | +dispatch_t dispatch[256]; | ||
1841 | + | ||
1842 | +int | ||
1843 | +male_indirect_jump (long offset) | ||
1844 | +{ | ||
1845 | + dispatch[offset](offset); | ||
1846 | + return 0; | ||
1847 | +} | ||
1848 | + | ||
1849 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1850 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1851 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1852 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ | ||
1853 | +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1854 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1855 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c | ||
1856 | new file mode 100644 | ||
1857 | index 0000000..ba2f92b | ||
1858 | --- /dev/null | ||
1859 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c | ||
1860 | @@ -0,0 +1,16 @@ | ||
1861 | +/* { dg-do compile { target *-*-linux* } } */ | ||
1862 | +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */ | ||
1863 | + | ||
1864 | +extern void bar (void); | ||
1865 | + | ||
1866 | +void | ||
1867 | +foo (void) | ||
1868 | +{ | ||
1869 | + bar (); | ||
1870 | +} | ||
1871 | + | ||
1872 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
1873 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ | ||
1874 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1875 | +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ | ||
1876 | +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ | ||
1877 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c | ||
1878 | new file mode 100644 | ||
1879 | index 0000000..0c5a2d4 | ||
1880 | --- /dev/null | ||
1881 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c | ||
1882 | @@ -0,0 +1,17 @@ | ||
1883 | +/* { dg-do compile { target *-*-linux* } } */ | ||
1884 | +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */ | ||
1885 | + | ||
1886 | +extern void bar (void); | ||
1887 | + | ||
1888 | +int | ||
1889 | +foo (void) | ||
1890 | +{ | ||
1891 | + bar (); | ||
1892 | + return 0; | ||
1893 | +} | ||
1894 | + | ||
1895 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
1896 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */ | ||
1897 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */ | ||
1898 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ | ||
1899 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1900 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c | ||
1901 | new file mode 100644 | ||
1902 | index 0000000..6652523 | ||
1903 | --- /dev/null | ||
1904 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c | ||
1905 | @@ -0,0 +1,43 @@ | ||
1906 | +/* { dg-do compile } */ | ||
1907 | +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ | ||
1908 | + | ||
1909 | +void func0 (void); | ||
1910 | +void func1 (void); | ||
1911 | +void func2 (void); | ||
1912 | +void func3 (void); | ||
1913 | +void func4 (void); | ||
1914 | +void func4 (void); | ||
1915 | +void func5 (void); | ||
1916 | + | ||
1917 | +void | ||
1918 | +bar (int i) | ||
1919 | +{ | ||
1920 | + switch (i) | ||
1921 | + { | ||
1922 | + default: | ||
1923 | + func0 (); | ||
1924 | + break; | ||
1925 | + case 1: | ||
1926 | + func1 (); | ||
1927 | + break; | ||
1928 | + case 2: | ||
1929 | + func2 (); | ||
1930 | + break; | ||
1931 | + case 3: | ||
1932 | + func3 (); | ||
1933 | + break; | ||
1934 | + case 4: | ||
1935 | + func4 (); | ||
1936 | + break; | ||
1937 | + case 5: | ||
1938 | + func5 (); | ||
1939 | + break; | ||
1940 | + } | ||
1941 | +} | ||
1942 | + | ||
1943 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ | ||
1944 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ | ||
1945 | +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ | ||
1946 | +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ | ||
1947 | +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ | ||
1948 | +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ | ||
1949 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c | ||
1950 | new file mode 100644 | ||
1951 | index 0000000..68c0ff7 | ||
1952 | --- /dev/null | ||
1953 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c | ||
1954 | @@ -0,0 +1,20 @@ | ||
1955 | +/* { dg-do compile } */ | ||
1956 | +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ | ||
1957 | + | ||
1958 | +typedef void (*dispatch_t)(long offset); | ||
1959 | + | ||
1960 | +dispatch_t dispatch; | ||
1961 | + | ||
1962 | +void | ||
1963 | +male_indirect_jump (long offset) | ||
1964 | +{ | ||
1965 | + dispatch(offset); | ||
1966 | +} | ||
1967 | + | ||
1968 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1969 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1970 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1971 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1972 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1973 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
1974 | +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ | ||
1975 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c | ||
1976 | new file mode 100644 | ||
1977 | index 0000000..e2da1fc | ||
1978 | --- /dev/null | ||
1979 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c | ||
1980 | @@ -0,0 +1,20 @@ | ||
1981 | +/* { dg-do compile } */ | ||
1982 | +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ | ||
1983 | + | ||
1984 | +typedef void (*dispatch_t)(long offset); | ||
1985 | + | ||
1986 | +dispatch_t dispatch[256]; | ||
1987 | + | ||
1988 | +void | ||
1989 | +male_indirect_jump (long offset) | ||
1990 | +{ | ||
1991 | + dispatch[offset](offset); | ||
1992 | +} | ||
1993 | + | ||
1994 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
1995 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
1996 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
1997 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
1998 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
1999 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
2000 | +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ | ||
2001 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c | ||
2002 | new file mode 100644 | ||
2003 | index 0000000..244fec7 | ||
2004 | --- /dev/null | ||
2005 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c | ||
2006 | @@ -0,0 +1,21 @@ | ||
2007 | +/* { dg-do compile } */ | ||
2008 | +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ | ||
2009 | + | ||
2010 | +typedef void (*dispatch_t)(long offset); | ||
2011 | + | ||
2012 | +dispatch_t dispatch; | ||
2013 | + | ||
2014 | +int | ||
2015 | +male_indirect_jump (long offset) | ||
2016 | +{ | ||
2017 | + dispatch(offset); | ||
2018 | + return 0; | ||
2019 | +} | ||
2020 | + | ||
2021 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
2022 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ | ||
2023 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ | ||
2024 | +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ | ||
2025 | +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ | ||
2026 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
2027 | +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ | ||
2028 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c | ||
2029 | new file mode 100644 | ||
2030 | index 0000000..107ebe3 | ||
2031 | --- /dev/null | ||
2032 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c | ||
2033 | @@ -0,0 +1,21 @@ | ||
2034 | +/* { dg-do compile } */ | ||
2035 | +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ | ||
2036 | + | ||
2037 | +typedef void (*dispatch_t)(long offset); | ||
2038 | + | ||
2039 | +dispatch_t dispatch[256]; | ||
2040 | + | ||
2041 | +int | ||
2042 | +male_indirect_jump (long offset) | ||
2043 | +{ | ||
2044 | + dispatch[offset](offset); | ||
2045 | + return 0; | ||
2046 | +} | ||
2047 | + | ||
2048 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ | ||
2049 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ | ||
2050 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ | ||
2051 | +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ | ||
2052 | +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ | ||
2053 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
2054 | +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ | ||
2055 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c | ||
2056 | new file mode 100644 | ||
2057 | index 0000000..17b04ef | ||
2058 | --- /dev/null | ||
2059 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c | ||
2060 | @@ -0,0 +1,17 @@ | ||
2061 | +/* { dg-do compile { target *-*-linux* } } */ | ||
2062 | +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */ | ||
2063 | + | ||
2064 | +extern void bar (void); | ||
2065 | + | ||
2066 | +void | ||
2067 | +foo (void) | ||
2068 | +{ | ||
2069 | + bar (); | ||
2070 | +} | ||
2071 | + | ||
2072 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
2073 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
2074 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
2075 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
2076 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
2077 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
2078 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c | ||
2079 | new file mode 100644 | ||
2080 | index 0000000..d9eb112 | ||
2081 | --- /dev/null | ||
2082 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c | ||
2083 | @@ -0,0 +1,18 @@ | ||
2084 | +/* { dg-do compile { target *-*-linux* } } */ | ||
2085 | +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */ | ||
2086 | + | ||
2087 | +extern void bar (void); | ||
2088 | + | ||
2089 | +int | ||
2090 | +foo (void) | ||
2091 | +{ | ||
2092 | + bar (); | ||
2093 | + return 0; | ||
2094 | +} | ||
2095 | + | ||
2096 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */ | ||
2097 | +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ | ||
2098 | +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ | ||
2099 | +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ | ||
2100 | +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ | ||
2101 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
2102 | diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c | ||
2103 | new file mode 100644 | ||
2104 | index 0000000..d02b1dc | ||
2105 | --- /dev/null | ||
2106 | +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c | ||
2107 | @@ -0,0 +1,44 @@ | ||
2108 | +/* { dg-do compile } */ | ||
2109 | +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ | ||
2110 | + | ||
2111 | +void func0 (void); | ||
2112 | +void func1 (void); | ||
2113 | +void func2 (void); | ||
2114 | +void func3 (void); | ||
2115 | +void func4 (void); | ||
2116 | +void func4 (void); | ||
2117 | +void func5 (void); | ||
2118 | + | ||
2119 | +void | ||
2120 | +bar (int i) | ||
2121 | +{ | ||
2122 | + switch (i) | ||
2123 | + { | ||
2124 | + default: | ||
2125 | + func0 (); | ||
2126 | + break; | ||
2127 | + case 1: | ||
2128 | + func1 (); | ||
2129 | + break; | ||
2130 | + case 2: | ||
2131 | + func2 (); | ||
2132 | + break; | ||
2133 | + case 3: | ||
2134 | + func3 (); | ||
2135 | + break; | ||
2136 | + case 4: | ||
2137 | + func4 (); | ||
2138 | + break; | ||
2139 | + case 5: | ||
2140 | + func5 (); | ||
2141 | + break; | ||
2142 | + } | ||
2143 | +} | ||
2144 | + | ||
2145 | +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ | ||
2146 | +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ | ||
2147 | +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ | ||
2148 | +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ | ||
2149 | +/* { dg-final { scan-assembler {\tpause} } } */ | ||
2150 | +/* { dg-final { scan-assembler {\tlfence} } } */ | ||
2151 | +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ | ||
2152 | -- | ||
2153 | 2.7.4 | ||
2154 | |||