This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Extend -fno-plt to normal non-PIC branches on x86


On Thu, May 28, 2015 at 10:37:53AM -0700, H.J. Lu wrote:
> This patch extends -fno-plt to normal non-PIC calls on x86.  -fno-plt
> works in 64-bit mode with the existing binutils.  For 32-bit, we need
> the updated assembler and linker to support "call/jmp *foo@GOT" with
> a new relocation different from R_386_GOT32 to indicate that this
> relocation applies to indirect branches.  A configure time check is
> added to verify that 32-bit assembler generates a known relocation
> which is different from R_386_GOT32.  A new 32-bit relocaton is needed
> since "call/jmp *foo@GOT" requires a different relocation from R_386_GOT32
> which is used together with a GOT register in "call/jmp *foo@GOT(%reg)".
> 
> OK for master?
> 
> Thanks.
> 
> H.J.
> ---
> 	* configure.ac (HAVE_AS_INDIRECT_BRANCH_VIA_GOT): New.  Defined
> 	if 32-bit assembler generates a known relocation which is
> 	different from R_386_GOT32.
> 	* config.in: Regenerated.
> 	* configure: Likewise.
> 	* config/i386/i386.c (ix86_output_call_insn):  Extend -fno-plt
> 	to normal non-PIC branches.


Here is the updated patch to properly handle local functions with
testcases.


H.J.
---
gcc/

	* configure.ac (HAVE_AS_INDIRECT_BRANCH_VIA_GOT): New.  Defined
	if 32-bit assembler generates a known relocation which is
	different from R_386_GOT32.
	* config.in: Regenerated.
	* configure: Likewise.
	* config/i386/i386.c (ix86_output_call_insn):  Extend -fno-plt
	to normal non-PIC branches.
	* config/i386/i386.h (TARGET_ELF): New.

gcc/testsuite/

	* gcc.target/i386/pr66232-6.c: New tests.
	* gcc.target/i386/pr66232-7.c: Likewise.
	* gcc.target/i386/pr66232-8.c: Likewise.
	* gcc.target/i386/pr66232-9.c: Likewise.
	* gcc.target/i386/pr66232-10.c: Likewise.
	* gcc.target/i386/pr66232-11.c: Likewise.
	* gcc.target/i386/pr66232-12.c: Likewise.
	* gcc.target/i386/pr66232-13.c: Likewise.
	* lib/target-supports.exp (check_effective_target_branch_via_got):
	New.
---
 gcc/config.in                              | 14 +++++---
 gcc/config/i386/i386.c                     | 40 +++++++++++++++++++++--
 gcc/config/i386/i386.h                     |  2 ++
 gcc/configure                              | 47 ++++++++++++++++++++++++++-
 gcc/configure.ac                           | 18 ++++++++++-
 gcc/testsuite/gcc.target/i386/pr66232-10.c | 13 ++++++++
 gcc/testsuite/gcc.target/i386/pr66232-11.c | 14 ++++++++
 gcc/testsuite/gcc.target/i386/pr66232-12.c | 13 ++++++++
 gcc/testsuite/gcc.target/i386/pr66232-13.c | 13 ++++++++
 gcc/testsuite/gcc.target/i386/pr66232-6.c  | 13 ++++++++
 gcc/testsuite/gcc.target/i386/pr66232-7.c  | 14 ++++++++
 gcc/testsuite/gcc.target/i386/pr66232-8.c  | 13 ++++++++
 gcc/testsuite/gcc.target/i386/pr66232-9.c  | 13 ++++++++
 gcc/testsuite/lib/target-supports.exp      | 52 ++++++++++++++++++++++++++++++
 14 files changed, 271 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-10.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-11.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-12.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-13.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-9.c

diff --git a/gcc/config.in b/gcc/config.in
index daaf906..0ee5c38 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -363,6 +363,12 @@
 #endif
 
 
+/* Define true if the assembler supports 'call *foo@GOT'. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_INDIRECT_BRANCH_VIA_GOT
+#endif
+
+
 /* Define if your assembler supports the Sun syntax for cmov. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_IX86_CMOV_SUN_SYNTAX
@@ -686,8 +692,8 @@
 #endif
 
 
-/* Define to 1 if we found a declaration for 'basename', otherwise define to
-   0. */
+/* Define to 1 if you have the declaration of `basename(const char*)', and to
+   0 if you don't. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_DECL_BASENAME
 #endif
@@ -963,8 +969,8 @@
 #endif
 
 
-/* Define to 1 if we found a declaration for 'strstr', otherwise define to 0.
-   */
+/* Define to 1 if you have the declaration of `strstr(const char*,const
+   char*)', and to 0 if you don't. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_DECL_STRSTR
 #endif
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index e77cd04..63ebc7f 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -25611,7 +25611,25 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
   if (SIBLING_CALL_P (insn))
     {
       if (direct_p)
-	xasm = "%!jmp\t%P0";
+	{
+	  if (!SYMBOL_REF_LOCAL_P (call_op)
+	      && !flag_plt
+	      && !flag_pic
+	      && TARGET_ELF)
+	    {
+	      /* Avoid PLT.  */
+	      if (TARGET_64BIT)
+		xasm = "%!jmp\t*%p0@GOTPCREL(%%rip)";
+	      else
+#ifdef HAVE_AS_INDIRECT_BRANCH_VIA_GOT
+		xasm = "%!jmp\t*%p0@GOT";
+#else
+		xasm = "%!jmp\t%P0";
+#endif
+	    }
+	  else
+	    xasm = "%!jmp\t%P0";
+	}
       /* SEH epilogue detection requires the indirect branch case
 	 to include REX.W.  */
       else if (TARGET_SEH)
