diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/i386/i386-expand.c | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 25 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 5 | ||||
-rw-r--r-- | gcc/doc/tm.texi.in | 2 | ||||
-rw-r--r-- | gcc/target.def | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr83782-1.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr83782-2.c | 26 | ||||
-rw-r--r-- | gcc/varasm.c | 3 |
9 files changed, 95 insertions, 3 deletions
diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index cba2880..068c5c2 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -9133,7 +9133,7 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, it an indirect call. */ if (flag_pic && GET_CODE (addr) == SYMBOL_REF - && !SYMBOL_REF_LOCAL_P (addr)) + && ix86_call_use_plt_p (addr)) { if (flag_plt && (SYMBOL_REF_DECL (addr) == NULL_TREE diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 1cd2197..7ffb408 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -152,6 +152,7 @@ extern void ix86_expand_sse_movcc (rtx, rtx, rtx, rtx); extern void ix86_expand_sse_unpack (rtx, rtx, bool, bool); extern bool ix86_expand_int_addcc (rtx[]); extern rtx_insn *ix86_expand_call (rtx, rtx, rtx, rtx, rtx, bool); +extern bool ix86_call_use_plt_p (rtx); extern void ix86_split_call_vzeroupper (rtx, rtx); extern void x86_initialize_trampoline (rtx, rtx, rtx); extern rtx ix86_zero_extend_to_Pmode (rtx); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 80fee62..ccb57af 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -12150,7 +12150,7 @@ output_pic_addr_const (FILE *file, rtx x, int code) assemble_name (file, name); } if (!TARGET_MACHO && !(TARGET_64BIT && TARGET_PECOFF) - && code == 'P' && ! SYMBOL_REF_LOCAL_P (x)) + && code == 'P' && ix86_call_use_plt_p (x)) fputs ("@PLT", file); break; @@ -15980,6 +15980,26 @@ ix86_zero_extend_to_Pmode (rtx exp) return force_reg (Pmode, convert_to_mode (Pmode, exp, 1)); } +/* Return true if the function is called via PLT. */ + +bool +ix86_call_use_plt_p (rtx call_op) +{ + if (SYMBOL_REF_LOCAL_P (call_op)) + { + if (SYMBOL_REF_DECL (call_op)) + { + /* NB: All ifunc functions must be called via PLT. */ + cgraph_node *node + = cgraph_node::get (SYMBOL_REF_DECL (call_op)); + if (node && node->ifunc_resolver) + return true; + } + return false; + } + return true; +} + /* Return true if the function being called was marked with attribute "noplt" or using -fno-plt and we are compiling for non-PIC. We need to handle the non-PIC case in the backend because there is no easy @@ -24582,6 +24602,9 @@ ix86_libgcc_floating_mode_supported_p #define TARGET_GET_MULTILIB_ABI_NAME \ ix86_get_multilib_abi_name +#undef TARGET_IFUNC_REF_LOCAL_OK +#define TARGET_IFUNC_REF_LOCAL_OK hook_bool_void_true + static bool ix86_libc_has_fast_function (int fcode ATTRIBUTE_UNUSED) { #ifdef OPTION_GLIBC diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 6ec1d50..78cc1a2 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -12359,6 +12359,11 @@ The support includes the assembler, linker and dynamic linker. The default value of this hook is based on target's libc. @end deftypefn +@deftypefn {Target Hook} bool TARGET_IFUNC_REF_LOCAL_OK (void) +Return true if it is OK to reference indirect function resolvers +locally. The default is to return false. +@end deftypefn + @deftypefn {Target Hook} {unsigned int} TARGET_ATOMIC_ALIGN_FOR_MODE (machine_mode @var{mode}) If defined, this function returns an appropriate alignment in bits for an atomic object of machine_mode @var{mode}. If 0 is returned then the diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 2b9960b..50c4fe6 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -8098,6 +8098,8 @@ and the associated definitions of those functions. @hook TARGET_HAS_IFUNC_P +@hook TARGET_IFUNC_REF_LOCAL_OK + @hook TARGET_ATOMIC_ALIGN_FOR_MODE @hook TARGET_ATOMIC_ASSIGN_EXPAND_FENV diff --git a/gcc/target.def b/gcc/target.def index b803c58..2f0ae55 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -2979,6 +2979,14 @@ The default value of this hook is based on target's libc.", bool, (void), default_has_ifunc_p) +/* True if it is OK to reference indirect function resolvers locally. */ +DEFHOOK +(ifunc_ref_local_ok, + "Return true if it is OK to reference indirect function resolvers\n\ +locally. The default is to return false.", + bool, (void), + hook_bool_void_false) + /* True if it is OK to do sibling call optimization for the specified call expression EXP. DECL will be the called function, or NULL if this is an indirect call. */ diff --git a/gcc/testsuite/gcc.target/i386/pr83782-1.c b/gcc/testsuite/gcc.target/i386/pr83782-1.c new file mode 100644 index 0000000..f4c7370 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr83782-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O2 -fpic" } */ + +static void +my_foo (void) +{ +} + +static void (*resolve_foo (void)) (void) +{ + return my_foo; +} + +extern void foo (void) __attribute__((ifunc("resolve_foo"), visibility("hidden"))); + +void * +bar(void) +{ + return foo; +} + +/* { dg-final { scan-assembler {leal[ \t]foo@GOTOFF\(%[^,]*\),[ \t]%eax} { target ia32 } } } */ +/* { dg-final { scan-assembler {leaq[ \t]foo\(%rip\),[ \t]%rax} { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "foo@GOT\\\(" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "foo@GOTPCREL\\\(" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr83782-2.c b/gcc/testsuite/gcc.target/i386/pr83782-2.c new file mode 100644 index 0000000..6c6528f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr83782-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O2 -fpic" } */ + +static void +my_foo (void) +{ +} + +static void (*resolve_foo (void)) (void) +{ + return my_foo; +} + +static void foo (void) __attribute__((ifunc("resolve_foo"))); + +void * +bar(void) +{ + return foo; +} + +/* { dg-final { scan-assembler {leal[ \t]foo@GOTOFF\(%[^,]*\),[ \t]%eax} { target ia32 } } } */ +/* { dg-final { scan-assembler {leaq[ \t]foo\(%rip\),[ \t]%rax} { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "foo@GOT\\\(" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "foo@GOTPCREL\\\(" { target { ! ia32 } } } } */ diff --git a/gcc/varasm.c b/gcc/varasm.c index aff93ca..5da3b8f 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -7474,7 +7474,8 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, FIXME: We can resolve the weakref case more curefuly by looking at the weakref alias. */ if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)) - || (TREE_CODE (exp) == FUNCTION_DECL + || (!targetm.ifunc_ref_local_ok () + && TREE_CODE (exp) == FUNCTION_DECL && cgraph_node::get (exp) && cgraph_node::get (exp)->ifunc_resolver)) return false; |