This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] x86: Force __x86_indirect_thunk_reg for function call via GOT
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Jan Hubicka <hubicka at ucw dot cz>
- Date: Tue, 27 Feb 2018 11:39:49 -0800
- Subject: [PATCH] x86: Force __x86_indirect_thunk_reg for function call via GOT
- Authentication-results: sourceware.org; auth=none
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
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