]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add TARGET_IFUNC_REF_LOCAL_OK
authorH.J. Lu <hjl.tools@gmail.com>
Sat, 19 Jun 2021 15:16:45 +0000 (08:16 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Fri, 3 Dec 2021 13:12:30 +0000 (05:12 -0800)
1. On some targets, like PowerPC, reference to ifunc function resolver
must be non-local so that compiler will properly emit PLT call.  Add
TARGET_IFUNC_REF_LOCAL_OK to allow binding indirect function resolver
locally for targets which don't require special PLT call sequence.
2. Add ix86_call_use_plt_p to call local ifunc function resolvers via
PLT.

gcc/

PR target/51469
PR target/83782
* target.def (ifunc_ref_local_ok): Add a target hook.
* varasm.c (default_binds_local_p_3): Force indirect function
resolver non-local only if targetm.ifunc_ref_local_ok returns
false.
* config/i386/i386-expand.c (ix86_expand_call): Call
ix86_call_use_plt_p to check if PLT should be used.
* config/i386/i386-protos.h (ix86_call_use_plt_p): New.
* config/i386/i386.c (output_pic_addr_const): Call
ix86_call_use_plt_p to check if "@PLT" is needed.
(ix86_call_use_plt_p): New.
(TARGET_IFUNC_REF_LOCAL_OK): New.
* doc/tm.texi.in: Add TARGET_IFUNC_REF_LOCAL_OK.
* doc/tm.texi: Regenerated.

gcc/testsuite/

PR target/51469
PR target/83782
* gcc.target/i386/pr83782-1.c: New test.
* gcc.target/i386/pr83782-2.c: Likewise.

gcc/config/i386/i386-expand.c
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/target.def
gcc/testsuite/gcc.target/i386/pr83782-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr83782-2.c [new file with mode: 0644]
gcc/varasm.c

index cba2880dc8d0d8ba8a4fee995d5a1ad20c22b384..068c5c23358a8a256bbf80ffcfccf04538c3d475 100644 (file)
@@ -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
index 1cd219798e32fda6a0390bb114dc81976c4b6a76..7ffb4089a0d895f1cabba405b131e1cf0fd0f768 100644 (file)
@@ -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);
index 80fee627358881bec5749efaed12d7645631c6fd..ccb57afee0521d57e8f7a7ae19fa5ba9027cd8e3 100644 (file)
@@ -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
index 6ec1d50b3e44c823cf242dbcc062a68245e291ef..78cc1a287dd25951ef3169c3fe8ac0531c7fc36b 100644 (file)
@@ -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
index 2b9960b73d70f89d129d2577a9d5446c77cac961..50c4fe62dc7405e20fd9b70044477d36a462975b 100644 (file)
@@ -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
index b803c582f01cb50230556a93711c13c923d86ead..2f0ae55f82e16bfcb7ef1f432e88154c26b9007e 100644 (file)
@@ -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 (file)
index 0000000..f4c7370
--- /dev/null
@@ -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 (file)
index 0000000..6c6528f
--- /dev/null
@@ -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 } } } } */
index aff93ca5de91a5d0b8c2f8fbc27f0142e0594664..5da3b8f6fbb0863fe1a2da2aa7c72627d296abf7 100644 (file)
@@ -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;