For x86 targets, when -fno-plt is used, external functions are called via GOT slot, in 64-bit mode:
[bnd] call/jmp *foo@GOTPCREL(%rip) and in 32-bit mode: [bnd] call/jmp *foo@GOT[(%reg)] With -mindirect-branch=, they are converted to, in 64-bit mode: pushq foo@GOTPCREL(%rip) [bnd] jmp __x86_indirect_thunk[_bnd] and in 32-bit mode: pushl foo@GOT[(%reg)] [bnd] jmp __x86_indirect_thunk[_bnd] which were incompatible with CFI. In 64-bit mode, since R11 is a scratch register, we generate: movq foo@GOTPCREL(%rip), %r11 [bnd] call/jmp __x86_indirect_thunk_[bnd_]r11 instead. We do it in ix86_output_indirect_branch so that we can use the newly proposed R_X86_64_THUNK_GOTPCRELX relocation: https://groups.google.com/forum/#!topic/x86-64-abi/eED5lzn3_Mg movq foo@OTPCREL_THUNK(%rip), %r11 [bnd] call/jmp __x86_indirect_thunk_[bnd_]r11 to load GOT slot into R11. If foo is defined locally, linker can can convert movq foo@GOTPCREL_THUNK(%rip), %reg call/jmp __x86_indirect_thunk_reg to call/jmp foo nop 0L(%rax) In 32-bit mode, since all caller-saved registers, EAX, EDX and ECX, may used to function parameters, there is no scratch register available. For -fno-plt -fno-pic -mindirect-branch=, we expand external function call to: movl foo@GOT, %reg [bnd] call/jmp *%reg so that it can be converted to movl foo@GOT, %reg [bnd] call/jmp __x86_indirect_thunk_[bnd_]reg in ix86_output_indirect_branch. Since this is performed during RTL expansion, other instructions may be inserted between movl and call/jmp. Linker optimization isn't always possible. Tested on i686 and x86-64. OK for trunk? H.J. --- gcc/ PR target/83970 * config/i386/constraints.md (Bs): Allow GOT_memory_operand for TARGET_LP64 with indirect branch conversion. (Bw): Likewise. * config/i386/i386.c (ix86_expand_call): Handle -fno-plt with -mindirect-branch=. (ix86_nopic_noplt_attribute_p): Likewise. (ix86_output_indirect_branch): In 64-bit mode, convert function call via GOT with R11 as a scratch register using __x86_indirect_thunk_r11. (ix86_output_call_insn): In 64-bit mode, set xasm to NULL when calling ix86_output_indirect_branch with function call via GOT. * config/i386/i386.md (*call_got_thunk): New call pattern for TARGET_LP64 with indirect branch conversion. (*call_value_got_thunk): Likewise. gcc/testsuite/ PR target/83970 * gcc.target/i386/indirect-thunk-5.c: Updated. * gcc.target/i386/indirect-thunk-6.c: Likewise. * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise. * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise. * gcc.target/i386/indirect-thunk-extern-5.c: Likewise. * gcc.target/i386/indirect-thunk-extern-6.c: Likewise. * gcc.target/i386/indirect-thunk-inline-5.c: Likewise. * gcc.target/i386/indirect-thunk-inline-6.c: Likewise. * gcc.target/i386/indirect-thunk-13.c: New test. * gcc.target/i386/indirect-thunk-14.c: Likewise. * gcc.target/i386/indirect-thunk-bnd-5.c: Likewise. * gcc.target/i386/indirect-thunk-bnd-6.c: Likewise. * gcc.target/i386/indirect-thunk-extern-11.c: Likewise. * gcc.target/i386/indirect-thunk-extern-12.c: Likewise. * gcc.target/i386/indirect-thunk-inline-8.c: Likewise. * gcc.target/i386/indirect-thunk-inline-9.c: Likewise. --- gcc/config/i386/constraints.md | 14 +++- gcc/config/i386/i386.c | 90 +++++++++++++++++++--- gcc/config/i386/i386.md | 36 +++++++++ gcc/testsuite/gcc.target/i386/indirect-thunk-13.c | 19 +++++ gcc/testsuite/gcc.target/i386/indirect-thunk-14.c | 20 +++++ gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 6 +- gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 12 +-- .../gcc.target/i386/indirect-thunk-bnd-3.c | 2 +- .../gcc.target/i386/indirect-thunk-bnd-4.c | 2 +- .../gcc.target/i386/indirect-thunk-bnd-5.c | 21 +++++ .../gcc.target/i386/indirect-thunk-bnd-6.c | 22 ++++++ .../gcc.target/i386/indirect-thunk-extern-11.c | 18 +++++ .../gcc.target/i386/indirect-thunk-extern-12.c | 19 +++++ .../gcc.target/i386/indirect-thunk-extern-5.c | 6 +- .../gcc.target/i386/indirect-thunk-extern-6.c | 8 +- .../gcc.target/i386/indirect-thunk-inline-5.c | 3 +- .../gcc.target/i386/indirect-thunk-inline-6.c | 3 +- .../gcc.target/i386/indirect-thunk-inline-8.c | 18 +++++ .../gcc.target/i386/indirect-thunk-inline-9.c | 19 +++++ 19 files changed, 300 insertions(+), 38 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-13.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-14.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-5.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-6.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-11.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-12.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-8.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-9.c diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index d026968c4c9..34d255aea59 100644 --- a/gcc/config/i386/constraints.md +++ b/gcc/config/i386/constraints.md @@ -228,7 +228,12 @@ (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER")) (not (match_test "TARGET_X32")) (match_operand 0 "sibcall_memory_operand")) - (and (match_test "TARGET_X32 && Pmode == DImode") + (and (ior (and (match_test "TARGET_LP64") + (match_test "cfun->machine->func_type + == TYPE_NORMAL") + (match_test "cfun->machine->indirect_branch_type + != indirect_branch_keep")) + (match_test "TARGET_X32 && Pmode == DImode")) (match_operand 0 "GOT_memory_operand")))) (define_constraint "Bw" @@ -236,7 +241,12 @@ (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER")) (not (match_test "TARGET_X32")) (match_operand 0 "memory_operand")) - (and (match_test "TARGET_X32 && Pmode == DImode") + (and (ior (and (match_test "TARGET_LP64") + (match_test "cfun->machine->func_type + == TYPE_NORMAL") + (match_test "cfun->machine->indirect_branch_type + != indirect_branch_keep")) + (match_test "TARGET_X32 && Pmode == DImode")) (match_operand 0 "GOT_memory_operand")))) (define_constraint "Bz" diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9041485bd61..a8a50f7687f 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -28526,7 +28526,14 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, pic_offset_table_rtx); } } - else if (!TARGET_PECOFF && !TARGET_MACHO) + /* In 64-bit mode, -mindirect-branch= is treated as -fno-pic + and ix86_output_indirect_branch will convert call via PLT + to indirect branch via GOT slot. */ + else if (!TARGET_PECOFF + && !TARGET_MACHO + && (!TARGET_64BIT + || (cfun->machine->indirect_branch_type + == indirect_branch_keep))) { if (TARGET_64BIT) { @@ -28553,6 +28560,30 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, fnaddr = gen_rtx_MEM (QImode, fnaddr); } } + else if (!TARGET_64BIT + && HAVE_AS_IX86_GOT32X + && !TARGET_PECOFF + && !TARGET_MACHO + && (cfun->machine->indirect_branch_type + != indirect_branch_keep) + && !flag_pic + && GET_CODE (addr) == SYMBOL_REF + && SYMBOL_REF_FUNCTION_P (addr) + && !SYMBOL_REF_LOCAL_P (addr) + && (!flag_plt + || (SYMBOL_REF_DECL (addr) != NULL_TREE + && lookup_attribute ("noplt", + DECL_ATTRIBUTES (SYMBOL_REF_DECL (addr)))))) + { + /* In 32-bit mode, with -fno-pic -mindirect-branch=, we load + function's GOT slot into a register and call the external + function via the register. */ + fnaddr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), + UNSPEC_GOT); + fnaddr = gen_rtx_CONST (Pmode, fnaddr); + fnaddr = gen_const_mem (Pmode, fnaddr); + fnaddr = gen_rtx_MEM (QImode, fnaddr); + } } /* Skip setting up RAX register for -mskip-rax-setup when there are no @@ -28699,7 +28730,7 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, static bool ix86_nopic_noplt_attribute_p (rtx call_op) { - if (flag_pic || ix86_cmodel == CM_LARGE + if (ix86_cmodel == CM_LARGE || !(TARGET_64BIT || HAVE_AS_IX86_GOT32X) || TARGET_MACHO || TARGET_SEH || TARGET_PECOFF || SYMBOL_REF_LOCAL_P (call_op)) @@ -28707,10 +28738,16 @@ ix86_nopic_noplt_attribute_p (rtx call_op) tree symbol_decl = SYMBOL_REF_DECL (call_op); + /* In 64-bit mode, -mindirect-branch= is treated as -fno-pic and + ix86_output_indirect_branch will convert call via PLT to indirect + branch via GOT slot. */ if (!flag_plt || (symbol_decl != NULL_TREE && lookup_attribute ("noplt", DECL_ATTRIBUTES (symbol_decl)))) - return true; + return (!flag_pic + || (TARGET_64BIT + && (cfun->machine->indirect_branch_type + != indirect_branch_keep))); return false; } @@ -28968,6 +29005,43 @@ static void ix86_output_indirect_branch (rtx call_op, const char *xasm, bool sibcall_p) { + /* In 64-bit mode, convert function call via GOT: + + [bnd] call/jmp *foo@GOTPCREL(%rip) + + to + + movq foo@GOTPCREL(%rip), %r11 + [bnd] call/jmp __x86_indirect_thunk_[bnd_]r11 + + with R11 as a scratch register. */ + if (TARGET_64BIT) + { + if (MEM_P (call_op) + && GET_CODE (XEXP (call_op, 0)) == CONST + && GET_CODE (XEXP (XEXP (call_op, 0), 0)) == UNSPEC + && XINT (XEXP (XEXP (call_op, 0), 0), 1) == UNSPEC_GOTPCREL) + { + rtx op = XVECEXP (XEXP (XEXP (call_op, 0), 0), 0, 0); + if (GET_CODE (op) != SYMBOL_REF) + gcc_unreachable (); + xasm = NULL; + call_op = op; + } + + if (xasm == NULL) + { + rtx xops[2]; + xops[0] = gen_rtx_REG (word_mode, R11_REG); + xops[1] = call_op; + char movq_buf[80]; + snprintf (movq_buf, sizeof (movq_buf), "movq\t%s", + "{%p1@GOTPCREL(%%rip), %0|%0, [QWORD PTR %p1@GOTPCREL[rip]]}"); + output_asm_insn (movq_buf, xops); + call_op = xops[0]; + } + } + if (REG_P (call_op)) ix86_output_indirect_branch_via_reg (call_op, sibcall_p); else @@ -29126,7 +29200,7 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) = (!TARGET_SEH && cfun->machine->indirect_branch_type != indirect_branch_keep); bool seh_nop_p = false; - const char *xasm; + const char *xasm = NULL; if (SIBLING_CALL_P (insn)) { @@ -29137,9 +29211,7 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) direct_p = false; if (TARGET_64BIT) { - if (output_indirect_p) - xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; - else + if (!output_indirect_p) xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; } else @@ -29209,9 +29281,7 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) direct_p = false; if (TARGET_64BIT) { - if (output_indirect_p) - xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; - else + if (!output_indirect_p) xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; } else diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 85e4b07cd0f..cb39a98aeb1 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -12575,6 +12575,23 @@ "* return ix86_output_call_insn (insn, operands[0]);" [(set_attr "type" "call")]) +;; This covers both call and sibcall since only GOT slot is allowed. +(define_insn "*call_got_thunk" + [(call (mem:QI (match_operand:DI 0 "GOT_memory_operand" "Bg")) + (match_operand 1))] + "TARGET_LP64 + && cfun->machine->func_type == TYPE_NORMAL + && cfun->machine->indirect_branch_type != indirect_branch_keep" +{ + rtx fnaddr = gen_const_mem (DImode, XEXP (operands[0], 0)); + return ix86_output_call_insn (insn, fnaddr); +} + [(set (attr "type") + (if_then_else (match_test "(cfun->machine->indirect_branch_type + != indirect_branch_keep)") + (const_string "multi") + (const_string "call")))]) + ;; This covers both call and sibcall since only GOT slot is allowed. (define_insn "*call_got_x32" [(call (mem:QI (zero_extend:DI @@ -12778,6 +12795,25 @@ "* return ix86_output_call_insn (insn, operands[1]);" [(set_attr "type" "callv")]) +;; This covers both call and sibcall since only GOT slot is allowed. +(define_insn "*call_value_got_thunk" + [(set (match_operand 0) + (call (mem:QI + (match_operand:DI 1 "GOT_memory_operand" "Bg")) + (match_operand 2)))] + "TARGET_LP64 + && cfun->machine->func_type == TYPE_NORMAL + && cfun->machine->indirect_branch_type != indirect_branch_keep" +{ + rtx fnaddr = gen_const_mem (DImode, XEXP (operands[1], 0)); + return ix86_output_call_insn (insn, fnaddr); +} + [(set (attr "type") + (if_then_else (match_test "(cfun->machine->indirect_branch_type + != indirect_branch_keep)") + (const_string "multi") + (const_string "callv")))]) + ;; This covers both call and sibcall since only GOT slot is allowed. (define_insn "*call_value_got_x32" [(set (match_operand 0) diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-13.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-13.c new file mode 100644 index 00000000000..ed9c43f23ce --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-13.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fno-plt -mindirect-branch=thunk" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_e" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_r" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-14.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-14.c new file mode 100644 index 00000000000..2bd547486b6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-14.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fno-plt -mindirect-branch=thunk" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_e" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_r" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c index fb26c005e80..95cbf62194d 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c @@ -9,10 +9,8 @@ foo (void) bar (); } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */ -/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "mov(l|q)\[ \t\]*bar@GOT" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)" } } */ /* { 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-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c index 8bc45ff68ce..7e8d9a48905 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c @@ -10,13 +10,9 @@ foo (void) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */ -/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 { target x32 } } } */ -/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 { target x32 } } } */ -/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ -/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)" } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */ /* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c index 42312f65588..b573040adc7 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c @@ -11,7 +11,7 @@ foo (void) } /* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" } } */ -/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd_rax" { target lp64 } } } */ +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd_r" { target lp64 } } } */ /* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_eax" { target ia32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c index 8850f2ffca4..db68eb5a157 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c @@ -12,7 +12,7 @@ foo (void) } /* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" } } */ -/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_(r|e)ax" } } */ +/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_(r|e)" } } */ /* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 1 } } */ /* { dg-final { scan-assembler "bnd ret" } } */ /* { dg-final { scan-assembler {\tpause} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-5.c new file mode 100644 index 00000000000..d0674ee4058 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-5.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic -fno-plt" } */ + +void bar (char *); +char buf[10]; + +void +foo (void) +{ + bar (buf); +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_e" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target lp64 } } } */ +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd_r" { target lp64 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "bnd ret" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-6.c new file mode 100644 index 00000000000..7d7ba2388e5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-6.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic -fno-plt" } */ + +void bar (char *); +char buf[10]; + +int +foo (void) +{ + bar (buf); + return 0; +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_e" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target lp64 } } } */ +/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_r" { target lp64 } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 1 } } */ +/* { dg-final { scan-assembler "bnd ret" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-11.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-11.c new file mode 100644 index 00000000000..ce8b21959af --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-11.c @@ -0,0 +1,18 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fno-plt -mindirect-branch=thunk-extern" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_e" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_r" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-12.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-12.c new file mode 100644 index 00000000000..8d13e2017ea --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-12.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fno-plt -mindirect-branch=thunk-extern" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_e" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_r" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c index 53282390977..fd818fe15f2 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c @@ -9,10 +9,8 @@ foo (void) bar (); } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */ -/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "mov(l|q)\[ \t\]*bar@GOT" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)" } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c index 8ae43482d0c..b9a053d2fea 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c @@ -10,8 +10,8 @@ foo (void) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */ -/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c index 21cbfd39582..cb6e7fdb986 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c @@ -9,8 +9,7 @@ foo (void) bar (); } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */ -/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "mov(l|q)\[ \t\]*bar@GOT" } } */ /* { 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-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c index d1300f18dc7..b61c855ffeb 100644 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c @@ -10,8 +10,7 @@ foo (void) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */ -/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ /* { dg-final { scan-assembler-times {\tpause} 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-8.c new file mode 100644 index 00000000000..5bc7eb7f359 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-8.c @@ -0,0 +1,18 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fno-plt -mindirect-branch=thunk-inline" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-9.c new file mode 100644 index 00000000000..4e724fe7e3b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-9.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic -fno-plt -mindirect-branch=thunk-inline" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target ia32 } } } */ +/* { dg-final { scan-assembler "movq\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ -- 2.14.3