Message ID | 20160623114505.GA17653@intel.com |
---|---|
State | New |
Headers | show |
On Thu, Jun 23, 2016 at 1:45 PM, H.J. Lu <hongjiu.lu@intel.com> wrote: > i386 psABI has been updated to clarify that R_386_GOT32X and R_386_GOT32 > relocations can be used to access GOT without base register when PIC is > disabled: > > https://groups.google.com/forum/#!topic/ia32-abi/awsRSvJOJfs > > 32-bit x86 assembler and linker from binutils 2.26.1 and 2.27 support > > call/jmp *_start@GOT > cmpl $0, bar@GOT > > for both normal and IFUNC functions. We check if 32-bit x86 assembler > and linker have the fix for: > > https://sourceware.org/bugzilla/show_bug.cgi?id=20244 > > before accessing external function via GOT slot for -fno-plt in both PIC > and non-PIC modes. > > Tested on i686 and x86-64. OK for trunk? > > > H.J. > ---- > PR target/66232 > PR target/67400 > * configure.ac (HAVE_LD_IX86_GOT32X_RELOC): New. Defined to 1 > if 32-bit assembler and linker support "jmp *_start@GOT" and > "movl $0, bar@GOT". Otherise, defined to 0. > * config.in: Regenerated. > * configure: Likewise. > * config/i386/i386.c (ix86_force_load_from_GOT_p): Return > true if HAVE_LD_IX86_GOT32X_RELOC is 1 in 32-bit mode. > (ix86_legitimate_address_p): Allow UNSPEC_GOT for -fno-plt > if ix86_force_load_from_GOT_p returns true. > (ix86_print_operand_address_as): Also support UNSPEC_GOT if > ix86_force_load_from_GOT_p returns true. > (ix86_expand_move): Generate UNSPEC_GOT in 32-bit mode to load > the external function address via the GOT slot. > (ix86_nopic_noplt_attribute_p): Check HAVE_LD_IX86_GOT32X_RELOC > == 0 before returning false in 32-bit mode. > (ix86_output_call_insn): Generate "%!jmp/call\t*%p0@GOT" in > 32-bit mode if ix86_nopic_noplt_attribute_p returns true. > > gcc/testsuite/ > > PR target/66232 > PR target/67400 > * gcc.target/i386/pr66232-14.c: New file. > * gcc.target/i386/pr66232-15.c: Likewise. > * gcc.target/i386/pr66232-16.c: Likewise. > * gcc.target/i386/pr66232-17.c: Likewise. > * gcc.target/i386/pr67400-1.c: Don't disable for ia32. Scan for > ia32 and if R_386_GOT32X relocation is supported. > * gcc.target/i386/pr67400-2.c: Likewise. > * gcc.target/i386/pr67400-3.c: Likewise. > * gcc.target/i386/pr67400-4.c: Likewise. > * gcc.target/i386/pr67400-6.c: Likewise. > * gcc.target/i386/pr67400-7.c: Likewise. > * lib/target-supports.exp (check_effective_target_got32x_reloc): > New. > --- > gcc/config.in | 9 +++++- > gcc/config/i386/i386.c | 35 ++++++++++++++++---- > gcc/configure | 50 +++++++++++++++++++++++++++++ > gcc/configure.ac | 42 ++++++++++++++++++++++++ > gcc/testsuite/gcc.target/i386/pr66232-14.c | 13 ++++++++ > gcc/testsuite/gcc.target/i386/pr66232-15.c | 14 ++++++++ > gcc/testsuite/gcc.target/i386/pr66232-16.c | 13 ++++++++ > gcc/testsuite/gcc.target/i386/pr66232-17.c | 13 ++++++++ > gcc/testsuite/gcc.target/i386/pr67400-1.c | 8 +++-- > gcc/testsuite/gcc.target/i386/pr67400-2.c | 8 +++-- > gcc/testsuite/gcc.target/i386/pr67400-3.c | 3 +- > gcc/testsuite/gcc.target/i386/pr67400-4.c | 5 +-- > gcc/testsuite/gcc.target/i386/pr67400-6.c | 8 +++-- > gcc/testsuite/gcc.target/i386/pr67400-7.c | 6 ++-- > gcc/testsuite/lib/target-supports.exp | 51 ++++++++++++++++++++++++++++++ > 15 files changed, 256 insertions(+), 22 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-14.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-15.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-16.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr66232-17.c > > diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c > index 9c7b015..a2dcf36 100644 > --- a/gcc/config/i386/i386.c > +++ b/gcc/config/i386/i386.c > @@ -15125,7 +15125,8 @@ darwin_local_data_pic (rtx disp) > bool > ix86_force_load_from_GOT_p (rtx x) > { > - return (TARGET_64BIT && !TARGET_PECOFF && !TARGET_MACHO > + return ((TARGET_64BIT || HAVE_LD_IX86_GOT32X_RELOC) > + && !TARGET_PECOFF && !TARGET_MACHO > && !flag_plt && !flag_pic > && ix86_cmodel != CM_LARGE > && GET_CODE (x) == SYMBOL_REF > @@ -15606,6 +15607,14 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict) > used. While ABI specify also 32bit relocations, we don't produce > them at all and use IP relative instead. */ > case UNSPEC_GOT: > + gcc_assert (flag_pic > + || ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0))); > + if (!TARGET_64BIT) > + goto is_legitimate_pic; > + > + /* 64bit address unspec. */ > + return false; The above should read like: case UNSPEC_GOT: if (!TARGET_64BIT && ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0))) goto is_legitimate_pic; /* FALLTHRU */ case UNSPEC_GOTOFF: gcc_assert (flag_pic); if (!TARGET_64BIT) goto is_legitimate_pic; Please also update the comment above. > case UNSPEC_GOTOFF: > gcc_assert (flag_pic); > if (!TARGET_64BIT) > @@ -18194,7 +18203,8 @@ ix86_print_operand_address_as (FILE *file, rtx addr, > /* Load the external function address via the GOT slot to avoid PLT. */ > else if (GET_CODE (disp) == CONST > && GET_CODE (XEXP (disp, 0)) == UNSPEC > - && XINT (XEXP (disp, 0), 1) == UNSPEC_GOTPCREL > + && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOTPCREL > + || XINT (XEXP (disp, 0), 1) == UNSPEC_GOT) > && ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0))) > output_pic_addr_const (file, disp, 0); > else if (flag_pic) > @@ -19449,7 +19459,9 @@ ix86_expand_move (machine_mode mode, rtx operands[]) > { > /* Load the external function address via GOT slot to avoid PLT. */ > op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op1), > - UNSPEC_GOTPCREL); > + (TARGET_64BIT > + ? UNSPEC_GOTPCREL > + : UNSPEC_GOT)); > op1 = gen_rtx_CONST (Pmode, op1); > op1 = gen_const_mem (Pmode, op1); > set_mem_alias_set (op1, ix86_GOT_alias_set ()); > @@ -28027,7 +28039,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_IX86_GOT32X_RELOC == 0) || !(TARGET_64BIT || HAVE_LD_IX86_GOT32X_RELOC) > + || TARGET_MACHO || TARGET_SEH || TARGET_PECOFF > || SYMBOL_REF_LOCAL_P (call_op)) > return false; > > @@ -28055,7 +28068,12 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) > if (direct_p) > { > if (ix86_nopic_noplt_attribute_p (call_op)) > - xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; > + { > + if (TARGET_64BIT) > + xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; > + else > + xasm = "%!jmp\t{*%p0@GOT|[DWORD PTR %p0@GOT]}"; > + } > else > xasm = "%!jmp\t%P0"; > } > @@ -28103,7 +28121,12 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) > if (direct_p) > { > if (ix86_nopic_noplt_attribute_p (call_op)) > - xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; > + { > + if (TARGET_64BIT) > + xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; > + else > + xasm = "%!call\t{*%p0@GOT|[DWORD PTR %p0@GOT]}"; > + } > else > xasm = "%!call\t%P0"; > } > diff --git a/gcc/configure.ac b/gcc/configure.ac > index fabd48e..2506957 100644 > --- a/gcc/configure.ac > +++ b/gcc/configure.ac > @@ -4200,6 +4200,48 @@ value:' > [`if test $gcc_cv_as_ix86_tlsldm = yes; then echo 1; else echo 0; fi`], > [Define to 1 if your assembler and linker support @tlsldm.]) > > + AC_CACHE_CHECK([linker for R_386_GOT32X relocation], > + [gcc_cv_ld_ix86_got32x_reloc], > + [gcc_cv_ld_ix86_got32x_reloc=no > + if test x$gcc_cv_as != x -a x$gcc_cv_ld != x \ > + -a x$gcc_cv_objdump != x -a x$gcc_cv_readelf != x; then > + # Enforce 32-bit output with gas and gld. > + if test x$gas = xyes; then > + as_ix86_got32x_opt="--32" > + fi > + if echo "$ld_ver" | grep GNU > /dev/null; then > + if $gcc_cv_ld -V 2>/dev/null | grep elf_i386_sol2 > /dev/null; then > + ld_ix86_got32x_opt="-melf_i386_sol2" > + else > + ld_ix86_got32x_opt="-melf_i386" > + fi > + fi > + cat > conftest.s <<EOF > + .data > +bar: > + .byte 1 > + .text > + .global _start > +_start: > + movl \$0, bar@GOT > + jmp *_start@GOT > +EOF > + if $gcc_cv_as $as_ix86_got32x_opt -o conftest.o conftest.s > /dev/null 2>&1 \ > + && $gcc_cv_readelf --relocs --wide conftest.o 2>&1 \ > + | grep R_386_GOT32X > /dev/null 2>&1 \ > + && $gcc_cv_ld $ld_ix86_got32x_opt -o conftest conftest.o > /dev/null 2>&1; then > + if $gcc_cv_objdump -dw conftest 2>&1 \ > + | grep 0xffffff > /dev/null 2>&1; then > + gcc_cv_ld_ix86_got32x_reloc=no > + else > + gcc_cv_ld_ix86_got32x_reloc=yes > + fi > + fi > + fi > + rm -f conftest conftest.s conftest.o]) > + AC_DEFINE_UNQUOTED(HAVE_LD_IX86_GOT32X_RELOC, > + [`if test x"$gcc_cv_ld_ix86_got32x_reloc" = xyes; then echo 1; else echo 0; fi`], > + [Define 0/1 if Define if your linker supports R_386_GOT32X relocation.]) THe configure script already determined how to enforce 32bit output with gas and gld, please rename and reuse as_ix86_tls_ldm_opt and ld_ix86_tls_ldm_opt from the above check. Then define conftest_s and call gcc_GAS_CHECK_FEATURE, as is the case with R_386_TLS_LDM reloc check. Also, please name this variable in a similar way, HAVE_AS_IX86_GOT32X. Please repost v2 patch. Uros. > ;; > > ia64*-*-*) > diff --git a/gcc/testsuite/gcc.target/i386/pr66232-14.c b/gcc/testsuite/gcc.target/i386/pr66232-14.c > new file mode 100644 > index 0000000..804e5a5 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr66232-14.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 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr66232-15.c b/gcc/testsuite/gcc.target/i386/pr66232-15.c > new file mode 100644 > index 0000000..3d2f6da > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr66232-15.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 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr66232-16.c b/gcc/testsuite/gcc.target/i386/pr66232-16.c > new file mode 100644 > index 0000000..d67f1a5 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr66232-16.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 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr66232-17.c b/gcc/testsuite/gcc.target/i386/pr66232-17.c > new file mode 100644 > index 0000000..bf6f375 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr66232-17.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 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr67400-1.c b/gcc/testsuite/gcc.target/i386/pr67400-1.c > index 18b3790..8af6650 100644 > --- a/gcc/testsuite/gcc.target/i386/pr67400-1.c > +++ b/gcc/testsuite/gcc.target/i386/pr67400-1.c > @@ -1,4 +1,4 @@ > -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ > +/* { dg-do compile { target *-*-linux* } } */ > /* { dg-options "-O2 -fno-pic -fno-plt" } */ > > extern void bar (void); > @@ -9,5 +9,7 @@ foo (void) > return &bar; > } > > -/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ > -/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," } } */ > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > +/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "\(mov|lea\)l\[ \t\]*\(\\\$|\)bar," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr67400-2.c b/gcc/testsuite/gcc.target/i386/pr67400-2.c > index 8f61c3f..23dd4bf 100644 > --- a/gcc/testsuite/gcc.target/i386/pr67400-2.c > +++ b/gcc/testsuite/gcc.target/i386/pr67400-2.c > @@ -1,4 +1,4 @@ > -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ > +/* { dg-do compile { target *-*-linux* } } */ > /* { dg-options "-O2 -fno-pic -fno-plt" } */ > > extern void bar (void); > @@ -10,5 +10,7 @@ foo (void) > p = &bar; > } > > -/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ > -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," } } */ > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr67400-3.c b/gcc/testsuite/gcc.target/i386/pr67400-3.c > index 40d3521..649c980 100644 > --- a/gcc/testsuite/gcc.target/i386/pr67400-3.c > +++ b/gcc/testsuite/gcc.target/i386/pr67400-3.c > @@ -13,4 +13,5 @@ foo (void) > } > > /* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */ > -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr67400-4.c b/gcc/testsuite/gcc.target/i386/pr67400-4.c > index a329bbf..5f6883d 100644 > --- a/gcc/testsuite/gcc.target/i386/pr67400-4.c > +++ b/gcc/testsuite/gcc.target/i386/pr67400-4.c > @@ -1,4 +1,4 @@ > -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ > +/* { dg-do compile { target *-*-linux* } } */ > /* { dg-options "-O2 -fno-pic -fno-plt" } */ > > extern void bar (void) __attribute__ ((visibility ("hidden"))); > @@ -10,4 +10,5 @@ foo (void) > } > > /* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */ > -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr67400-6.c b/gcc/testsuite/gcc.target/i386/pr67400-6.c > index bb766cd..652add4 100644 > --- a/gcc/testsuite/gcc.target/i386/pr67400-6.c > +++ b/gcc/testsuite/gcc.target/i386/pr67400-6.c > @@ -1,4 +1,4 @@ > -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ > +/* { dg-do compile { target *-*-linux* } } */ > /* { dg-options "-O2 -fno-pic -fno-plt" } */ > > extern int bar (void); > @@ -9,5 +9,7 @@ check (void *p) > return p != &bar; > } > > -/* { dg-final { scan-assembler "cmp\(l|q\)\[ \t\]*.*bar@GOTPCREL" } } */ > -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," } } */ > +/* { dg-final { scan-assembler "cmp\(l|q\)\[ \t\]*.*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr67400-7.c b/gcc/testsuite/gcc.target/i386/pr67400-7.c > index 32ae85f..900e87a 100644 > --- a/gcc/testsuite/gcc.target/i386/pr67400-7.c > +++ b/gcc/testsuite/gcc.target/i386/pr67400-7.c > @@ -1,4 +1,4 @@ > -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ > +/* { dg-do compile { target *-*-linux* } } */ > /* { dg-options "-O2 -fno-pic -fno-plt" } */ > > extern void bar (void); > @@ -9,5 +9,5 @@ foo (void) > return &bar+1; > } > > -/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ > -/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," } } */ > +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," { target { ! ia32 } } } } */ > diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp > index 1b1d03a..0b9b507 100644 > --- a/gcc/testsuite/lib/target-supports.exp > +++ b/gcc/testsuite/lib/target-supports.exp > @@ -6975,6 +6975,57 @@ proc check_effective_target_pie_copyreloc { } { > return $pie_copyreloc_available_saved > } > > +# Return 1 if the x86 target supports R_386_GOT32X relocation, 0 > +# otherwise. Cache the result. > + > +proc check_effective_target_got32x_reloc { } { > + global got32x_reloc_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 got32x_reloc_available_saved] { > + verbose "check_effective_target_got32x_reloc returning saved $got32x_reloc_available_saved" 2 > + } else { > + # Include the current process ID in the file names to prevent > + # conflicts with invocations for multiple testsuites. > + > + set src got32x[pid].c > + set obj got32x[pid].o > + > + set f [open $src "w"] > + puts $f "#include \"../../auto-host.h\"" > + puts $f "#if HAVE_LD_IX86_GOT32X_RELOC == 0" > + puts $f "# error Assembler does not support R_386_GOT32X." > + puts $f "#endif" > + close $f > + > + verbose "check_effective_target_got32x_reloc 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_got32x_reloc testfile compilation passed" 2 > + set got32x_reloc_available_saved 1 > + } else { > + verbose "check_effective_target_got32x_reloc testfile compilation failed" 2 > + set got32x_reloc_available_saved 0 > + } > + } > + > + return $got32x_reloc_available_saved > +} > + > # Return 1 if the target uses comdat groups. > > proc check_effective_target_comdat_group {} { > -- > 2.5.5 >
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9c7b015..a2dcf36 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -15125,7 +15125,8 @@ darwin_local_data_pic (rtx disp) bool ix86_force_load_from_GOT_p (rtx x) { - return (TARGET_64BIT && !TARGET_PECOFF && !TARGET_MACHO + return ((TARGET_64BIT || HAVE_LD_IX86_GOT32X_RELOC) + && !TARGET_PECOFF && !TARGET_MACHO && !flag_plt && !flag_pic && ix86_cmodel != CM_LARGE && GET_CODE (x) == SYMBOL_REF @@ -15606,6 +15607,14 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict) used. While ABI specify also 32bit relocations, we don't produce them at all and use IP relative instead. */ case UNSPEC_GOT: + gcc_assert (flag_pic + || ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0))); + if (!TARGET_64BIT) + goto is_legitimate_pic; + + /* 64bit address unspec. */ + return false; + case UNSPEC_GOTOFF: gcc_assert (flag_pic); if (!TARGET_64BIT) @@ -18194,7 +18203,8 @@ ix86_print_operand_address_as (FILE *file, rtx addr, /* Load the external function address via the GOT slot to avoid PLT. */ else if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == UNSPEC - && XINT (XEXP (disp, 0), 1) == UNSPEC_GOTPCREL + && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOTPCREL + || XINT (XEXP (disp, 0), 1) == UNSPEC_GOT) && ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0))) output_pic_addr_const (file, disp, 0); else if (flag_pic) @@ -19449,7 +19459,9 @@ ix86_expand_move (machine_mode mode, rtx operands[]) { /* Load the external function address via GOT slot to avoid PLT. */ op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op1), - UNSPEC_GOTPCREL); + (TARGET_64BIT + ? UNSPEC_GOTPCREL + : UNSPEC_GOT)); op1 = gen_rtx_CONST (Pmode, op1); op1 = gen_const_mem (Pmode, op1); set_mem_alias_set (op1, ix86_GOT_alias_set ()); @@ -28027,7 +28039,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_IX86_GOT32X_RELOC == 0) + || TARGET_MACHO || TARGET_SEH || TARGET_PECOFF || SYMBOL_REF_LOCAL_P (call_op)) return false; @@ -28055,7 +28068,12 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) if (direct_p) { if (ix86_nopic_noplt_attribute_p (call_op)) - xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; + { + if (TARGET_64BIT) + xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; + else + xasm = "%!jmp\t{*%p0@GOT|[DWORD PTR %p0@GOT]}"; + } else xasm = "%!jmp\t%P0"; } @@ -28103,7 +28121,12 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) if (direct_p) { if (ix86_nopic_noplt_attribute_p (call_op)) - xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; + { + if (TARGET_64BIT) + xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}"; + else + xasm = "%!call\t{*%p0@GOT|[DWORD PTR %p0@GOT]}"; + } else xasm = "%!call\t%P0"; } diff --git a/gcc/configure.ac b/gcc/configure.ac index fabd48e..2506957 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4200,6 +4200,48 @@ value:' [`if test $gcc_cv_as_ix86_tlsldm = yes; then echo 1; else echo 0; fi`], [Define to 1 if your assembler and linker support @tlsldm.]) + AC_CACHE_CHECK([linker for R_386_GOT32X relocation], + [gcc_cv_ld_ix86_got32x_reloc], + [gcc_cv_ld_ix86_got32x_reloc=no + if test x$gcc_cv_as != x -a x$gcc_cv_ld != x \ + -a x$gcc_cv_objdump != x -a x$gcc_cv_readelf != x; then + # Enforce 32-bit output with gas and gld. + if test x$gas = xyes; then + as_ix86_got32x_opt="--32" + fi + if echo "$ld_ver" | grep GNU > /dev/null; then + if $gcc_cv_ld -V 2>/dev/null | grep elf_i386_sol2 > /dev/null; then + ld_ix86_got32x_opt="-melf_i386_sol2" + else + ld_ix86_got32x_opt="-melf_i386" + fi + fi + cat > conftest.s <<EOF + .data +bar: + .byte 1 + .text + .global _start +_start: + movl \$0, bar@GOT + jmp *_start@GOT +EOF + if $gcc_cv_as $as_ix86_got32x_opt -o conftest.o conftest.s > /dev/null 2>&1 \ + && $gcc_cv_readelf --relocs --wide conftest.o 2>&1 \ + | grep R_386_GOT32X > /dev/null 2>&1 \ + && $gcc_cv_ld $ld_ix86_got32x_opt -o conftest conftest.o > /dev/null 2>&1; then + if $gcc_cv_objdump -dw conftest 2>&1 \ + | grep 0xffffff > /dev/null 2>&1; then + gcc_cv_ld_ix86_got32x_reloc=no + else + gcc_cv_ld_ix86_got32x_reloc=yes + fi + fi + fi + rm -f conftest conftest.s conftest.o]) + AC_DEFINE_UNQUOTED(HAVE_LD_IX86_GOT32X_RELOC, + [`if test x"$gcc_cv_ld_ix86_got32x_reloc" = xyes; then echo 1; else echo 0; fi`], + [Define 0/1 if Define if your linker supports R_386_GOT32X relocation.]) ;; ia64*-*-*) diff --git a/gcc/testsuite/gcc.target/i386/pr66232-14.c b/gcc/testsuite/gcc.target/i386/pr66232-14.c new file mode 100644 index 0000000..804e5a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66232-14.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 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr66232-15.c b/gcc/testsuite/gcc.target/i386/pr66232-15.c new file mode 100644 index 0000000..3d2f6da --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66232-15.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 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr66232-16.c b/gcc/testsuite/gcc.target/i386/pr66232-16.c new file mode 100644 index 0000000..d67f1a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66232-16.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 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr66232-17.c b/gcc/testsuite/gcc.target/i386/pr66232-17.c new file mode 100644 index 0000000..bf6f375 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66232-17.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 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr67400-1.c b/gcc/testsuite/gcc.target/i386/pr67400-1.c index 18b3790..8af6650 100644 --- a/gcc/testsuite/gcc.target/i386/pr67400-1.c +++ b/gcc/testsuite/gcc.target/i386/pr67400-1.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-do compile { target *-*-linux* } } */ /* { dg-options "-O2 -fno-pic -fno-plt" } */ extern void bar (void); @@ -9,5 +9,7 @@ foo (void) return &bar; } -/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ -/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," } } */ +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ +/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "\(mov|lea\)l\[ \t\]*\(\\\$|\)bar," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr67400-2.c b/gcc/testsuite/gcc.target/i386/pr67400-2.c index 8f61c3f..23dd4bf 100644 --- a/gcc/testsuite/gcc.target/i386/pr67400-2.c +++ b/gcc/testsuite/gcc.target/i386/pr67400-2.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-do compile { target *-*-linux* } } */ /* { dg-options "-O2 -fno-pic -fno-plt" } */ extern void bar (void); @@ -10,5 +10,7 @@ foo (void) p = &bar; } -/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," } } */ +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr67400-3.c b/gcc/testsuite/gcc.target/i386/pr67400-3.c index 40d3521..649c980 100644 --- a/gcc/testsuite/gcc.target/i386/pr67400-3.c +++ b/gcc/testsuite/gcc.target/i386/pr67400-3.c @@ -13,4 +13,5 @@ foo (void) } /* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */ -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr67400-4.c b/gcc/testsuite/gcc.target/i386/pr67400-4.c index a329bbf..5f6883d 100644 --- a/gcc/testsuite/gcc.target/i386/pr67400-4.c +++ b/gcc/testsuite/gcc.target/i386/pr67400-4.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-do compile { target *-*-linux* } } */ /* { dg-options "-O2 -fno-pic -fno-plt" } */ extern void bar (void) __attribute__ ((visibility ("hidden"))); @@ -10,4 +10,5 @@ foo (void) } /* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */ -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr67400-6.c b/gcc/testsuite/gcc.target/i386/pr67400-6.c index bb766cd..652add4 100644 --- a/gcc/testsuite/gcc.target/i386/pr67400-6.c +++ b/gcc/testsuite/gcc.target/i386/pr67400-6.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-do compile { target *-*-linux* } } */ /* { dg-options "-O2 -fno-pic -fno-plt" } */ extern int bar (void); @@ -9,5 +9,7 @@ check (void *p) return p != &bar; } -/* { dg-final { scan-assembler "cmp\(l|q\)\[ \t\]*.*bar@GOTPCREL" } } */ -/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," } } */ +/* { dg-final { scan-assembler "cmp\(l|q\)\[ \t\]*.*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr67400-7.c b/gcc/testsuite/gcc.target/i386/pr67400-7.c index 32ae85f..900e87a 100644 --- a/gcc/testsuite/gcc.target/i386/pr67400-7.c +++ b/gcc/testsuite/gcc.target/i386/pr67400-7.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-do compile { target *-*-linux* } } */ /* { dg-options "-O2 -fno-pic -fno-plt" } */ extern void bar (void); @@ -9,5 +9,5 @@ foo (void) return &bar+1; } -/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */ -/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," } } */ +/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 1b1d03a..0b9b507 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -6975,6 +6975,57 @@ proc check_effective_target_pie_copyreloc { } { return $pie_copyreloc_available_saved } +# Return 1 if the x86 target supports R_386_GOT32X relocation, 0 +# otherwise. Cache the result. + +proc check_effective_target_got32x_reloc { } { + global got32x_reloc_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 got32x_reloc_available_saved] { + verbose "check_effective_target_got32x_reloc returning saved $got32x_reloc_available_saved" 2 + } else { + # Include the current process ID in the file names to prevent + # conflicts with invocations for multiple testsuites. + + set src got32x[pid].c + set obj got32x[pid].o + + set f [open $src "w"] + puts $f "#include \"../../auto-host.h\"" + puts $f "#if HAVE_LD_IX86_GOT32X_RELOC == 0" + puts $f "# error Assembler does not support R_386_GOT32X." + puts $f "#endif" + close $f + + verbose "check_effective_target_got32x_reloc 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_got32x_reloc testfile compilation passed" 2 + set got32x_reloc_available_saved 1 + } else { + verbose "check_effective_target_got32x_reloc testfile compilation failed" 2 + set got32x_reloc_available_saved 0 + } + } + + return $got32x_reloc_available_saved +} + # Return 1 if the target uses comdat groups. proc check_effective_target_comdat_group {} {