x86: Force __x86_indirect_thunk_reg for function call via GOT

Message ID 20180227193949.GA336556@intel.com
State New
Headers show
Series
  • x86: Force __x86_indirect_thunk_reg for function call via GOT
Related show

Commit Message

H.J. Lu Feb. 27, 2018, 7:39 p.m.
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

-- 
2.14.3

Patch

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" } } */