Message ID | 20180615125949.GA114203@intel.com |
---|---|
State | New |
Headers | show |
Series | i386; Add -mmanual-endbr and cf_check function attribute | expand |
On Fri, Jun 15, 2018 at 2:59 PM H.J. Lu <hongjiu.lu@intel.com> wrote: > > Currently GCC inserts ENDBR instruction at entries of all non-static > functions, unless LTO compilation is used. Marking all functions, > which are not called indirectly with nocf_check attribute, is not > ideal since 99% of functions in a program may be of this kind. > > This patch adds -mmanual-endbr and cf_check function attribute. They > can be used together with -fcf-protection such that ENDBR instruction > is inserted only at entries of functions with cf_check attribute. It > can limit number of ENDBR instructions to reduce program size. > > OK for trubk? I wonder if the linker could assist with ENDBR creation by redirecting all non-direct call relocs to a linker-generated stub with ENBR and a direct branch? Richard. > H.J. > ----- > gcc/ > > * config/i386/i386.c (rest_of_insert_endbranch): Insert ENDBR > at the function entry only when -mmanual-endbr isn't used or > there is cf_check function attribute. > (ix86_attribute_table): Add cf_check. > * config/i386/i386.opt: Add -mmanual-endbr. > * doc/extend.texi: Document cf_check attribute. > * doc/invoke.texi: Document -mmanual-endbr. > > gcc/testsuite/ > > * gcc.target/i386/cf_check-1.c: New test. > * gcc.target/i386/cf_check-2.c: Likewise. > * gcc.target/i386/cf_check-3.c: Likewise. > * gcc.target/i386/cf_check-4.c: Likewise. > * gcc.target/i386/cf_check-5.c: Likewise. > --- > gcc/config/i386/i386.c | 5 +++++ > gcc/config/i386/i386.opt | 5 +++++ > gcc/doc/extend.texi | 7 +++++++ > gcc/doc/invoke.texi | 9 ++++++++- > gcc/testsuite/gcc.target/i386/cf_check-1.c | 11 +++++++++++ > gcc/testsuite/gcc.target/i386/cf_check-2.c | 11 +++++++++++ > gcc/testsuite/gcc.target/i386/cf_check-3.c | 11 +++++++++++ > gcc/testsuite/gcc.target/i386/cf_check-4.c | 10 ++++++++++ > gcc/testsuite/gcc.target/i386/cf_check-5.c | 9 +++++++++ > 9 files changed, 77 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-1.c > create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-2.c > create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-3.c > create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-4.c > create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-5.c > > diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c > index 95cfa05ce61..d356e0e7acd 100644 > --- a/gcc/config/i386/i386.c > +++ b/gcc/config/i386/i386.c > @@ -2604,6 +2604,9 @@ rest_of_insert_endbranch (void) > > if (!lookup_attribute ("nocf_check", > TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl))) > + && (!flag_manual_endbr > + || lookup_attribute ("cf_check", > + DECL_ATTRIBUTES (cfun->decl))) > && !cgraph_node::get (cfun->decl)->only_called_directly_p ()) > { > cet_eb = gen_nop_endbr (); > @@ -45896,6 +45899,8 @@ static const struct attribute_spec ix86_attribute_table[] = > ix86_handle_fndecl_attribute, NULL }, > { "function_return", 1, 1, true, false, false, false, > ix86_handle_fndecl_attribute, NULL }, > + { "cf_check", 0, 0, true, false, false, false, > + ix86_handle_fndecl_attribute, NULL }, > > /* End element. */ > { NULL, 0, 0, false, false, false, false, NULL, NULL } > diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt > index a34d4acf1a2..aebc023420b 100644 > --- a/gcc/config/i386/i386.opt > +++ b/gcc/config/i386/i386.opt > @@ -1016,6 +1016,11 @@ Target Report Undocumented Var(flag_cet_switch) Init(0) > Turn on CET instrumentation for switch statements that use a jump table and > an indirect jump. > > +mmanual-endbr > +Target Report Var(flag_manual_endbr) Init(0) > +Insert ENDBR instruction at function entry only via cf_check attribute > +for CET instrumentation. > + > mforce-indirect-call > Target Report Var(flag_force_indirect_call) Init(0) > Make all function calls indirect. > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index e0a84b8b3c5..5fd4a1b22b0 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -5864,6 +5864,13 @@ foo (void) > @} > @end smallexample > > +@item cf_check > +@cindex @code{cf_check} function attribute, x86 > + > +The @code{cf_check} attribute on a function is used to inform the > +compiler that ENDBR instruction should be placed at the function > +entry when @option{-fcf-protection=branch} is enabled. > + > @end table > > On the x86, the inliner does not inline a > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 940b84697fa..7ec4267b7b1 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -1250,7 +1250,7 @@ See RS/6000 and PowerPC Options. > -msse4a -m3dnow -m3dnowa -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop @gol > -mlzcnt -mbmi2 -mfxsr -mxsave -mxsaveopt -mrtm -mlwp @gol > -mmwaitx -mclzero -mpku -mthreads -mgfni -mvaes -mwaitpkg @gol > --mshstk -mforce-indirect-call -mavx512vbmi2 @gol > +-mshstk -mforce-indirect-call -mmanual-endbr -mavx512vbmi2 @gol > -mvpclmulqdq -mavx512bitalg -mmovdiri -mmovdir64b -mavx512vpopcntdq > -mcldemote @gol > -mms-bitfields -mno-align-stringops -minline-all-stringops @gol > @@ -27476,6 +27476,13 @@ Force all calls to functions to be indirect. This is useful > when using Intel Processor Trace where it generates more precise timing > information for function calls. > > +@item -mmanual-endbr > +@opindex mmanual-endbr > +Insert ENDBR instruction at function entry only via the @code{cf_check} > +function attribute. This is useful when used with the option > +@option{-fcf-protection=branch} to control ENDBR insertion at the > +function entry. > + > @item -mcall-ms2sysv-xlogues > @opindex mcall-ms2sysv-xlogues > @opindex mno-call-ms2sysv-xlogues > diff --git a/gcc/testsuite/gcc.target/i386/cf_check-1.c b/gcc/testsuite/gcc.target/i386/cf_check-1.c > new file mode 100644 > index 00000000000..c433eab854a > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/cf_check-1.c > @@ -0,0 +1,11 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fcf-protection -mmanual-endbr" } */ > +/* { dg-final { scan-assembler-not {\mendbr} } } */ > + > +extern void bar (void) __attribute__((__cf_check__)); > + > +void > +foo (void) > +{ > + bar (); > +} > diff --git a/gcc/testsuite/gcc.target/i386/cf_check-2.c b/gcc/testsuite/gcc.target/i386/cf_check-2.c > new file mode 100644 > index 00000000000..e2b9c4dbcb2 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/cf_check-2.c > @@ -0,0 +1,11 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fcf-protection -mno-manual-endbr" } */ > +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */ > + > +extern void bar (void) __attribute__((__cf_check__)); > + > +void > +foo (void) > +{ > + bar (); > +} > diff --git a/gcc/testsuite/gcc.target/i386/cf_check-3.c b/gcc/testsuite/gcc.target/i386/cf_check-3.c > new file mode 100644 > index 00000000000..d835cc3a21b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/cf_check-3.c > @@ -0,0 +1,11 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fcf-protection=none" } */ > +/* { dg-final { scan-assembler-not {\mendbr} } } */ > + > +extern void bar (void) __attribute__((__cf_check__)); > + > +void > +foo (void) > +{ > + bar (); > +} > diff --git a/gcc/testsuite/gcc.target/i386/cf_check-4.c b/gcc/testsuite/gcc.target/i386/cf_check-4.c > new file mode 100644 > index 00000000000..d6cb27cf20b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/cf_check-4.c > @@ -0,0 +1,10 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fcf-protection -mmanual-endbr" } */ > +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */ > + > +extern void foo (void) __attribute__((__cf_check__)); > + > +void > +foo (void) > +{ > +} > diff --git a/gcc/testsuite/gcc.target/i386/cf_check-5.c b/gcc/testsuite/gcc.target/i386/cf_check-5.c > new file mode 100644 > index 00000000000..f2c0c5c2c09 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/cf_check-5.c > @@ -0,0 +1,9 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fcf-protection -mmanual-endbr" } */ > +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */ > + > +__attribute__((__cf_check__)) > +void > +foo (void) > +{ > +} > -- > 2.17.1 >
On Mon, Jun 18, 2018 at 2:20 AM Richard Biener <richard.guenther@gmail.com> wrote: > > On Fri, Jun 15, 2018 at 2:59 PM H.J. Lu <hongjiu.lu@intel.com> wrote: > > > > Currently GCC inserts ENDBR instruction at entries of all non-static > > functions, unless LTO compilation is used. Marking all functions, > > which are not called indirectly with nocf_check attribute, is not > > ideal since 99% of functions in a program may be of this kind. > > > > This patch adds -mmanual-endbr and cf_check function attribute. They > > can be used together with -fcf-protection such that ENDBR instruction > > is inserted only at entries of functions with cf_check attribute. It > > can limit number of ENDBR instructions to reduce program size. > > > > OK for trubk? > > I wonder if the linker could assist with ENDBR creation by > redirecting all non-direct call relocs to a linker-generated > stub with ENBR and a direct branch? > The goal of this patch is to add as few as ENDBR as possible to reduce program size as much as possible. Also there is no relocation for indirect branch via register.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 95cfa05ce61..d356e0e7acd 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -2604,6 +2604,9 @@ rest_of_insert_endbranch (void) if (!lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl))) + && (!flag_manual_endbr + || lookup_attribute ("cf_check", + DECL_ATTRIBUTES (cfun->decl))) && !cgraph_node::get (cfun->decl)->only_called_directly_p ()) { cet_eb = gen_nop_endbr (); @@ -45896,6 +45899,8 @@ static const struct attribute_spec ix86_attribute_table[] = ix86_handle_fndecl_attribute, NULL }, { "function_return", 1, 1, true, false, false, false, ix86_handle_fndecl_attribute, NULL }, + { "cf_check", 0, 0, true, false, false, false, + ix86_handle_fndecl_attribute, NULL }, /* End element. */ { NULL, 0, 0, false, false, false, false, NULL, NULL } diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index a34d4acf1a2..aebc023420b 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -1016,6 +1016,11 @@ Target Report Undocumented Var(flag_cet_switch) Init(0) Turn on CET instrumentation for switch statements that use a jump table and an indirect jump. +mmanual-endbr +Target Report Var(flag_manual_endbr) Init(0) +Insert ENDBR instruction at function entry only via cf_check attribute +for CET instrumentation. + mforce-indirect-call Target Report Var(flag_force_indirect_call) Init(0) Make all function calls indirect. diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index e0a84b8b3c5..5fd4a1b22b0 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5864,6 +5864,13 @@ foo (void) @} @end smallexample +@item cf_check +@cindex @code{cf_check} function attribute, x86 + +The @code{cf_check} attribute on a function is used to inform the +compiler that ENDBR instruction should be placed at the function +entry when @option{-fcf-protection=branch} is enabled. + @end table On the x86, the inliner does not inline a diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 940b84697fa..7ec4267b7b1 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1250,7 +1250,7 @@ See RS/6000 and PowerPC Options. -msse4a -m3dnow -m3dnowa -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop @gol -mlzcnt -mbmi2 -mfxsr -mxsave -mxsaveopt -mrtm -mlwp @gol -mmwaitx -mclzero -mpku -mthreads -mgfni -mvaes -mwaitpkg @gol --mshstk -mforce-indirect-call -mavx512vbmi2 @gol +-mshstk -mforce-indirect-call -mmanual-endbr -mavx512vbmi2 @gol -mvpclmulqdq -mavx512bitalg -mmovdiri -mmovdir64b -mavx512vpopcntdq -mcldemote @gol -mms-bitfields -mno-align-stringops -minline-all-stringops @gol @@ -27476,6 +27476,13 @@ Force all calls to functions to be indirect. This is useful when using Intel Processor Trace where it generates more precise timing information for function calls. +@item -mmanual-endbr +@opindex mmanual-endbr +Insert ENDBR instruction at function entry only via the @code{cf_check} +function attribute. This is useful when used with the option +@option{-fcf-protection=branch} to control ENDBR insertion at the +function entry. + @item -mcall-ms2sysv-xlogues @opindex mcall-ms2sysv-xlogues @opindex mno-call-ms2sysv-xlogues diff --git a/gcc/testsuite/gcc.target/i386/cf_check-1.c b/gcc/testsuite/gcc.target/i386/cf_check-1.c new file mode 100644 index 00000000000..c433eab854a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cf_check-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection -mmanual-endbr" } */ +/* { dg-final { scan-assembler-not {\mendbr} } } */ + +extern void bar (void) __attribute__((__cf_check__)); + +void +foo (void) +{ + bar (); +} diff --git a/gcc/testsuite/gcc.target/i386/cf_check-2.c b/gcc/testsuite/gcc.target/i386/cf_check-2.c new file mode 100644 index 00000000000..e2b9c4dbcb2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cf_check-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection -mno-manual-endbr" } */ +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */ + +extern void bar (void) __attribute__((__cf_check__)); + +void +foo (void) +{ + bar (); +} diff --git a/gcc/testsuite/gcc.target/i386/cf_check-3.c b/gcc/testsuite/gcc.target/i386/cf_check-3.c new file mode 100644 index 00000000000..d835cc3a21b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cf_check-3.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection=none" } */ +/* { dg-final { scan-assembler-not {\mendbr} } } */ + +extern void bar (void) __attribute__((__cf_check__)); + +void +foo (void) +{ + bar (); +} diff --git a/gcc/testsuite/gcc.target/i386/cf_check-4.c b/gcc/testsuite/gcc.target/i386/cf_check-4.c new file mode 100644 index 00000000000..d6cb27cf20b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cf_check-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection -mmanual-endbr" } */ +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */ + +extern void foo (void) __attribute__((__cf_check__)); + +void +foo (void) +{ +} diff --git a/gcc/testsuite/gcc.target/i386/cf_check-5.c b/gcc/testsuite/gcc.target/i386/cf_check-5.c new file mode 100644 index 00000000000..f2c0c5c2c09 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cf_check-5.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fcf-protection -mmanual-endbr" } */ +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */ + +__attribute__((__cf_check__)) +void +foo (void) +{ +}