Commit e3d62871 by Uros Bizjak

re PR target/67400 (-fno-plt doesn't work with function pointers)

	PR target/67400
	* config/i386/i386-protos.h (ix86_force_load_from_GOT_p): New.
	* config/i386/i386.c (ix86_force_load_from_GOT_p): New function.
	(ix86_legitimate_constant_p): Do not allow UNSPEC_GOTPCREL if
	ix86_force_load_from_GOT_p returns true.
	(ix86_legitimate_address_p): Allow UNSPEC_GOTPCREL if
	ix86_force_load_from_GOT_p returns true.
	(ix86_print_operand_address_as): Support UNSPEC_GOTPCREL if
	ix86_force_load_from_GOT_p returns true.
	(ix86_expand_move): Load the external function address via the
	GOT slot if ix86_force_load_from_GOT_p returns true.
	* config/i386/predicates.md (x86_64_immediate_operand): Return
	false for SYMBOL_REFs where ix86_force_load_from_GOT_p returns true.
	(x86_64_zext_immediate_operand): Ditto.

testsuite/ChangeLog:

	PR target/67400
        * gcc.target/i386/pr67400-1.c: New test.
        * 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-5.c: Likewise.
        * gcc.target/i386/pr67400-6.c: Likewise.
        * gcc.target/i386/pr67400-7.c: Likewise.

From-SVN: r237720
parent 37c467c0
2016-06-23 Uros Bizjak <ubizjak@gmail.com>
H.J. Lu <hongjiu.lu@intel.com>
PR target/67400
* config/i386/i386-protos.h (ix86_force_load_from_GOT_p): New.
* config/i386/i386.c (ix86_force_load_from_GOT_p): New function.
(ix86_legitimate_constant_p): Do not allow UNSPEC_GOTPCREL if
ix86_force_load_from_GOT_p returns true.
(ix86_legitimate_address_p): Allow UNSPEC_GOTPCREL if
ix86_force_load_from_GOT_p returns true.
(ix86_print_operand_address_as): Support UNSPEC_GOTPCREL if
ix86_force_load_from_GOT_p returns true.
(ix86_expand_move): Load the external function address via the
GOT slot if ix86_force_load_from_GOT_p returns true.
* config/i386/predicates.md (x86_64_immediate_operand): Return
false for SYMBOL_REFs where ix86_force_load_from_GOT_p returns true.
(x86_64_zext_immediate_operand): Ditto.
2016-06-22 Uros Bizjak <ubizjak@gmail.com> 2016-06-22 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.c (ix86_expand_move): Simplify SYMBOL_REF handling. * config/i386/i386.c (ix86_expand_move): Simplify SYMBOL_REF handling.
......
...@@ -70,6 +70,7 @@ extern bool ix86_expand_set_or_movmem (rtx, rtx, rtx, rtx, rtx, rtx, ...@@ -70,6 +70,7 @@ extern bool ix86_expand_set_or_movmem (rtx, rtx, rtx, rtx, rtx, rtx,
extern bool constant_address_p (rtx); extern bool constant_address_p (rtx);
extern bool legitimate_pic_operand_p (rtx); extern bool legitimate_pic_operand_p (rtx);
extern bool legitimate_pic_address_disp_p (rtx); extern bool legitimate_pic_address_disp_p (rtx);
extern bool ix86_force_load_from_GOT_p (rtx);
extern void print_reg (rtx, int, FILE*); extern void print_reg (rtx, int, FILE*);
extern void ix86_print_operand (FILE *, rtx, int); extern void ix86_print_operand (FILE *, rtx, int);
......
...@@ -15120,6 +15120,19 @@ darwin_local_data_pic (rtx disp) ...@@ -15120,6 +15120,19 @@ darwin_local_data_pic (rtx disp)
&& XINT (disp, 1) == UNSPEC_MACHOPIC_OFFSET); && XINT (disp, 1) == UNSPEC_MACHOPIC_OFFSET);
} }
/* True if operand X should be loaded from GOT. */
bool
ix86_force_load_from_GOT_p (rtx x)
{
return (TARGET_64BIT && !TARGET_PECOFF && !TARGET_MACHO
&& !flag_plt && !flag_pic
&& ix86_cmodel != CM_LARGE
&& GET_CODE (x) == SYMBOL_REF
&& SYMBOL_REF_FUNCTION_P (x)
&& !SYMBOL_REF_LOCAL_P (x));
}
/* Determine if a given RTX is a valid constant. We already know this /* Determine if a given RTX is a valid constant. We already know this
satisfies CONSTANT_P. */ satisfies CONSTANT_P. */
...@@ -15188,6 +15201,12 @@ ix86_legitimate_constant_p (machine_mode mode, rtx x) ...@@ -15188,6 +15201,12 @@ ix86_legitimate_constant_p (machine_mode mode, rtx x)
if (MACHO_DYNAMIC_NO_PIC_P) if (MACHO_DYNAMIC_NO_PIC_P)
return machopic_symbol_defined_p (x); return machopic_symbol_defined_p (x);
#endif #endif
/* External function address should be loaded
via the GOT slot to avoid PLT. */
if (ix86_force_load_from_GOT_p (x))
return false;
break; break;
CASE_CONST_SCALAR_INT: CASE_CONST_SCALAR_INT:
...@@ -15596,6 +15615,9 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict) ...@@ -15596,6 +15615,9 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict)
return false; return false;
case UNSPEC_GOTPCREL: case UNSPEC_GOTPCREL:
if (ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0)))
goto is_legitimate_pic;
/* FALLTHRU */
case UNSPEC_PCREL: case UNSPEC_PCREL:
gcc_assert (flag_pic); gcc_assert (flag_pic);
goto is_legitimate_pic; goto is_legitimate_pic;
...@@ -18169,6 +18191,12 @@ ix86_print_operand_address_as (FILE *file, rtx addr, ...@@ -18169,6 +18191,12 @@ ix86_print_operand_address_as (FILE *file, rtx addr,
fputs ("ds:", file); fputs ("ds:", file);
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp)); fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
} }
/* 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
&& ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0)))
output_pic_addr_const (file, disp, 0);
else if (flag_pic) else if (flag_pic)
output_pic_addr_const (file, disp, 0); output_pic_addr_const (file, disp, 0);
else else
...@@ -19417,6 +19445,15 @@ ix86_expand_move (machine_mode mode, rtx operands[]) ...@@ -19417,6 +19445,15 @@ ix86_expand_move (machine_mode mode, rtx operands[])
if (model) if (model)
op1 = legitimize_tls_address (op1, model, true); op1 = legitimize_tls_address (op1, model, true);
else if (ix86_force_load_from_GOT_p (op1))
{
/* Load the external function address via GOT slot to avoid PLT. */
op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op1),
UNSPEC_GOTPCREL);
op1 = gen_rtx_CONST (Pmode, op1);
op1 = gen_const_mem (Pmode, op1);
set_mem_alias_set (op1, ix86_GOT_alias_set ());
}
else else
{ {
tmp = legitimize_pe_coff_symbol (op1, addend != NULL_RTX); tmp = legitimize_pe_coff_symbol (op1, addend != NULL_RTX);
...@@ -160,13 +160,18 @@ ...@@ -160,13 +160,18 @@
return trunc_int_for_mode (val, SImode) == val; return trunc_int_for_mode (val, SImode) == val;
} }
case SYMBOL_REF: case SYMBOL_REF:
/* TLS symbols are not constant. */
if (SYMBOL_REF_TLS_MODEL (op))
return false;
/* Load the external function address via the GOT slot. */
if (ix86_force_load_from_GOT_p (op))
return false;
/* For certain code models, the symbolic references are known to fit. /* For certain code models, the symbolic references are known to fit.
in CM_SMALL_PIC model we know it fits if it is local to the shared in CM_SMALL_PIC model we know it fits if it is local to the shared
library. Don't count TLS SYMBOL_REFs here, since they should fit library. Don't count TLS SYMBOL_REFs here, since they should fit
only if inside of UNSPEC handled below. */ only if inside of UNSPEC handled below. */
/* TLS symbols are not constant. */
if (SYMBOL_REF_TLS_MODEL (op))
return false;
return (ix86_cmodel == CM_SMALL || ix86_cmodel == CM_KERNEL return (ix86_cmodel == CM_SMALL || ix86_cmodel == CM_KERNEL
|| (ix86_cmodel == CM_MEDIUM && !SYMBOL_REF_FAR_ADDR_P (op))); || (ix86_cmodel == CM_MEDIUM && !SYMBOL_REF_FAR_ADDR_P (op)));
...@@ -207,6 +212,11 @@ ...@@ -207,6 +212,11 @@
/* TLS symbols are not constant. */ /* TLS symbols are not constant. */
if (SYMBOL_REF_TLS_MODEL (op1)) if (SYMBOL_REF_TLS_MODEL (op1))
return false; return false;
/* Load the external function address via the GOT slot. */
if (ix86_force_load_from_GOT_p (op1))
return false;
/* For CM_SMALL assume that latest object is 16MB before /* For CM_SMALL assume that latest object is 16MB before
end of 31bits boundary. We may also accept pretty end of 31bits boundary. We may also accept pretty
large negative constants knowing that all objects are large negative constants knowing that all objects are
...@@ -273,10 +283,15 @@ ...@@ -273,10 +283,15 @@
return !(INTVAL (op) & ~(HOST_WIDE_INT) 0xffffffff); return !(INTVAL (op) & ~(HOST_WIDE_INT) 0xffffffff);
case SYMBOL_REF: case SYMBOL_REF:
/* For certain code models, the symbolic references are known to fit. */
/* TLS symbols are not constant. */ /* TLS symbols are not constant. */
if (SYMBOL_REF_TLS_MODEL (op)) if (SYMBOL_REF_TLS_MODEL (op))
return false; return false;
/* Load the external function address via the GOT slot. */
if (ix86_force_load_from_GOT_p (op))
return false;
/* For certain code models, the symbolic references are known to fit. */
return (ix86_cmodel == CM_SMALL return (ix86_cmodel == CM_SMALL
|| (ix86_cmodel == CM_MEDIUM || (ix86_cmodel == CM_MEDIUM
&& !SYMBOL_REF_FAR_ADDR_P (op))); && !SYMBOL_REF_FAR_ADDR_P (op)));
...@@ -301,6 +316,11 @@ ...@@ -301,6 +316,11 @@
/* TLS symbols are not constant. */ /* TLS symbols are not constant. */
if (SYMBOL_REF_TLS_MODEL (op1)) if (SYMBOL_REF_TLS_MODEL (op1))
return false; return false;
/* Load the external function address via the GOT slot. */
if (ix86_force_load_from_GOT_p (op1))
return false;
/* For small code model we may accept pretty large positive /* For small code model we may accept pretty large positive
offsets, since one bit is available for free. Negative offsets, since one bit is available for free. Negative
offsets are limited by the size of NULL pointer area offsets are limited by the size of NULL pointer area
......
2016-06-23 H.J. Lu <hongjiu.lu@intel.com>
PR target/67400
* gcc.target/i386/pr67400-1.c: New test.
* 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-5.c: Likewise.
* gcc.target/i386/pr67400-6.c: Likewise.
* gcc.target/i386/pr67400-7.c: Likewise.
2016-06-22 David Malcolm <dmalcolm@redhat.com> 2016-06-22 David Malcolm <dmalcolm@redhat.com>
* c-c++-common/missing-header-1.c: New test case. * c-c++-common/missing-header-1.c: New test case.
...@@ -355,7 +366,7 @@ ...@@ -355,7 +366,7 @@
2016-06-15 Uros Bizjak <ubizjak@gmail.com> 2016-06-15 Uros Bizjak <ubizjak@gmail.com>
* gcc.dg/torture/float128-nan.c: Include stdint.h to define uint64_t. * gcc.dg/torture/float128-nan.c: Include stdint.h to define uint64_t.
2016-06-15 Alan Hayward <alan.hayward@arm.com> 2016-06-15 Alan Hayward <alan.hayward@arm.com>
...@@ -394,10 +405,10 @@ ...@@ -394,10 +405,10 @@
2016-06-14 Uros Bizjak <ubizjak@gmail.com> 2016-06-14 Uros Bizjak <ubizjak@gmail.com>
* gcc.target/i386/float128-3.c: New test. * gcc.target/i386/float128-3.c: New test.
* gcc.target/i386/quad-sse4.c: Ditto. * gcc.target/i386/quad-sse4.c: Ditto.
* gcc.target/i386/quad-sse.c: Use -msse instead of -msse2. * gcc.target/i386/quad-sse.c: Use -msse instead of -msse2.
Update scan strings. Update scan strings.
2016-06-14 Richard Biener <rguenther@suse.de> 2016-06-14 Richard Biener <rguenther@suse.de>
......
/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
/* { dg-options "-O2 -fno-pic -fno-plt" } */
extern void bar (void);
void *
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-do compile { target { *-*-linux* && { ! ia32 } } } } */
/* { dg-options "-O2 -fno-pic -fno-plt" } */
extern void bar (void);
extern void *p;
void
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-do compile { target { *-*-linux* && { ! ia32 } } } } */
/* { dg-options "-O2 -fno-pic -fno-plt" } */
static void
bar (void)
{
}
void *
foo (void)
{
return &bar;
}
/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */
/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */
/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
/* { dg-options "-O2 -fno-pic -fno-plt" } */
extern void bar (void) __attribute__ ((visibility ("hidden")));
void *
foo (void)
{
return &bar;
}
/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */
/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */
/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
/* { dg-options "-O2 -fno-pic -fno-plt" } */
extern void foo (void);
extern void bar (int, int, int, int, int, int, void *);
void
x (void)
{
bar (1, 2, 3, 4, 5, 6, foo);
}
/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
/* { dg-options "-O2 -fno-pic -fno-plt" } */
extern int bar (void);
int
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-do compile { target { *-*-linux* && { ! ia32 } } } } */
/* { dg-options "-O2 -fno-pic -fno-plt" } */
extern void bar (void);
void *
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," } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment