aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/i386/i386-expand.c2
-rw-r--r--gcc/config/i386/i386-protos.h1
-rw-r--r--gcc/config/i386/i386.c25
-rw-r--r--gcc/doc/tm.texi5
-rw-r--r--gcc/doc/tm.texi.in2
-rw-r--r--gcc/target.def8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr83782-1.c26
-rw-r--r--gcc/testsuite/gcc.target/i386/pr83782-2.c26
-rw-r--r--gcc/varasm.c3
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;