@@ -25654,7 +25672,25 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
     }
 
   if (direct_p)
-    xasm = "%!call\t%P0";
+    {
+      if (!SYMBOL_REF_LOCAL_P (call_op)
+	  && !flag_plt
+	  && !flag_pic
+	  && TARGET_ELF)
+	{
+	  /* Avoid PLT.  */
+	  if (TARGET_64BIT)
+	    xasm = "%!call\t*%p0@GOTPCREL(%%rip)";
+	  else
+#ifdef HAVE_AS_INDIRECT_BRANCH_VIA_GOT
+	    xasm = "%!call\t*%p0@GOT";
+#else
+	    xasm = "%!call\t%P0";
+#endif
+	}
+      else
+	xasm = "%!call\t%P0";
+    }
   else
     xasm = "%!call\t%A0";
 
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 34ef343..9b7f10f 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -584,6 +584,8 @@ extern tree x86_mfence;
 /* This is re-defined by cygming.h.  */
 #define TARGET_PECOFF 0
 
+#define TARGET_ELF (!TARGET_MACHO && !TARGET_SEH && !TARGET_PECOFF)
+
 /* The default abi used by target.  */
 #define DEFAULT_ABI SYSV_ABI
 
diff --git a/gcc/configure b/gcc/configure
index a9a76d6..4419035 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -25361,7 +25361,7 @@ $as_echo "#define HAVE_AS_IX86_DIFF_SECT_DELTA 1" >>confdefs.h
 
 fi
 
-    # These two are used unconditionally by i386.[ch]; it is to be defined
+    # These three are used unconditionally by i386.[ch]; it is to be defined
     # to 1 if the feature is present, 0 otherwise.
     as_ix86_gotoff_in_data_opt=
     if test x$gas = xyes; then
