This patch extends -fno-plt to non-PIC 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", which accesses the GOT slot without a base register, with a new R_386_GOT32x relocation.
gcc/ * config/i386/i386.c (ix86_nopic_noplt_attribute_p): Check HAVE_LD_R_386_GOT32X == 0 before returning false. (ix86_output_call_insn): Generate "%!jmp/call\t*%p0@GOT" for 32-bit. gcc/testsuite/ * gcc.target/i386/pr66232-10.c: New file. * 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_r_386_got32x): New. (check_effective_target_r_x86_64_gotpcrelx): Likewise. --- gcc/config/i386/i386.c | 19 +++++- 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/lib/target-supports.exp | 104 +++++++++++++++++++++++++++++ 6 files changed, 173 insertions(+), 3 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 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f5b1717..b4c57ba 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -26904,7 +26904,8 @@ static bool ix86_nopic_noplt_attribute_p (rtx call_op) { if (flag_pic || ix86_cmodel == CM_LARGE - || !TARGET_64BIT || TARGET_MACHO || TARGET_SEH || TARGET_PECOFF + || (!TARGET_64BIT && HAVE_LD_R_386_GOT32X == 0) + || TARGET_MACHO || TARGET_SEH || TARGET_PECOFF || SYMBOL_REF_LOCAL_P (call_op)) return false; @@ -26929,8 +26930,14 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) if (SIBLING_CALL_P (insn)) { + /* ix86_nopic_noplt_attribute_p returns false for PIC. */ if (direct_p && ix86_nopic_noplt_attribute_p (call_op)) - xasm = "%!jmp\t*%p0@GOTPCREL(%%rip)"; + { + if (TARGET_64BIT) + xasm = "%!jmp\t*%p0@GOTPCREL(%%rip)"; + else + xasm = "%!jmp\t*%p0@GOT"; + } else if (direct_p) xasm = "%!jmp\t%P0"; /* SEH epilogue detection requires the indirect branch case @@ -26974,8 +26981,14 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) seh_nop_p = true; } + /* ix86_nopic_noplt_attribute_p returns false for PIC. */ if (direct_p && ix86_nopic_noplt_attribute_p (call_op)) - xasm = "%!call\t*%p0@GOTPCREL(%%rip)"; + { + if (TARGET_64BIT) + xasm = "%!call\t*%p0@GOTPCREL(%%rip)"; + else + xasm = "%!call\t*%p0@GOT"; + } else if (direct_p) xasm = "%!call\t%P0"; else 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..2e902d6 --- /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); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*.bar@GOT" { target { ia32 && r_386_got32x } } } } */ 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..9254759 --- /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); + +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 && r_386_got32x } } } } */ 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..97c3a3c --- /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); + +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 && r_386_got32x } } } } */ 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..14ad039 --- /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); + +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 && r_386_got32x } } } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 2de8fac..e6d4601 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -6472,6 +6472,110 @@ proc check_effective_target_pie_copyreloc { } { return $pie_copyreloc_available_saved } +# Return 1 if the x86 target generates R_386_GOT32X for "call *foo@GOT", +# 0 otherwise. Cache the result. + +proc check_effective_target_r_386_got32x { } { + global r_386_got32x_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 r_386_got32x_available_saved] { + verbose "check_effective_target_r_386_got32x returning saved $r_386_got32x_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 "#if HAVE_LD_R_386_GOT32X == 0" + puts $f "# error Assembler does not support R_386_GOT32X." + puts $f "#endif" + close $f + + verbose "check_effective_target_r_386_got32x 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_r_386_got32x testfile compilation passed" 2 + set r_386_got32x_available_saved 1 + } else { + verbose "check_effective_target_r_386_got32x testfile compilation failed" 2 + set r_386_got32x_available_saved 0 + } + } + + return $r_386_got32x_available_saved +} + +# Return 1 if the x86 target generates R_386_GOT32X for +# "call *foo@GOTPCREL(%rip)", 0 otherwise. Cache the result. + +proc check_effective_target_r_x86_64_gotpcrelx { } { + global r_x86_64_gotpcrelx_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 r_x86_64_gotpcrelx_available_saved] { + verbose "check_effective_target_r_x86_64_gotpcrelx returning saved $r_x86_64_gotpcrelx_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 "#if HAVE_LD_R_X86_64_GOTPCRELX == 0" + puts $f "# error Assembler does not support R_X86_64_GOTPCRELX." + puts $f "#endif" + close $f + + verbose "check_effective_target_r_x86_64_gotpcrelx 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_r_x86_64_gotpcrelx testfile compilation passed" 2 + set r_x86_64_gotpcrelx_available_saved 1 + } else { + verbose "check_effective_target_r_x86_64_gotpcrelx testfile compilation failed" 2 + set r_x86_64_gotpcrelx_available_saved 0 + } + } + + return $r_x86_64_gotpcrelx_available_saved +} + # Return 1 if the target uses comdat groups. proc check_effective_target_comdat_group {} { -- 2.4.3