summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuro Bystricky <juro.bystricky@intel.com>2018-03-01 18:32:43 (GMT)
committerRichard Purdie <richard.purdie@linuxfoundation.org>2018-03-14 14:55:02 (GMT)
commitdc786f9841ea687fa46ee3f03a1a39da441336b3 (patch)
tree8153d5168ab784023eeb26c1e6e363826d300b19
parentaa072d0162e51340b065092a440b775061911699 (diff)
downloadpoky-dc786f9841ea687fa46ee3f03a1a39da441336b3.tar.gz
gcc6: Backport few more patches
Backported series of patches from https://github.com/hjl-tools/gcc.git branch /hjl/indirect/gcc-6-branch/master which contains an IA patch series for security related issues (From OE-Core rev: 8283b4ee5290843b1033ca496759fce6229b8f91) Signed-off-by: Juro Bystricky <juro.bystricky@intel.com> Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4.inc13
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch247
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch74
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch131
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch2154
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch1570
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0006-x86-Add-mindirect-branch-register.patch946
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0007-x86-Add-V-register-operand-modifier.patch139
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0008-x86-Disallow-mindirect-branch-mfunction-return-with-.patch304
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0009-Use-INVALID_REGNUM-in-indirect-thunk-processing.patch126
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0010-i386-Pass-INVALID_REGNUM-as-invalid-register-number.patch46
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch453
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0012-i386-Add-TARGET_INDIRECT_BRANCH_REGISTER.patch1004
13 files changed, 7207 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-6.4.inc b/meta/recipes-devtools/gcc/gcc-6.4.inc
index 66654e6..1803917 100644
--- a/meta/recipes-devtools/gcc/gcc-6.4.inc
+++ b/meta/recipes-devtools/gcc/gcc-6.4.inc
@@ -88,7 +88,20 @@ BACKPORTS = "\
88 file://CVE-2016-6131.patch \ 88 file://CVE-2016-6131.patch \
89 file://0057-ARM-PR-82445-suppress-32-bit-aligned-ldrd-strd-peeph.patch \ 89 file://0057-ARM-PR-82445-suppress-32-bit-aligned-ldrd-strd-peeph.patch \
90 file://0001-enable-FL_LPAE-flag-for-armv7ve-cores.patch \ 90 file://0001-enable-FL_LPAE-flag-for-armv7ve-cores.patch \
91 file://0001-i386-Move-struct-ix86_frame-to-machine_function.patch \
92 file://0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch \
93 file://0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch \
94 file://0004-x86-Add-mindirect-branch.patch \
95 file://0005-x86-Add-mfunction-return.patch \
96 file://0006-x86-Add-mindirect-branch-register.patch \
97 file://0007-x86-Add-V-register-operand-modifier.patch \
98 file://0008-x86-Disallow-mindirect-branch-mfunction-return-with-.patch \
99 file://0009-Use-INVALID_REGNUM-in-indirect-thunk-processing.patch \
100 file://0010-i386-Pass-INVALID_REGNUM-as-invalid-register-number.patch \
101 file://0011-i386-Update-mfunction-return-for-return-with-pop.patch \
102 file://0012-i386-Add-TARGET_INDIRECT_BRANCH_REGISTER.patch \
91" 103"
104
92SRC_URI[md5sum] = "11ba51a0cfb8471927f387c8895fe232" 105SRC_URI[md5sum] = "11ba51a0cfb8471927f387c8895fe232"
93SRC_URI[sha256sum] = "850bf21eafdfe5cd5f6827148184c08c4a0852a37ccf36ce69855334d2c914d4" 106SRC_URI[sha256sum] = "850bf21eafdfe5cd5f6827148184c08c4a0852a37ccf36ce69855334d2c914d4"
94 107
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch
new file mode 100644
index 0000000..00b0ffd
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch
@@ -0,0 +1,247 @@
1From c2c7775c5587dc59b6756162d390d89d60971a16 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Mon, 15 Jan 2018 11:27:24 +0000
4Subject: [PATCH 01/12] i386: Move struct ix86_frame to machine_function
5
6Make ix86_frame available to i386 code generation. This is needed to
7backport the patch set of -mindirect-branch= to mitigate variant #2 of
8the speculative execution vulnerabilities on x86 processors identified
9by CVE-2017-5715, aka Spectre.
10
11 Backport from mainline
12 2017-06-01 Bernd Edlinger <bernd.edlinger@hotmail.de>
13
14 * config/i386/i386.c (ix86_frame): Moved to ...
15 * config/i386/i386.h (ix86_frame): Here.
16 (machine_function): Add frame.
17 * config/i386/i386.c (ix86_compute_frame_layout): Repace the
18 frame argument with &cfun->machine->frame.
19 (ix86_can_use_return_insn_p): Don't pass &frame to
20 ix86_compute_frame_layout. Copy frame from cfun->machine->frame.
21 (ix86_can_eliminate): Likewise.
22 (ix86_expand_prologue): Likewise.
23 (ix86_expand_epilogue): Likewise.
24 (ix86_expand_split_stack_prologue): Likewise.
25
26
27Upstream-Status: Pending
28
29Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
30
31---
32 gcc/config/i386/i386.c | 68 ++++++++++----------------------------------------
33 gcc/config/i386/i386.h | 53 ++++++++++++++++++++++++++++++++++++++-
34 2 files changed, 65 insertions(+), 56 deletions(-)
35
36diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
37index 8b5faac..a1ff32b 100644
38--- a/gcc/config/i386/i386.c
39+++ b/gcc/config/i386/i386.c
40@@ -2434,53 +2434,6 @@ struct GTY(()) stack_local_entry {
41 struct stack_local_entry *next;
42 };
43
44-/* Structure describing stack frame layout.
45- Stack grows downward:
46-
47- [arguments]
48- <- ARG_POINTER
49- saved pc
50-
51- saved static chain if ix86_static_chain_on_stack
52-
53- saved frame pointer if frame_pointer_needed
54- <- HARD_FRAME_POINTER
55- [saved regs]
56- <- regs_save_offset
57- [padding0]
58-
59- [saved SSE regs]
60- <- sse_regs_save_offset
61- [padding1] |
62- | <- FRAME_POINTER
63- [va_arg registers] |
64- |
65- [frame] |
66- |
67- [padding2] | = to_allocate
68- <- STACK_POINTER
69- */
70-struct ix86_frame
71-{
72- int nsseregs;
73- int nregs;
74- int va_arg_size;
75- int red_zone_size;
76- int outgoing_arguments_size;
77-
78- /* The offsets relative to ARG_POINTER. */
79- HOST_WIDE_INT frame_pointer_offset;
80- HOST_WIDE_INT hard_frame_pointer_offset;
81- HOST_WIDE_INT stack_pointer_offset;
82- HOST_WIDE_INT hfp_save_offset;
83- HOST_WIDE_INT reg_save_offset;
84- HOST_WIDE_INT sse_reg_save_offset;
85-
86- /* When save_regs_using_mov is set, emit prologue using
87- move instead of push instructions. */
88- bool save_regs_using_mov;
89-};
90-
91 /* Which cpu are we scheduling for. */
92 enum attr_cpu ix86_schedule;
93
94@@ -2572,7 +2525,7 @@ static unsigned int ix86_function_arg_boundary (machine_mode,
95 const_tree);
96 static rtx ix86_static_chain (const_tree, bool);
97 static int ix86_function_regparm (const_tree, const_tree);
98-static void ix86_compute_frame_layout (struct ix86_frame *);
99+static void ix86_compute_frame_layout (void);
100 static bool ix86_expand_vector_init_one_nonzero (bool, machine_mode,
101 rtx, rtx, int);
102 static void ix86_add_new_builtins (HOST_WIDE_INT);
103@@ -10944,7 +10897,8 @@ ix86_can_use_return_insn_p (void)
104 if (crtl->args.pops_args && crtl->args.size >= 32768)
105 return 0;
106
107- ix86_compute_frame_layout (&frame);
108+ ix86_compute_frame_layout ();
109+ frame = cfun->machine->frame;
110 return (frame.stack_pointer_offset == UNITS_PER_WORD
111 && (frame.nregs + frame.nsseregs) == 0);
112 }
113@@ -11355,8 +11309,8 @@ ix86_can_eliminate (const int from, const int to)
114 HOST_WIDE_INT
115 ix86_initial_elimination_offset (int from, int to)
116 {
117- struct ix86_frame frame;
118- ix86_compute_frame_layout (&frame);
119+ ix86_compute_frame_layout ();
120+ struct ix86_frame frame = cfun->machine->frame;
121
122 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
123 return frame.hard_frame_pointer_offset;
124@@ -11395,8 +11349,9 @@ ix86_builtin_setjmp_frame_value (void)
125 /* Fill structure ix86_frame about frame of currently computed function. */
126
127 static void
128-ix86_compute_frame_layout (struct ix86_frame *frame)
129+ix86_compute_frame_layout (void)
130 {
131+ struct ix86_frame *frame = &cfun->machine->frame;
132 unsigned HOST_WIDE_INT stack_alignment_needed;
133 HOST_WIDE_INT offset;
134 unsigned HOST_WIDE_INT preferred_alignment;
135@@ -12702,7 +12657,8 @@ ix86_expand_prologue (void)
136 m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
137 m->fs.sp_valid = true;
138
139- ix86_compute_frame_layout (&frame);
140+ ix86_compute_frame_layout ();
141+ frame = m->frame;
142
143 if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
144 {
145@@ -13379,7 +13335,8 @@ ix86_expand_epilogue (int style)
146 bool using_drap;
147
148 ix86_finalize_stack_realign_flags ();
149- ix86_compute_frame_layout (&frame);
150+ ix86_compute_frame_layout ();
151+ frame = m->frame;
152
153 m->fs.sp_valid = (!frame_pointer_needed
154 || (crtl->sp_is_unchanging
155@@ -13876,7 +13833,8 @@ ix86_expand_split_stack_prologue (void)
156 gcc_assert (flag_split_stack && reload_completed);
157
158 ix86_finalize_stack_realign_flags ();
159- ix86_compute_frame_layout (&frame);
160+ ix86_compute_frame_layout ();
161+ frame = cfun->machine->frame;
162 allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
163
164 /* This is the label we will branch to if we have enough stack
165diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
166index 8113f83..5414416 100644
167--- a/gcc/config/i386/i386.h
168+++ b/gcc/config/i386/i386.h
169@@ -2427,9 +2427,56 @@ enum avx_u128_state
170
171 #define FASTCALL_PREFIX '@'
172
173+#ifndef USED_FOR_TARGET
174+/* Structure describing stack frame layout.
175+ Stack grows downward:
176+
177+ [arguments]
178+ <- ARG_POINTER
179+ saved pc
180+
181+ saved static chain if ix86_static_chain_on_stack
182+
183+ saved frame pointer if frame_pointer_needed
184+ <- HARD_FRAME_POINTER
185+ [saved regs]
186+ <- regs_save_offset
187+ [padding0]
188+
189+ [saved SSE regs]
190+ <- sse_regs_save_offset
191+ [padding1] |
192+ | <- FRAME_POINTER
193+ [va_arg registers] |
194+ |
195+ [frame] |
196+ |
197+ [padding2] | = to_allocate
198+ <- STACK_POINTER
199+ */
200+struct GTY(()) ix86_frame
201+{
202+ int nsseregs;
203+ int nregs;
204+ int va_arg_size;
205+ int red_zone_size;
206+ int outgoing_arguments_size;
207+
208+ /* The offsets relative to ARG_POINTER. */
209+ HOST_WIDE_INT frame_pointer_offset;
210+ HOST_WIDE_INT hard_frame_pointer_offset;
211+ HOST_WIDE_INT stack_pointer_offset;
212+ HOST_WIDE_INT hfp_save_offset;
213+ HOST_WIDE_INT reg_save_offset;
214+ HOST_WIDE_INT sse_reg_save_offset;
215+
216+ /* When save_regs_using_mov is set, emit prologue using
217+ move instead of push instructions. */
218+ bool save_regs_using_mov;
219+};
220+
221 /* Machine specific frame tracking during prologue/epilogue generation. */
222
223-#ifndef USED_FOR_TARGET
224 struct GTY(()) machine_frame_state
225 {
226 /* This pair tracks the currently active CFA as reg+offset. When reg
227@@ -2475,6 +2522,9 @@ struct GTY(()) machine_function {
228 int varargs_fpr_size;
229 int optimize_mode_switching[MAX_386_ENTITIES];
230
231+ /* Cached initial frame layout for the current function. */
232+ struct ix86_frame frame;
233+
234 /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE
235 has been computed for. */
236 int use_fast_prologue_epilogue_nregs;
237@@ -2554,6 +2604,7 @@ struct GTY(()) machine_function {
238 #define ix86_current_function_calls_tls_descriptor \
239 (ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG))
240 #define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack)
241+#define ix86_red_zone_size (cfun->machine->frame.red_zone_size)
242
243 /* Control behavior of x86_file_start. */
244 #define X86_FILE_START_VERSION_DIRECTIVE false
245--
2462.7.4
247
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch
new file mode 100644
index 0000000..df65b08
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch
@@ -0,0 +1,74 @@
1From fe2b3be3f4b6ec6b3a6f89c26016a3983b7cb351 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Mon, 15 Jan 2018 11:28:44 +0000
4Subject: [PATCH 02/12] i386: Use reference of struct ix86_frame to avoid copy
5
6When there is no need to make a copy of ix86_frame, we can use reference
7of struct ix86_frame to avoid copy.
8
9 Backport from mainline
10 2017-11-06 H.J. Lu <hongjiu.lu@intel.com>
11
12 * config/i386/i386.c (ix86_can_use_return_insn_p): Use reference
13 of struct ix86_frame.
14 (ix86_initial_elimination_offset): Likewise.
15 (ix86_expand_split_stack_prologue): Likewise.
16
17Upstream-Status: Pending
18
19Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
20
21---
22 gcc/config/i386/i386.c | 8 +++-----
23 1 file changed, 3 insertions(+), 5 deletions(-)
24
25diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
26index a1ff32b..13ebf10 100644
27--- a/gcc/config/i386/i386.c
28+++ b/gcc/config/i386/i386.c
29@@ -10887,7 +10887,6 @@ symbolic_reference_mentioned_p (rtx op)
30 bool
31 ix86_can_use_return_insn_p (void)
32 {
33- struct ix86_frame frame;
34
35 if (! reload_completed || frame_pointer_needed)
36 return 0;
37@@ -10898,7 +10897,7 @@ ix86_can_use_return_insn_p (void)
38 return 0;
39
40 ix86_compute_frame_layout ();
41- frame = cfun->machine->frame;
42+ struct ix86_frame &frame = cfun->machine->frame;
43 return (frame.stack_pointer_offset == UNITS_PER_WORD
44 && (frame.nregs + frame.nsseregs) == 0);
45 }
46@@ -11310,7 +11309,7 @@ HOST_WIDE_INT
47 ix86_initial_elimination_offset (int from, int to)
48 {
49 ix86_compute_frame_layout ();
50- struct ix86_frame frame = cfun->machine->frame;
51+ struct ix86_frame &frame = cfun->machine->frame;
52
53 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
54 return frame.hard_frame_pointer_offset;
55@@ -13821,7 +13820,6 @@ static GTY(()) rtx split_stack_fn_large;
56 void
57 ix86_expand_split_stack_prologue (void)
58 {
59- struct ix86_frame frame;
60 HOST_WIDE_INT allocate;
61 unsigned HOST_WIDE_INT args_size;
62 rtx_code_label *label;
63@@ -13834,7 +13832,7 @@ ix86_expand_split_stack_prologue (void)
64
65 ix86_finalize_stack_realign_flags ();
66 ix86_compute_frame_layout ();
67- frame = cfun->machine->frame;
68+ struct ix86_frame &frame = cfun->machine->frame;
69 allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
70
71 /* This is the label we will branch to if we have enough stack
72--
732.7.4
74
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch
new file mode 100644
index 0000000..a5ffd85
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch
@@ -0,0 +1,131 @@
1From 82243732dc63e9b90396a5ae4ad99ca36af81355 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Sat, 27 Jan 2018 13:10:24 +0000
4Subject: [PATCH 03/12] i386: Use const reference of struct ix86_frame to avoid
5 copy
6
7We can use const reference of struct ix86_frame to avoid making a local
8copy of ix86_frame. ix86_expand_epilogue makes a local copy of struct
9ix86_frame and uses the reg_save_offset field as a local variable. This
10patch uses a separate local variable for reg_save_offset.
11
12Tested on x86-64 with ada.
13
14 Backport from mainline
15 PR target/83905
16 * config/i386/i386.c (ix86_expand_prologue): Use cost reference
17 of struct ix86_frame.
18 (ix86_expand_epilogue): Likewise. Add a local variable for
19 the reg_save_offset field in struct ix86_frame.
20
21git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@257123 138bc75d-0d04-0410-961f-82ee72b054a4
22
23Upstream-Status: Pending
24
25Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
26
27---
28 gcc/config/i386/i386.c | 24 ++++++++++++------------
29 1 file changed, 12 insertions(+), 12 deletions(-)
30
31diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
32index 13ebf10..6c98f75 100644
33--- a/gcc/config/i386/i386.c
34+++ b/gcc/config/i386/i386.c
35@@ -12633,7 +12633,6 @@ ix86_expand_prologue (void)
36 {
37 struct machine_function *m = cfun->machine;
38 rtx insn, t;
39- struct ix86_frame frame;
40 HOST_WIDE_INT allocate;
41 bool int_registers_saved;
42 bool sse_registers_saved;
43@@ -12657,7 +12656,7 @@ ix86_expand_prologue (void)
44 m->fs.sp_valid = true;
45
46 ix86_compute_frame_layout ();
47- frame = m->frame;
48+ const struct ix86_frame &frame = cfun->machine->frame;
49
50 if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
51 {
52@@ -13329,13 +13328,12 @@ ix86_expand_epilogue (int style)
53 {
54 struct machine_function *m = cfun->machine;
55 struct machine_frame_state frame_state_save = m->fs;
56- struct ix86_frame frame;
57 bool restore_regs_via_mov;
58 bool using_drap;
59
60 ix86_finalize_stack_realign_flags ();
61 ix86_compute_frame_layout ();
62- frame = m->frame;
63+ const struct ix86_frame &frame = cfun->machine->frame;
64
65 m->fs.sp_valid = (!frame_pointer_needed
66 || (crtl->sp_is_unchanging
67@@ -13377,11 +13375,13 @@ ix86_expand_epilogue (int style)
68 + UNITS_PER_WORD);
69 }
70
71+ HOST_WIDE_INT reg_save_offset = frame.reg_save_offset;
72+
73 /* Special care must be taken for the normal return case of a function
74 using eh_return: the eax and edx registers are marked as saved, but
75 not restored along this path. Adjust the save location to match. */
76 if (crtl->calls_eh_return && style != 2)
77- frame.reg_save_offset -= 2 * UNITS_PER_WORD;
78+ reg_save_offset -= 2 * UNITS_PER_WORD;
79
80 /* EH_RETURN requires the use of moves to function properly. */
81 if (crtl->calls_eh_return)
82@@ -13397,11 +13397,11 @@ ix86_expand_epilogue (int style)
83 else if (TARGET_EPILOGUE_USING_MOVE
84 && cfun->machine->use_fast_prologue_epilogue
85 && (frame.nregs > 1
86- || m->fs.sp_offset != frame.reg_save_offset))
87+ || m->fs.sp_offset != reg_save_offset))
88 restore_regs_via_mov = true;
89 else if (frame_pointer_needed
90 && !frame.nregs
91- && m->fs.sp_offset != frame.reg_save_offset)
92+ && m->fs.sp_offset != reg_save_offset)
93 restore_regs_via_mov = true;
94 else if (frame_pointer_needed
95 && TARGET_USE_LEAVE
96@@ -13439,7 +13439,7 @@ ix86_expand_epilogue (int style)
97 rtx t;
98
99 if (frame.nregs)
100- ix86_emit_restore_regs_using_mov (frame.reg_save_offset, style == 2);
101+ ix86_emit_restore_regs_using_mov (reg_save_offset, style == 2);
102
103 /* eh_return epilogues need %ecx added to the stack pointer. */
104 if (style == 2)
105@@ -13529,19 +13529,19 @@ ix86_expand_epilogue (int style)
106 epilogues. */
107 if (!m->fs.sp_valid
108 || (TARGET_SEH
109- && (m->fs.sp_offset - frame.reg_save_offset
110+ && (m->fs.sp_offset - reg_save_offset
111 >= SEH_MAX_FRAME_SIZE)))
112 {
113 pro_epilogue_adjust_stack (stack_pointer_rtx, hard_frame_pointer_rtx,
114 GEN_INT (m->fs.fp_offset
115- - frame.reg_save_offset),
116+ - reg_save_offset),
117 style, false);
118 }
119- else if (m->fs.sp_offset != frame.reg_save_offset)
120+ else if (m->fs.sp_offset != reg_save_offset)
121 {
122 pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
123 GEN_INT (m->fs.sp_offset
124- - frame.reg_save_offset),
125+ - reg_save_offset),
126 style,
127 m->fs.cfa_reg == stack_pointer_rtx);
128 }
129--
1302.7.4
131
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 0000000..a9d6e5f
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch
@@ -0,0 +1,2154 @@
1From 6140c2c0bb2b61e69d0da84315e0433ff3520aaa Mon Sep 17 00:00:00 2001
2From: "H.J. Lu" <hjl.tools@gmail.com>
3Date: Sat, 6 Jan 2018 22:29:55 -0800
4Subject: [PATCH 04/12] x86: Add -mindirect-branch=
5
6Add -mindirect-branch= option to convert indirect call and jump to call
7and return thunks. The default is 'keep', which keeps indirect call and
8jump unmodified. 'thunk' converts indirect call and jump to call and
9return thunk. 'thunk-inline' converts indirect call and jump to inlined
10call and return thunk. 'thunk-extern' converts indirect call and jump to
11external call and return thunk provided in a separate object file. You
12can control this behavior for a specific function by using the function
13attribute indirect_branch.
14
152 kinds of thunks are geneated. Memory thunk where the function address
16is at the top of the stack:
17
18__x86_indirect_thunk:
19 call L2
20L1:
21 pause
22 lfence
23 jmp L1
24L2:
25 lea 8(%rsp), %rsp|lea 4(%esp), %esp
26 ret
27
28Indirect jmp via memory, "jmp mem", is converted to
29
30 push memory
31 jmp __x86_indirect_thunk
32
33Indirect call via memory, "call mem", is converted to
34
35 jmp L2
36L1:
37 push [mem]
38 jmp __x86_indirect_thunk
39L2:
40 call L1
41
42Register thunk where the function address is in a register, reg:
43
44__x86_indirect_thunk_reg:
45 call L2
46L1:
47 pause
48 lfence
49 jmp L1
50L2:
51 movq %reg, (%rsp)|movl %reg, (%esp)
52 ret
53
54where 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
57Indirect jmp via register, "jmp reg", is converted to
58
59 jmp __x86_indirect_thunk_reg
60
61Indirect call via register, "call reg", is converted to
62
63 call __x86_indirect_thunk_reg
64
65gcc/
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
111gcc/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
150Upstream-Status: Pending
151
152Signed-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
231diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h
232index 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
253diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
254index 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
265diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
266index 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 };
1020diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
1021index 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
1038diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
1039index 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
1100diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
1101index 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)
1128diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
1129index 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
1149diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
1150index 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
1180diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1181new file mode 100644
1182index 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} } } */
1206diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1207new file mode 100644
1208index 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} } } */
1232diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1233new file mode 100644
1234index 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} } } */
1259diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1260new file mode 100644
1261index 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} } } */
1286diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
1287new file mode 100644
1288index 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} } } */
1309diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
1310new file mode 100644
1311index 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} } } */
1333diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1334new file mode 100644
1335index 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} } } */
1383diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1384new file mode 100644
1385index 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} } } */
1412diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1413new file mode 100644
1414index 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} } } */
1439diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1440new file mode 100644
1441index 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 } } } */
1468diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1469new file mode 100644
1470index 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 } } } */
1496diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1497new file mode 100644
1498index 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)} } } */
1524diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1525new file mode 100644
1526index 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)} } } */
1551diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1552new file mode 100644
1553index 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" } } */
1601diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1602new file mode 100644
1603index 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" } } */
1649diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
1650new file mode 100644
1651index 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} } } */
1675diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
1676new file mode 100644
1677index 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} } } */
1702diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
1703new file mode 100644
1704index 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} } } */
1727diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
1728new file mode 100644
1729index 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} } } */
1753diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
1754new file mode 100644
1755index 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" } } */
1778diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
1779new file mode 100644
1780index 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" } } */
1803diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
1804new file mode 100644
1805index 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)} } } */
1829diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1830new file mode 100644
1831index 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)} } } */
1855diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
1856new file mode 100644
1857index 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" } } */
1877diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
1878new file mode 100644
1879index 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)} } } */
1900diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1901new file mode 100644
1902index 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" } } */
1949diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1950new file mode 100644
1951index 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 } } } */
1975diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1976new file mode 100644
1977index 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 } } } */
2001diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
2002new file mode 100644
2003index 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 } } } */
2028diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
2029new file mode 100644
2030index 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 } } } */
2055diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
2056new file mode 100644
2057index 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" } } */
2078diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
2079new file mode 100644
2080index 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" } } */
2102diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
2103new file mode 100644
2104index 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--
21532.7.4
2154
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch
new file mode 100644
index 0000000..5354c77
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch
@@ -0,0 +1,1570 @@
1From e3270814b9e0caad63fbcdfd7ae9da2d52c97497 Mon Sep 17 00:00:00 2001
2From: "H.J. Lu" <hjl.tools@gmail.com>
3Date: Sat, 6 Jan 2018 22:29:56 -0800
4Subject: [PATCH 05/12] x86: Add -mfunction-return=
5
6Add -mfunction-return= option to convert function return to call and
7return thunks. The default is 'keep', which keeps function return
8unmodified. 'thunk' converts function return to call and return thunk.
9'thunk-inline' converts function return to inlined call and return thunk.
10'thunk-extern' converts function return to external call and return
11thunk provided in a separate object file. You can control this behavior
12for a specific function by using the function attribute function_return.
13
14Function return thunk is the same as memory thunk for -mindirect-branch=
15where the return address is at the top of the stack:
16
17__x86_return_thunk:
18 call L2
19L1:
20 pause
21 lfence
22 jmp L1
23L2:
24 lea 8(%rsp), %rsp|lea 4(%esp), %esp
25 ret
26
27and function return becomes
28
29 jmp __x86_return_thunk
30
31-mindirect-branch= tests are updated with -mfunction-return=keep to
32avoid false test failures when -mfunction-return=thunk is added to
33RUNTESTFLAGS for "make check".
34
35gcc/
36
37 Backport from mainline
38 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
39
40 * config/i386/i386-protos.h (ix86_output_function_return): New.
41 * config/i386/i386.c (ix86_set_indirect_branch_type): Also
42 set function_return_type.
43 (indirect_thunk_name): Add ret_p to indicate thunk for function
44 return.
45 (output_indirect_thunk_function): Pass false to
46 indirect_thunk_name.
47 (ix86_output_indirect_branch_via_reg): Likewise.
48 (ix86_output_indirect_branch_via_push): Likewise.
49 (output_indirect_thunk_function): Create alias for function
50 return thunk if regno < 0.
51 (ix86_output_function_return): New function.
52 (ix86_handle_fndecl_attribute): Handle function_return.
53 (ix86_attribute_table): Add function_return.
54 * config/i386/i386.h (machine_function): Add
55 function_return_type.
56 * config/i386/i386.md (simple_return_internal): Use
57 ix86_output_function_return.
58 (simple_return_internal_long): Likewise.
59 * config/i386/i386.opt (mfunction-return=): New option.
60 (indirect_branch): Mention -mfunction-return=.
61 * doc/extend.texi: Document function_return function attribute.
62 * doc/invoke.texi: Document -mfunction-return= option.
63
64gcc/testsuite/
65
66 Backport from mainline
67 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
68
69 * gcc.target/i386/indirect-thunk-1.c (dg-options): Add
70 -mfunction-return=keep.
71 * gcc.target/i386/indirect-thunk-2.c: Likewise.
72 * gcc.target/i386/indirect-thunk-3.c: Likewise.
73 * gcc.target/i386/indirect-thunk-4.c: Likewise.
74 * gcc.target/i386/indirect-thunk-5.c: Likewise.
75 * gcc.target/i386/indirect-thunk-6.c: Likewise.
76 * gcc.target/i386/indirect-thunk-7.c: Likewise.
77 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
78 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
79 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
80 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
81 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
82 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
83 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
84 * gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
85 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
86 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
87 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
88 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
89 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
90 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
91 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
92 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
93 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
94 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
95 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
96 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
97 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
98 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
99 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
100 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
101 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
102 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
103 * gcc.target/i386/ret-thunk-1.c: New test.
104 * gcc.target/i386/ret-thunk-10.c: Likewise.
105 * gcc.target/i386/ret-thunk-11.c: Likewise.
106 * gcc.target/i386/ret-thunk-12.c: Likewise.
107 * gcc.target/i386/ret-thunk-13.c: Likewise.
108 * gcc.target/i386/ret-thunk-14.c: Likewise.
109 * gcc.target/i386/ret-thunk-15.c: Likewise.
110 * gcc.target/i386/ret-thunk-16.c: Likewise.
111 * gcc.target/i386/ret-thunk-2.c: Likewise.
112 * gcc.target/i386/ret-thunk-3.c: Likewise.
113 * gcc.target/i386/ret-thunk-4.c: Likewise.
114 * gcc.target/i386/ret-thunk-5.c: Likewise.
115 * gcc.target/i386/ret-thunk-6.c: Likewise.
116 * gcc.target/i386/ret-thunk-7.c: Likewise.
117 * gcc.target/i386/ret-thunk-8.c: Likewise.
118 * gcc.target/i386/ret-thunk-9.c: Likewise.
119
120i386: Don't use ASM_OUTPUT_DEF for TARGET_MACHO
121
122ASM_OUTPUT_DEF isn't defined for TARGET_MACHO. Use ASM_OUTPUT_LABEL to
123generate the __x86_return_thunk label, instead of the set directive.
124Update testcase to remove the __x86_return_thunk label check. Since
125-fno-pic is ignored on Darwin, update testcases to sscan or "push"
126only on Linux.
127
128gcc/
129
130 Backport from mainline
131 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
132
133 PR target/83839
134 * config/i386/i386.c (output_indirect_thunk_function): Use
135 ASM_OUTPUT_LABEL, instead of ASM_OUTPUT_DEF, for TARGET_MACHO
136 for __x86.return_thunk.
137
138gcc/testsuite/
139
140 Backport from mainline
141 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
142
143 PR target/83839
144 * gcc.target/i386/indirect-thunk-1.c: Scan for "push" only on
145 Linux.
146 * gcc.target/i386/indirect-thunk-2.c: Likewise.
147 * gcc.target/i386/indirect-thunk-3.c: Likewise.
148 * gcc.target/i386/indirect-thunk-4.c: Likewise.
149 * gcc.target/i386/indirect-thunk-7.c: Likewise.
150 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
151 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
152 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
153 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
154 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
155 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
156 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
157 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
158 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
159 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
160 * gcc.target/i386/indirect-thunk-register-1.c: Likewise.
161 * gcc.target/i386/indirect-thunk-register-3.c: Likewise.
162 * gcc.target/i386/indirect-thunk-register-4.c: Likewise.
163 * gcc.target/i386/ret-thunk-10.c: Likewise.
164 * gcc.target/i386/ret-thunk-11.c: Likewise.
165 * gcc.target/i386/ret-thunk-12.c: Likewise.
166 * gcc.target/i386/ret-thunk-13.c: Likewise.
167 * gcc.target/i386/ret-thunk-14.c: Likewise.
168 * gcc.target/i386/ret-thunk-15.c: Likewise.
169 * gcc.target/i386/ret-thunk-9.c: Don't check the
170 __x86_return_thunk label.
171 Scan for "push" only for Linux.
172
173Upstream-Status: Pending
174
175Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
176
177---
178 gcc/config/i386/i386-protos.h | 1 +
179 gcc/config/i386/i386.c | 152 +++++++++++++++++++--
180 gcc/config/i386/i386.h | 3 +
181 gcc/config/i386/i386.md | 9 +-
182 gcc/config/i386/i386.opt | 6 +-
183 gcc/doc/extend.texi | 9 ++
184 gcc/doc/invoke.texi | 14 +-
185 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 4 +-
186 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 4 +-
187 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 4 +-
188 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 4 +-
189 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 2 +-
190 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 2 +-
191 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 4 +-
192 .../gcc.target/i386/indirect-thunk-attr-1.c | 4 +-
193 .../gcc.target/i386/indirect-thunk-attr-2.c | 4 +-
194 .../gcc.target/i386/indirect-thunk-attr-3.c | 4 +-
195 .../gcc.target/i386/indirect-thunk-attr-4.c | 4 +-
196 .../gcc.target/i386/indirect-thunk-attr-5.c | 4 +-
197 .../gcc.target/i386/indirect-thunk-attr-6.c | 4 +-
198 .../gcc.target/i386/indirect-thunk-attr-7.c | 4 +-
199 .../gcc.target/i386/indirect-thunk-attr-8.c | 2 +-
200 .../gcc.target/i386/indirect-thunk-bnd-1.c | 4 +-
201 .../gcc.target/i386/indirect-thunk-bnd-2.c | 4 +-
202 .../gcc.target/i386/indirect-thunk-bnd-3.c | 2 +-
203 .../gcc.target/i386/indirect-thunk-bnd-4.c | 2 +-
204 .../gcc.target/i386/indirect-thunk-extern-1.c | 4 +-
205 .../gcc.target/i386/indirect-thunk-extern-2.c | 4 +-
206 .../gcc.target/i386/indirect-thunk-extern-3.c | 4 +-
207 .../gcc.target/i386/indirect-thunk-extern-4.c | 4 +-
208 .../gcc.target/i386/indirect-thunk-extern-5.c | 2 +-
209 .../gcc.target/i386/indirect-thunk-extern-6.c | 2 +-
210 .../gcc.target/i386/indirect-thunk-extern-7.c | 4 +-
211 .../gcc.target/i386/indirect-thunk-inline-1.c | 4 +-
212 .../gcc.target/i386/indirect-thunk-inline-2.c | 4 +-
213 .../gcc.target/i386/indirect-thunk-inline-3.c | 4 +-
214 .../gcc.target/i386/indirect-thunk-inline-4.c | 4 +-
215 .../gcc.target/i386/indirect-thunk-inline-5.c | 2 +-
216 .../gcc.target/i386/indirect-thunk-inline-6.c | 2 +-
217 .../gcc.target/i386/indirect-thunk-inline-7.c | 4 +-
218 gcc/testsuite/gcc.target/i386/ret-thunk-1.c | 13 ++
219 gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 23 ++++
220 gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 23 ++++
221 gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 22 +++
222 gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 22 +++
223 gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 22 +++
224 gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 22 +++
225 gcc/testsuite/gcc.target/i386/ret-thunk-16.c | 18 +++
226 gcc/testsuite/gcc.target/i386/ret-thunk-2.c | 13 ++
227 gcc/testsuite/gcc.target/i386/ret-thunk-3.c | 12 ++
228 gcc/testsuite/gcc.target/i386/ret-thunk-4.c | 12 ++
229 gcc/testsuite/gcc.target/i386/ret-thunk-5.c | 15 ++
230 gcc/testsuite/gcc.target/i386/ret-thunk-6.c | 14 ++
231 gcc/testsuite/gcc.target/i386/ret-thunk-7.c | 13 ++
232 gcc/testsuite/gcc.target/i386/ret-thunk-8.c | 14 ++
233 gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 24 ++++
234 56 files changed, 516 insertions(+), 74 deletions(-)
235 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-1.c
236 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-10.c
237 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-11.c
238 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-12.c
239 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-13.c
240 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-14.c
241 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-15.c
242 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-16.c
243 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-2.c
244 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-3.c
245 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-4.c
246 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-5.c
247 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-6.c
248 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-7.c
249 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-8.c
250 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-9.c
251
252diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
253index eca4cbf..620d70e 100644
254--- a/gcc/config/i386/i386-protos.h
255+++ b/gcc/config/i386/i386-protos.h
256@@ -312,6 +312,7 @@ extern enum attr_cpu ix86_schedule;
257
258 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
259 extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
260+extern const char * ix86_output_function_return (bool long_p);
261 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
262 enum machine_mode mode);
263
264diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
265index 0b9fc4d..34e26a3 100644
266--- a/gcc/config/i386/i386.c
267+++ b/gcc/config/i386/i386.c
268@@ -6390,6 +6390,31 @@ ix86_set_indirect_branch_type (tree fndecl)
269 else
270 cfun->machine->indirect_branch_type = ix86_indirect_branch;
271 }
272+
273+ if (cfun->machine->function_return_type == indirect_branch_unset)
274+ {
275+ tree attr = lookup_attribute ("function_return",
276+ DECL_ATTRIBUTES (fndecl));
277+ if (attr != NULL)
278+ {
279+ tree args = TREE_VALUE (attr);
280+ if (args == NULL)
281+ gcc_unreachable ();
282+ tree cst = TREE_VALUE (args);
283+ if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
284+ cfun->machine->function_return_type = indirect_branch_keep;
285+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
286+ cfun->machine->function_return_type = indirect_branch_thunk;
287+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
288+ cfun->machine->function_return_type = indirect_branch_thunk_inline;
289+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
290+ cfun->machine->function_return_type = indirect_branch_thunk_extern;
291+ else
292+ gcc_unreachable ();
293+ }
294+ else
295+ cfun->machine->function_return_type = ix86_function_return;
296+ }
297 }
298
299 /* Establish appropriate back-end context for processing the function
300@@ -11036,8 +11061,12 @@ static int indirect_thunks_bnd_used;
301 /* Fills in the label name that should be used for the indirect thunk. */
302
303 static void
304-indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
305+indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
306+ bool ret_p)
307 {
308+ if (regno >= 0 && ret_p)
309+ gcc_unreachable ();
310+
311 if (USE_HIDDEN_LINKONCE)
312 {
313 const char *bnd = need_bnd_p ? "_bnd" : "";
314@@ -11052,7 +11081,10 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
315 bnd, reg_prefix, reg_names[regno]);
316 }
317 else
318- sprintf (name, "__x86_indirect_thunk%s", bnd);
319+ {
320+ const char *ret = ret_p ? "return" : "indirect";
321+ sprintf (name, "__x86_%s_thunk%s", ret, bnd);
322+ }
323 }
324 else
325 {
326@@ -11065,10 +11097,20 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
327 }
328 else
329 {
330- if (need_bnd_p)
331- ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
332+ if (ret_p)
333+ {
334+ if (need_bnd_p)
335+ ASM_GENERATE_INTERNAL_LABEL (name, "LRTB", 0);
336+ else
337+ ASM_GENERATE_INTERNAL_LABEL (name, "LRT", 0);
338+ }
339 else
340- ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
341+ {
342+ if (need_bnd_p)
343+ ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
344+ else
345+ ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
346+ }
347 }
348 }
349 }
350@@ -11163,7 +11205,7 @@ output_indirect_thunk_function (bool need_bnd_p, int regno)
351 tree decl;
352
353 /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */
354- indirect_thunk_name (name, regno, need_bnd_p);
355+ indirect_thunk_name (name, regno, need_bnd_p, false);
356 decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
357 get_identifier (name),
358 build_function_type_list (void_type_node, NULL_TREE));
359@@ -11206,6 +11248,36 @@ output_indirect_thunk_function (bool need_bnd_p, int regno)
360 ASM_OUTPUT_LABEL (asm_out_file, name);
361 }
362
363+ if (regno < 0)
364+ {
365+ /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
366+ char alias[32];
367+
368+ indirect_thunk_name (alias, regno, need_bnd_p, true);
369+#if TARGET_MACHO
370+ if (TARGET_MACHO)
371+ {
372+ fputs ("\t.weak_definition\t", asm_out_file);
373+ assemble_name (asm_out_file, alias);
374+ fputs ("\n\t.private_extern\t", asm_out_file);
375+ assemble_name (asm_out_file, alias);
376+ putc ('\n', asm_out_file);
377+ ASM_OUTPUT_LABEL (asm_out_file, alias);
378+ }
379+#else
380+ ASM_OUTPUT_DEF (asm_out_file, alias, name);
381+ if (USE_HIDDEN_LINKONCE)
382+ {
383+ fputs ("\t.globl\t", asm_out_file);
384+ assemble_name (asm_out_file, alias);
385+ putc ('\n', asm_out_file);
386+ fputs ("\t.hidden\t", asm_out_file);
387+ assemble_name (asm_out_file, alias);
388+ putc ('\n', asm_out_file);
389+ }
390+#endif
391+ }
392+
393 DECL_INITIAL (decl) = make_node (BLOCK);
394 current_function_decl = decl;
395 allocate_struct_function (decl, false);
396@@ -27687,7 +27759,7 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
397 else
398 indirect_thunks_used |= 1 << i;
399 }
400- indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
401+ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
402 thunk_name = thunk_name_buf;
403 }
404 else
405@@ -27796,7 +27868,7 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
406 else
407 indirect_thunk_needed = true;
408 }
409- indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
410+ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
411 thunk_name = thunk_name_buf;
412 }
413 else
414@@ -27931,6 +28003,46 @@ ix86_output_indirect_jmp (rtx call_op, bool ret_p)
415 return "%!jmp\t%A0";
416 }
417
418+/* Output function return. CALL_OP is the jump target. Add a REP
419+ prefix to RET if LONG_P is true and function return is kept. */
420+
421+const char *
422+ix86_output_function_return (bool long_p)
423+{
424+ if (cfun->machine->function_return_type != indirect_branch_keep)
425+ {
426+ char thunk_name[32];
427+ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
428+
429+ if (cfun->machine->function_return_type
430+ != indirect_branch_thunk_inline)
431+ {
432+ bool need_thunk = (cfun->machine->function_return_type
433+ == indirect_branch_thunk);
434+ indirect_thunk_name (thunk_name, -1, need_bnd_p, true);
435+ if (need_bnd_p)
436+ {
437+ indirect_thunk_bnd_needed |= need_thunk;
438+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
439+ }
440+ else
441+ {
442+ indirect_thunk_needed |= need_thunk;
443+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
444+ }
445+ }
446+ else
447+ output_indirect_thunk (need_bnd_p, -1);
448+
449+ return "";
450+ }
451+
452+ if (!long_p || ix86_bnd_prefixed_insn_p (current_output_insn))
453+ return "%!ret";
454+
455+ return "rep%; ret";
456+}
457+
458 /* Output the assembly for a call instruction. */
459
460 const char *
461@@ -45461,6 +45573,28 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int,
462 }
463 }
464
465+ if (is_attribute_p ("function_return", name))
466+ {
467+ tree cst = TREE_VALUE (args);
468+ if (TREE_CODE (cst) != STRING_CST)
469+ {
470+ warning (OPT_Wattributes,
471+ "%qE attribute requires a string constant argument",
472+ name);
473+ *no_add_attrs = true;
474+ }
475+ else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
476+ && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
477+ && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
478+ && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
479+ {
480+ warning (OPT_Wattributes,
481+ "argument to %qE attribute is not "
482+ "(keep|thunk|thunk-inline|thunk-extern)", name);
483+ *no_add_attrs = true;
484+ }
485+ }
486+
487 return NULL_TREE;
488 }
489
490@@ -49690,6 +49824,8 @@ static const struct attribute_spec ix86_attribute_table[] =
491 ix86_handle_callee_pop_aggregate_return, true },
492 { "indirect_branch", 1, 1, true, false, false,
493 ix86_handle_fndecl_attribute, false },
494+ { "function_return", 1, 1, true, false, false,
495+ ix86_handle_fndecl_attribute, false },
496
497 /* End element. */
498 { NULL, 0, 0, false, false, false, NULL, false }
499diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
500index 9dccdb0..b34bc11 100644
501--- a/gcc/config/i386/i386.h
502+++ b/gcc/config/i386/i386.h
503@@ -2579,6 +2579,9 @@ struct GTY(()) machine_function {
504 "indirect_jump" or "tablejump". */
505 BOOL_BITFIELD has_local_indirect_jump : 1;
506
507+ /* How to generate function return. */
508+ ENUM_BITFIELD(indirect_branch) function_return_type : 3;
509+
510 /* If true, there is register available for argument passing. This
511 is used only in ix86_function_ok_for_sibcall by 32-bit to determine
512 if there is scratch register available for indirect sibcall. In
513diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
514index 153e162..2da671e 100644