@@ -25407,6 +25407,51 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+    as_ix86_indirect_branch_via_got_opt=
+    if test x$gas = xyes; then
+      as_ix86_indirect_branch_via_got_opt="--32"
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for call *foo@GOT" >&5
+$as_echo_n "checking assembler for call *foo@GOT... " >&6; }
+if test "${gcc_cv_as_ix86_indirect_branch_via_got+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_ix86_indirect_branch_via_got=no
+    if test $in_tree_gas = yes; then
+    if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 26 \) \* 1000 + 0`
+  then gcc_cv_as_ix86_indirect_branch_via_got=yes
+fi
+  elif test x$gcc_cv_as != x; then
+    $as_echo '	.text
+	call *foo@GOT' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags $as_ix86_indirect_branch_via_got_opt -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	if test x$gcc_cv_readelf != x \
+	 && $gcc_cv_readelf -r conftest.o | grep R_386_ | grep -v R_386_GOT32 > /dev/null 2>&1; then
+	   gcc_cv_as_ix86_indirect_branch_via_got=yes
+	 fi
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_ix86_indirect_branch_via_got" >&5
+$as_echo "$gcc_cv_as_ix86_indirect_branch_via_got" >&6; }
+if test $gcc_cv_as_ix86_indirect_branch_via_got = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_AS_INDIRECT_BRANCH_VIA_GOT 1
+_ACEOF
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for rep and lock prefix" >&5
 $as_echo_n "checking assembler for rep and lock prefix... " >&6; }
 if test "${gcc_cv_as_ix86_rep_lock_prefix+set}" = set; then :
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 83f9c09..543e650 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -3953,7 +3953,7 @@ foo:	nop
       [AC_DEFINE(HAVE_AS_IX86_DIFF_SECT_DELTA, 1,
         [Define if your assembler supports the subtraction of symbols in different sections.])])
 
-    # These two are used unconditionally by i386.[ch]; it is to be defined
+    # These three are used unconditionally by i386.[ch]; it is to be defined
     # to 1 if the feature is present, 0 otherwise.
     as_ix86_gotoff_in_data_opt=
     if test x$gas = xyes; then
@@ -3971,6 +3971,22 @@ foo:	nop
       [`if test $gcc_cv_as_ix86_gotoff_in_data = yes; then echo 1; else echo 0; fi`],
       [Define true if the assembler supports '.long foo@GOTOFF'.])
 
+    as_ix86_indirect_branch_via_got_opt=
+    if test x$gas = xyes; then
+      as_ix86_indirect_branch_via_got_opt="--32"
+    fi
+    gcc_GAS_CHECK_FEATURE([call *foo@GOT],
+      gcc_cv_as_ix86_indirect_branch_via_got, [2,26,0],
+      [$as_ix86_indirect_branch_via_got_opt],
+[	.text
+	call *foo@GOT],
+	[if test x$gcc_cv_readelf != x \
+	 && $gcc_cv_readelf -r conftest.o | grep R_386_ | grep -v R_386_GOT32 > /dev/null 2>&1; then
+	   gcc_cv_as_ix86_indirect_branch_via_got=yes
+	 fi],
+     [AC_DEFINE_UNQUOTED(HAVE_AS_INDIRECT_BRANCH_VIA_GOT, 1,
+       [Define true if the assembler supports 'call *foo@GOT'.])])
+
     gcc_GAS_CHECK_FEATURE([rep and lock prefix],
         gcc_cv_as_ix86_rep_lock_prefix,,,
 	[rep movsl
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-10.c b/gcc/testsuite/gcc.target/i386/pr66232-10.c
new file mode 100644
index 0000000..e95c789
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-10.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void) __attribute__((visibility("hidden")));
+
+void
+foo (void)
+{
+  bar ();
+}
+
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*.bar@GOT" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-11.c b/gcc/testsuite/gcc.target/i386/pr66232-11.c
new file mode 100644
index 0000000..63a1809
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-11.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void) __attribute__((visibility("hidden")));
+
+int
+foo (void)
+{
+  bar ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "call\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "call\[ \t\]*.bar@GOT" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-12.c b/gcc/testsuite/gcc.target/i386/pr66232-12.c
new file mode 100644
index 0000000..89bb605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-12.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern int bar (void) __attribute__((visibility("hidden")));
+
+int
+foo (void)
+{
+  return bar ();
+}
+
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*.bar@GOT" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-13.c b/gcc/testsuite/gcc.target/i386/pr66232-13.c
new file mode 100644
index 0000000..4aec477
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-13.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern int bar (void) __attribute__((visibility("hidden")));
+
+int
+foo (void)
+{
+  return bar () + 1;
+}
+
+/* { dg-final { scan-assembler-not "call\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "call\[ \t\]*.bar@GOT" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-6.c b/gcc/testsuite/gcc.target/i386/pr66232-6.c
new file mode 100644
index 0000000..b465e59
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-6.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void);
+
+void
+foo (void)
+{
+  bar ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOT" { target { ia32 && branch_via_got } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-7.c b/gcc/testsuite/gcc.target/i386/pr66232-7.c
new file mode 100644
index 0000000..2908541
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-7.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void);
+
+int
+foo (void)
+{
+  bar ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*.bar@GOT" { target { ia32 && branch_via_got } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-8.c b/gcc/testsuite/gcc.target/i386/pr66232-8.c
new file mode 100644
index 0000000..c23d6bb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-8.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern int bar (void);
+
+int
+foo (void)
+{
+  return bar ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOT" { target { ia32 && branch_via_got } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66232-9.c b/gcc/testsuite/gcc.target/i386/pr66232-9.c
new file mode 100644
index 0000000..b0cd40b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66232-9.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern int bar (void);
+
+int
+foo (void)
+{
+  return bar () + 1;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*.bar@GOT" { target { ia32 && branch_via_got } } } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index f0c209f..f80fd60 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -6320,6 +6320,58 @@ proc check_effective_target_pie_copyreloc { } {
     return $pie_copyreloc_available_saved
 }
 
+# Return 1 if the x86 target supports "call *foo@GOT", 0 otherwise.
+# Cache the result.
+
+proc check_effective_target_branch_via_got { } {
+    global branch_via_got_available_saved
+    global tool
+    global GCC_UNDER_TEST
+
+    if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+	return 0
+    }
+
+    # Need auto-host.h to check linker support.
+    if { ![file exists ../../auto-host.h ] } {
+	return 0
+    }
+
+    if [info exists branch_via_got_available_saved] {
+	verbose "check_effective_target_branch_via_got returning saved $branch_via_got_available_saved" 2
+    } else {
+	# Set up and compile to see if linker supports PIE with copy
+	# reloc.  Include the current process ID in the file names to
+	# prevent conflicts with invocations for multiple testsuites.
+
+	set src pie[pid].c
+	set obj pie[pid].o
+
+	set f [open $src "w"]
+	puts $f "#include \"../../auto-host.h\""
+	puts $f "#ifndef HAVE_AS_INDIRECT_BRANCH_VIA_GOT"
+	puts $f "# error Assembler does not support call *foo@GOT."
+	puts $f "#endif"
+	close $f
+
+	verbose "check_effective_target_branch_via_got compiling testfile $src" 2
+	set lines [${tool}_target_compile $src $obj object ""]
+
+	file delete $src
+	file delete $obj
+
+	if [string match "" $lines] then {
+	    verbose "check_effective_target_branch_via_got testfile compilation passed" 2
+	    set branch_via_got_available_saved 1
+	} else {
+	    verbose "check_effective_target_branch_via_got testfile compilation failed" 2
+	    set branch_via_got_available_saved 0
+	}
+    }
+
+    return $branch_via_got_available_saved
+}
+
 # Return 1 if the target uses comdat groups.
 
 proc check_effective_target_comdat_group {} {
-- 
1.9.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]