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. --- gcc/config.in | 14 ++++++++++---- gcc/config/i386/i386.c | 42 ++++++++++++++++++++++++++++++++++++++++-- gcc/configure | 47 ++++++++++++++++++++++++++++++++++++++++++++++- gcc/configure.ac | 18 +++++++++++++++++- 4 files changed, 113 insertions(+), 8 deletions(-) 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..5ca19f2 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -25611,7 +25611,26 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) if (SIBLING_CALL_P (insn)) { if (direct_p) - xasm = "%!jmp\t%P0"; + { + if (!flag_plt + && !flag_pic + && !TARGET_MACHO + && !TARGET_SEH + && !TARGET_PECOFF) + { + /* 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 +25673,26 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) } if (direct_p) - xasm = "%!call\t%P0"; + { + if (!flag_plt + && !flag_pic + && !TARGET_MACHO + && !TARGET_SEH + && !TARGET_PECOFF) + { + /* 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/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 -- 1.9.3