From fdddac6289f5bb64a6180b40572cc084f5452aa8 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sat, 6 Jan 2018 22:29:55 -0800 Subject: 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. --- gcc/config/i386/i386-opts.h | 6 ++++++ gcc/config/i386/i386.c | 19 +++++++++++++++++-- gcc/config/i386/i386.opt | 17 +++++++++++++++++ gcc/doc/invoke.texi | 9 ++++++++- gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c | 19 +++++++++++++++++++ gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c | 19 +++++++++++++++++++ gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c | 19 +++++++++++++++++++ gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c | 19 +++++++++++++++++++ gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c | 19 +++++++++++++++++++ 9 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c 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" } } */ -- cgit v1.2.1