nocf_check attribute can be used with -fcf-protection -mcet to disable control-flow check by adding NOTRACK prefix before indirect branch. When -mindirect-branch=thunk-extern -mindirect-branch-register is added, indirect branch via register, "notrack call/jmp reg", is converted to
call/jmp __x86_indirect_thunk_nt_reg When running on machines with CET enabled, __x86_indirect_thunk_nt_reg can be updated to notrack jmp reg at run-time to restore NOTRACK prefix in the original indirect branch. Since we don't support -mindirect-branch=thunk-extern, CET and MPX at the same time, -mindirect-branch=thunk-extern is disallowed with -fcf-protection=branch and -fcheck-pointer-bounds. Tested on i686 and x86-64. OK for trunk? Thanks. H.J. --- gcc/ PR target/84176 * config/i386/i386.c (ix86_set_indirect_branch_type): Issue an error when -mindirect-branch=thunk-extern, -fcf-protection=branch and -fcheck-pointer-bounds are used together. (indirect_thunk_prefix): New enum. (indirect_thunk_need_prefix): New function. (indirect_thunk_name): Replace need_bnd_p with need_prefix. Use "_nt" instead of "_bnd" for NOTRACK prefix. (output_indirect_thunk): Replace need_bnd_p with need_prefix. (output_indirect_thunk_function): Likewise. (): Likewise. (ix86_code_end): Update output_indirect_thunk_function calls. (ix86_output_indirect_branch_via_reg): Replace ix86_bnd_prefixed_insn_p with indirect_thunk_need_prefix. (ix86_output_indirect_branch_via_push): Likewise. (ix86_output_function_return): Likewise. * doc/invoke.texi: Document -mindirect-branch=thunk-extern is incompatible with -fcf-protection=branch and -fcheck-pointer-bounds. gcc/testsuite/ PR target/84176 * gcc.target/i386/indirect-thunk-11.c: New test. * gcc.target/i386/indirect-thunk-12.c: Likewise. * gcc.target/i386/indirect-thunk-attr-12.c: Likewise. * gcc.target/i386/indirect-thunk-attr-13.c: Likewise. * gcc.target/i386/indirect-thunk-attr-14.c: Likewise. * gcc.target/i386/indirect-thunk-attr-15.c: Likewise. * gcc.target/i386/indirect-thunk-attr-16.c: Likewise. * gcc.target/i386/indirect-thunk-extern-10.c: Likewise. * gcc.target/i386/indirect-thunk-extern-8.c: Likewise. * gcc.target/i386/indirect-thunk-extern-9.c: Likewise. --- gcc/config/i386/i386.c | 151 +++++++++++++++------ gcc/doc/invoke.texi | 5 + gcc/testsuite/gcc.target/i386/indirect-thunk-11.c | 7 + gcc/testsuite/gcc.target/i386/indirect-thunk-12.c | 7 + .../gcc.target/i386/indirect-thunk-attr-12.c | 8 ++ .../gcc.target/i386/indirect-thunk-attr-13.c | 8 ++ .../gcc.target/i386/indirect-thunk-attr-14.c | 14 ++ .../gcc.target/i386/indirect-thunk-attr-15.c | 14 ++ .../gcc.target/i386/indirect-thunk-attr-16.c | 13 ++ .../gcc.target/i386/indirect-thunk-extern-10.c | 12 ++ .../gcc.target/i386/indirect-thunk-extern-8.c | 13 ++ .../gcc.target/i386/indirect-thunk-extern-9.c | 13 ++ 12 files changed, 222 insertions(+), 43 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-11.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-12.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-12.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-13.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-14.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-15.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-16.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-10.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-8.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-9.c diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index b07f581cd65..4abf3d5a2e3 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -5886,6 +5886,16 @@ ix86_set_indirect_branch_type (tree fndecl) ((cfun->machine->indirect_branch_type == indirect_branch_thunk_extern) ? "thunk-extern" : "thunk")); + + /* -mindirect-branch=thunk-extern, -fcf-protection=branch and + -fcheck-pointer-bounds are not compatible. */ + if ((cfun->machine->indirect_branch_type + == indirect_branch_thunk_extern) + && flag_check_pointer_bounds + && (flag_cf_protection & CF_BRANCH) != 0) + error ("%<-mindirect-branch=thunk-extern%>, " + "%<-fcf-protection=branch%> and " + "%<-fcheck-pointer-bounds%> are not compatible"); } if (cfun->machine->function_return_type == indirect_branch_unset) @@ -10794,18 +10804,62 @@ static int indirect_thunks_bnd_used; # define INDIRECT_LABEL "LIND" #endif +/* Indicate what prefix is needed for an indirect branch. */ +enum indirect_thunk_prefix +{ + indirect_thunk_prefix_none, + indirect_thunk_prefix_bnd, + indirect_thunk_prefix_nt +}; + +/* Return the prefix needed for an indirect branch INSN. */ + +enum indirect_thunk_prefix +indirect_thunk_need_prefix (rtx_insn *insn) +{ + enum indirect_thunk_prefix need_prefix; + if (ix86_bnd_prefixed_insn_p (insn)) + need_prefix = indirect_thunk_prefix_bnd; + else if ((cfun->machine->indirect_branch_type + == indirect_branch_thunk_extern) + && ix86_notrack_prefixed_insn_p (insn)) + { + /* NOTRACK prefix is only used with external thunk so that it + can be properly updated to support CET at run-time. */ + need_prefix = indirect_thunk_prefix_nt; + } + else + need_prefix = indirect_thunk_prefix_none; + return need_prefix; +} + /* Fills in the label name that should be used for the indirect thunk. */ static void indirect_thunk_name (char name[32], unsigned int regno, - bool need_bnd_p, bool ret_p) + enum indirect_thunk_prefix need_prefix, + bool ret_p) { if (regno != INVALID_REGNUM && ret_p) gcc_unreachable (); if (USE_HIDDEN_LINKONCE) { - const char *bnd = need_bnd_p ? "_bnd" : ""; + const char *prefix; + + if (need_prefix == indirect_thunk_prefix_bnd) + prefix = "_bnd"; + else if (need_prefix == indirect_thunk_prefix_nt + && regno != INVALID_REGNUM) + { + /* NOTRACK prefix is only used with external thunk via + register so that NOTRACK prefix can be added to indirect + branch via register to support CET at run-time. */ + prefix = "_nt"; + } + else + prefix = ""; + if (regno != INVALID_REGNUM) { const char *reg_prefix; @@ -10814,19 +10868,19 @@ indirect_thunk_name (char name[32], unsigned int regno, else reg_prefix = ""; sprintf (name, "__x86_indirect_thunk%s_%s%s", - bnd, reg_prefix, reg_names[regno]); + prefix, reg_prefix, reg_names[regno]); } else { const char *ret = ret_p ? "return" : "indirect"; - sprintf (name, "__x86_%s_thunk%s", ret, bnd); + sprintf (name, "__x86_%s_thunk%s", ret, prefix); } } else { if (regno != INVALID_REGNUM) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) ASM_GENERATE_INTERNAL_LABEL (name, "LITBR", regno); else ASM_GENERATE_INTERNAL_LABEL (name, "LITR", regno); @@ -10835,14 +10889,14 @@ indirect_thunk_name (char name[32], unsigned int regno, { if (ret_p) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) ASM_GENERATE_INTERNAL_LABEL (name, "LRTB", 0); else ASM_GENERATE_INTERNAL_LABEL (name, "LRT", 0); } else { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0); else ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0); @@ -10878,7 +10932,8 @@ indirect_thunk_name (char name[32], unsigned int regno, */ static void -output_indirect_thunk (bool need_bnd_p, unsigned int regno) +output_indirect_thunk (enum indirect_thunk_prefix need_prefix, + unsigned int regno) { char indirectlabel1[32]; char indirectlabel2[32]; @@ -10889,7 +10944,7 @@ output_indirect_thunk (bool need_bnd_p, unsigned int regno) indirectlabelno++); /* Call */ - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fputs ("\tbnd call\t", asm_out_file); else fputs ("\tcall\t", asm_out_file); @@ -10926,7 +10981,7 @@ output_indirect_thunk (bool need_bnd_p, unsigned int regno) output_asm_insn ("lea\t{%E1, %0|%0, %E1}", xops); } - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fputs ("\tbnd ret\n", asm_out_file); else fputs ("\tret\n", asm_out_file); @@ -10938,13 +10993,14 @@ output_indirect_thunk (bool need_bnd_p, unsigned int regno) on the top of stack. */ static void -output_indirect_thunk_function (bool need_bnd_p, unsigned int regno) +output_indirect_thunk_function (enum indirect_thunk_prefix need_prefix, + unsigned int regno) { char name[32]; tree decl; /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */ - indirect_thunk_name (name, regno, need_bnd_p, false); + indirect_thunk_name (name, regno, need_prefix, false); decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier (name), build_function_type_list (void_type_node, NULL_TREE)); @@ -10992,7 +11048,7 @@ output_indirect_thunk_function (bool need_bnd_p, unsigned int regno) /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */ char alias[32]; - indirect_thunk_name (alias, regno, need_bnd_p, true); + indirect_thunk_name (alias, regno, need_prefix, true); #if TARGET_MACHO if (TARGET_MACHO) { @@ -11028,7 +11084,7 @@ output_indirect_thunk_function (bool need_bnd_p, unsigned int regno) /* Make sure unwind info is emitted for the thunk if needed. */ final_start_function (emit_barrier (), asm_out_file, 1); - output_indirect_thunk (need_bnd_p, regno); + output_indirect_thunk (need_prefix, regno); final_end_function (); init_insn_lengths (); @@ -11064,18 +11120,22 @@ ix86_code_end (void) unsigned int regno; if (indirect_thunk_needed) - output_indirect_thunk_function (false, INVALID_REGNUM); + output_indirect_thunk_function (indirect_thunk_prefix_none, + INVALID_REGNUM); if (indirect_thunk_bnd_needed) - output_indirect_thunk_function (true, INVALID_REGNUM); + output_indirect_thunk_function (indirect_thunk_prefix_bnd, + INVALID_REGNUM); for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++) { unsigned int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1; if ((indirect_thunks_used & (1 << i))) - output_indirect_thunk_function (false, regno); + output_indirect_thunk_function (indirect_thunk_prefix_none, + regno); if ((indirect_thunks_bnd_used & (1 << i))) - output_indirect_thunk_function (true, regno); + output_indirect_thunk_function (indirect_thunk_prefix_bnd, + regno); } for (regno = FIRST_INT_REG; regno <= LAST_INT_REG; regno++) @@ -11084,10 +11144,12 @@ ix86_code_end (void) tree decl; if ((indirect_thunks_used & (1 << regno))) - output_indirect_thunk_function (false, regno); + output_indirect_thunk_function (indirect_thunk_prefix_none, + regno); if ((indirect_thunks_bnd_used & (1 << regno))) - output_indirect_thunk_function (true, regno); + output_indirect_thunk_function (indirect_thunk_prefix_bnd, + regno); if (!(pic_labels_used & (1 << regno))) continue; @@ -28664,7 +28726,8 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) { char thunk_name_buf[32]; char *thunk_name; - bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn); + enum indirect_thunk_prefix need_prefix + = indirect_thunk_need_prefix (current_output_insn); int regno = REGNO (call_op); if (cfun->machine->indirect_branch_type @@ -28675,12 +28738,12 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) int i = regno; if (i >= FIRST_REX_INT_REG) i -= (FIRST_REX_INT_REG - LAST_INT_REG - 1); - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) indirect_thunks_bnd_used |= 1 << i; else indirect_thunks_used |= 1 << i; } - indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false); + indirect_thunk_name (thunk_name_buf, regno, need_prefix, false); thunk_name = thunk_name_buf; } else @@ -28690,19 +28753,19 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) { if (thunk_name != NULL) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); else fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); } else - output_indirect_thunk (need_bnd_p, regno); + output_indirect_thunk (need_prefix, regno); } else { if (thunk_name != NULL) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fprintf (asm_out_file, "\tbnd call\t%s\n", thunk_name); else fprintf (asm_out_file, "\tcall\t%s\n", thunk_name); @@ -28720,7 +28783,7 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) indirectlabelno++); /* Jump. */ - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fputs ("\tbnd jmp\t", asm_out_file); else fputs ("\tjmp\t", asm_out_file); @@ -28731,18 +28794,18 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) if (thunk_name != NULL) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); else fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); } else - output_indirect_thunk (need_bnd_p, regno); + output_indirect_thunk (need_prefix, regno); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); /* Call. */ - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fputs ("\tbnd call\t", asm_out_file); else fputs ("\tcall\t", asm_out_file); @@ -28776,7 +28839,8 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm, char thunk_name_buf[32]; char *thunk_name; char push_buf[64]; - bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn); + enum indirect_thunk_prefix need_prefix + = indirect_thunk_need_prefix (current_output_insn); int regno = -1; if (cfun->machine->indirect_branch_type @@ -28784,12 +28848,12 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm, { if (cfun->machine->indirect_branch_type == indirect_branch_thunk) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) indirect_thunk_bnd_needed = true; else indirect_thunk_needed = true; } - indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false); + indirect_thunk_name (thunk_name_buf, regno, need_prefix, false); thunk_name = thunk_name_buf; } else @@ -28803,13 +28867,13 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm, output_asm_insn (push_buf, &call_op); if (thunk_name != NULL) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); else fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); } else - output_indirect_thunk (need_bnd_p, regno); + output_indirect_thunk (need_prefix, regno); } else { @@ -28824,7 +28888,7 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm, indirectlabelno++); /* Jump. */ - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fputs ("\tbnd jmp\t", asm_out_file); else fputs ("\tjmp\t", asm_out_file); @@ -28870,18 +28934,18 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm, if (thunk_name != NULL) { - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); else fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); } else - output_indirect_thunk (need_bnd_p, regno); + output_indirect_thunk (need_prefix, regno); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); /* Call. */ - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) fputs ("\tbnd call\t", asm_out_file); else fputs ("\tcall\t", asm_out_file); @@ -28933,16 +28997,17 @@ ix86_output_function_return (bool long_p) if (cfun->machine->function_return_type != indirect_branch_keep) { char thunk_name[32]; - bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn); + enum indirect_thunk_prefix need_prefix + = indirect_thunk_need_prefix (current_output_insn); if (cfun->machine->function_return_type != indirect_branch_thunk_inline) { bool need_thunk = (cfun->machine->function_return_type == indirect_branch_thunk); - indirect_thunk_name (thunk_name, INVALID_REGNUM, need_bnd_p, + indirect_thunk_name (thunk_name, INVALID_REGNUM, need_prefix, true); - if (need_bnd_p) + if (need_prefix == indirect_thunk_prefix_bnd) { indirect_thunk_bnd_needed |= need_thunk; fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name); @@ -28954,7 +29019,7 @@ ix86_output_function_return (bool long_p) } } else - output_indirect_thunk (need_bnd_p, INVALID_REGNUM); + output_indirect_thunk (need_prefix, INVALID_REGNUM); return ""; } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index f3d93367640..9e21b8b4bf3 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -26929,6 +26929,11 @@ Note that @option{-mcmodel=large} is incompatible with @option{-mindirect-branch=thunk-extern} since the thunk function may not be reachable in large code model. +Note that @option{-mindirect-branch=thunk-extern} is incompatible with +@option{-fcf-protection=branch} and @option{-fcheck-pointer-bounds} +since the external thunk can not be modified to disable control-flow +check. + @item -mfunction-return=@var{choice} @opindex -mfunction-return Convert function return with @var{choice}. The default is @samp{keep}, diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-11.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-11.c new file mode 100644 index 00000000000..afa89ff227b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-11.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { ! x32 } } } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fcf-protection -mcet -fcheck-pointer-bounds -mmpx" } */ + +void +bar (void) +{ /* { dg-error "'-mindirect-branch=thunk-extern', '-fcf-protection=branch' and '-fcheck-pointer-bounds' are not compatible" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-12.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-12.c new file mode 100644 index 00000000000..d456973ee6d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-12.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { ! x32 } } } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fcf-protection -mcet -fcheck-pointer-bounds -mmpx" } */ + +void +bar (void) +{ +} diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-12.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-12.c new file mode 100644 index 00000000000..24a1a08a3ca --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-12.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { ! x32 } } } */ +/* { dg-options "-O2 -mindirect-branch=keep -fcf-protection -mcet -fcheck-pointer-bounds -mmpx" } */ + +__attribute__ ((indirect_branch("thunk-extern"))) +void +bar (void) +{ /* { dg-error "'-mindirect-branch=thunk-extern', '-fcf-protection=branch' and '-fcheck-pointer-bounds' are not compatible" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-13.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-13.c new file mode 100644 index 00000000000..ff2fccae935 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-13.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { ! x32 } } } */ +/* { dg-options "-O2 -mindirect-branch=keep -fcf-protection -mcet -fcheck-pointer-bounds -mmpx" } */ + +__attribute__ ((indirect_branch("thunk-inline"))) +void +bar (void) +{ +} diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-14.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-14.c new file mode 100644 index 00000000000..669e56d7726 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-14.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fplt -mindirect-branch=keep -fcf-protection -mcet" } */ + +extern void (*bar) (void); + +__attribute__ ((indirect_branch("thunk-extern"))) +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk_nt" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-15.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-15.c new file mode 100644 index 00000000000..c033fb23879 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-15.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mindirect-branch-register -mfunction-return=keep -fno-pic -fplt -mindirect-branch=keep -fcf-protection -mcet" } */ + +extern void (*bar) (void); + +__attribute__ ((indirect_branch("thunk-extern"))) +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk_nt" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-16.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-16.c new file mode 100644 index 00000000000..0244edf53b7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-16.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mindirect-branch-register -mfunction-return=keep -fno-pic -fplt -mindirect-branch=keep -fcf-protection -mcet" } */ + +extern void (*bar) (void) __attribute__((nocf_check)); + +__attribute__ ((indirect_branch("thunk-extern"))) +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_nt_(r|e)" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-10.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-10.c new file mode 100644 index 00000000000..2a982ab69f8 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-10.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mindirect-branch-register -mfunction-return=keep -fno-pic -fplt -mindirect-branch=thunk-extern -fcf-protection -mcet" } */ + +extern void (*bar) (void) __attribute__((nocf_check)); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_nt_(r|e)" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-8.c new file mode 100644 index 00000000000..30d12cc0711 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-8.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fplt -mindirect-branch=thunk-extern -fcf-protection -mcet" } */ + +extern void (*bar) (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk_nt" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-9.c new file mode 100644 index 00000000000..d714b0155df --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-9.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mindirect-branch-register -mfunction-return=keep -fno-pic -fplt -mindirect-branch=thunk-extern -fcf-protection -mcet" } */ + +extern void (*bar) (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk_nt" } } */ -- 2.14.3