summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-01-06 22:29:55 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-01-07 08:54:24 -0800
commitfdddac6289f5bb64a6180b40572cc084f5452aa8 (patch)
treea9c90cec7a08f8dc59b62ecee0cbbb2329c7df8a
parentce3c2faad7b9761171ccaa438212318e9063f916 (diff)
downloadgcc-fdddac6289f5bb64a6180b40572cc084f5452aa8.tar.gz
x86: Add -mindirect-branch-loop=
Add -mindirect-branch-loop= option to control loop filler in call and return thunks generated by -mindirect-branch=. 'lfence' uses "lfence" as loop filler. 'pause' uses "pause" as loop filler. 'nop' uses "nop" as loop filler. The default is 'lfence'. gcc/ * config/i386/i386-opts.h (indirect_branch_loop): New. * config/i386/i386.c (output_indirect_thunk): Support -mindirect-branch-loop=. * config/i386/i386.opt (mindirect-branch-loop=): New option. (indirect_branch_loop): New. (lfence): Likewise. (pause): Likewise. (nop): Likewise. * doc/invoke.texi: Document -mindirect-branch-loop= option. gcc/testsuite/ * gcc.target/i386/indirect-thunk-loop-1.c: New test. * gcc.target/i386/indirect-thunk-loop-2.c: Likewise. * gcc.target/i386/indirect-thunk-loop-3.c: Likewise. * gcc.target/i386/indirect-thunk-loop-4.c: Likewise. * gcc.target/i386/indirect-thunk-loop-5.c: Likewise.
-rw-r--r--gcc/config/i386/i386-opts.h6
-rw-r--r--gcc/config/i386/i386.c19
-rw-r--r--gcc/config/i386/i386.opt17
-rw-r--r--gcc/doc/invoke.texi9
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c19
9 files changed, 143 insertions, 3 deletions
diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h
index f14cbeee7a1..52f7cb979cc 100644
--- a/gcc/config/i386/i386-opts.h
+++ b/gcc/config/i386/i386-opts.h
@@ -114,4 +114,10 @@ enum indirect_branch {
indirect_branch_thunk_extern
};
+enum indirect_branch_loop {
+ indirect_branch_loop_lfence,
+ indirect_branch_loop_pause,
+ indirect_branch_loop_nop
+};
+
#endif
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index ac4d1f62f50..f327a6b1b62 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10753,8 +10753,23 @@ output_indirect_thunk (bool need_bnd_p, int regno)
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
- /* lfence . */
- fprintf (asm_out_file, "\tlfence\n");
+ switch (ix86_indirect_branch_loop)
+ {
+ case indirect_branch_loop_lfence:
+ /* lfence. */
+ fprintf (asm_out_file, "\tlfence\n");
+ break;
+ case indirect_branch_loop_pause:
+ /* pause. */
+ fprintf (asm_out_file, "\tpause\n");
+ break;
+ case indirect_branch_loop_nop:
+ /* nop. */
+ fprintf (asm_out_file, "\tnop\n");
+ break;
+ default:
+ gcc_unreachable ();
+ }
/* Jump. */
fputs ("\tjmp\t", asm_out_file);
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 22c806206e4..f3e43da0aed 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -1041,3 +1041,20 @@ Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
EnumValue
Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
+
+mindirect-branch-loop=
+Target Report RejectNegative Joined Enum(indirect_branch_loop) Var(ix86_indirect_branch_loop) Init(indirect_branch_loop_lfence)
+Control loop filler in call and return thunk for indirect call and jump.
+
+Enum
+Name(indirect_branch_loop) Type(enum indirect_branch_loop)
+Known looop choices (for use with the -mindirect-branch-loop= option):
+
+EnumValue
+Enum(indirect_branch_loop) String(lfence) Value(indirect_branch_loop_lfence)
+
+EnumValue
+Enum(indirect_branch_loop) String(pause) Value(indirect_branch_loop_pause)
+
+EnumValue
+Enum(indirect_branch_loop) String(nop) Value(indirect_branch_loop_nop)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 46461d1ada3..ee5248aba59 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1227,7 +1227,7 @@ See RS/6000 and PowerPC Options.
-mstack-protector-guard-offset=@var{offset} @gol
-mstack-protector-guard-symbol=@var{symbol} -mmitigate-rop @gol
-mgeneral-regs-only -mcall-ms2sysv-xlogues @gol
--mindirect-branch=@var{choice}}
+-mindirect-branch=@var{choice} -mindirect-branch-loop=@var{choice}}
@emph{x86 Windows Options}
@gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
@@ -26776,6 +26776,13 @@ to external call and return thunk provided in a separate object file.
You can control this behavior for a specific function by using the
function attribute @code{indirect_branch}. @xref{Function Attributes}.
+@item -mindirect-branch-loop=@var{choice}
+@opindex -mindirect-branch-boop
+Control loop filler in call and return thunk for indirect call and jump.
+@samp{lfence} uses @code{lfence} as loop filler. @samp{pause} uses
+@code{pause} as loop filler. @samp{nop} uses @code{nop} as loop filler.
+The default is @samp{lfence}.
+
@end table
These @samp{-m} switches are supported in addition to the above
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c
new file mode 100644
index 00000000000..1b0e2c58775
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=pause -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+ dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tpause} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c
new file mode 100644
index 00000000000..feace47a765
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=nop -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch[256];
+
+void
+male_indirect_jump (long offset)
+{
+ dispatch[offset](offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tnop} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c
new file mode 100644
index 00000000000..ad2165fa7aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=lfence -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+ dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tlfence} } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c
new file mode 100644
index 00000000000..4ba997da966
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-loop=pause -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+ dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler {\tpause} } } */
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c
new file mode 100644
index 00000000000..10fb2193f5e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-loop=pause -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+ dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
+/* { dg-final { scan-assembler-not {\t(lfence|pause|nop)} } } */
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */