]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
configure.ac (gnu_indirect_function): New test.
authorNathan Sidwell <nathan@codesourcery.com>
Thu, 9 Sep 2010 14:12:57 +0000 (14:12 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Thu, 9 Sep 2010 14:12:57 +0000 (14:12 +0000)
* configure.ac (gnu_indirect_function): New test.
* configure: Rebuilt.
* config.in (HAVE_GAS_INDIRECT_FUNCTION): New.
* defaults.h (IFUNC_ASM_TYPE): Provide default.

* doc/extend.texi (Function Attributes): Document ifunc.
* varasm.c (do_assemble_alias): Deal with ifuncs too.

c-family/
* c-common.c (handle_alias_ifunc_attribute): New, broken out of ...
(handle_alias_attribute): ... here.
(handle_ifunc_attribute): New.

testsuite/
* lib/target-supports-dg.exp (dg-require-ifunc): New.
* lib/target-supports.exp (check_ifunc_available): New.
* gcc.dg/attr-ifunc-1.c: New.
* gcc.dg/attr-ifunc-2.c: New.
* gcc.dg/attr-ifunc-3.c: New.
* gcc.dg/attr-ifunc-4.c: New.
* gcc.dg/attr-ifunc-5.c: New.
* testsuite/g++.dg/ext/attr-ifunc-1.C
* testsuite/g++.dg/ext/attr-ifunc-2.C
* testsuite/g++.dg/ext/attr-ifunc-3.C
* testsuite/g++.dg/ext/attr-ifunc-4.C

From-SVN: r164110

21 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/config.in
gcc/configure
gcc/configure.ac
gcc/defaults.h
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/attr-ifunc-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-ifunc-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-ifunc-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-ifunc-4.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-ifunc-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-ifunc-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-ifunc-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-ifunc-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-ifunc-5.c [new file with mode: 0644]
gcc/testsuite/lib/target-supports-dg.exp
gcc/testsuite/lib/target-supports.exp
gcc/varasm.c

index 5aeade6683039c99823c2cfbcc782bc4ff3e267e..c8bce534ca70544eb0bec1acfca2b036ab5a7fac 100644 (file)
@@ -1,3 +1,13 @@
+2010-09-09  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * configure.ac (gnu_indirect_function): New test.
+       * configure: Rebuilt.
+       * config.in (HAVE_GAS_INDIRECT_FUNCTION): New.
+       * defaults.h (IFUNC_ASM_TYPE): Provide default.
+
+       * doc/extend.texi (Function Attributes): Document ifunc.
+       * varasm.c (do_assemble_alias): Deal with ifuncs too.
+
 2010-09-09  Hariharan Sandanagobalane <hariharan@picochip.com>
 
        * config/picochip/picochip.c (picochip_reorg): Check for note_p for
index 50c4ea14aac2bf63c9c6790c6eb11b1d932a9449..6d3b024c4c08a1de89d0cdff2ef08a77280604a8 100644 (file)
@@ -1,3 +1,9 @@
+2010-09-09  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * c-common.c (handle_alias_ifunc_attribute): New, broken out of ...
+       (handle_alias_attribute): ... here.
+       (handle_ifunc_attribute): New.
+
 2010-09-06  Mark Mitchell  <mark@codesourcery.com>
 
        * c-common.h (do_warn_double_promotion): Declare.
index 48c67b4bcd46ecaeffa102eb4224c97b62cc00fa..a3a332bb270b17dd5860841a821dbd21c957f62f 100644 (file)
@@ -327,6 +327,8 @@ static tree handle_mode_attribute (tree *, tree, tree, int, bool *);
 static tree handle_section_attribute (tree *, tree, tree, int, bool *);
 static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
 static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
+static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
+static tree handle_ifunc_attribute (tree *, tree, tree, int, bool *);
 static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
 static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_visibility_attribute (tree *, tree, tree, int,
@@ -599,6 +601,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_aligned_attribute },
   { "weak",                   0, 0, true,  false, false,
                              handle_weak_attribute },
+  { "ifunc",                  1, 1, true,  false, false,
+                             handle_ifunc_attribute },
   { "alias",                  1, 1, true,  false, false,
                              handle_alias_attribute },
   { "weakref",                0, 1, true,  false, false,
@@ -6595,6 +6599,12 @@ handle_weak_attribute (tree *node, tree name,
       error ("inline function %q+D cannot be declared weak", *node);
       *no_add_attrs = true;
     }
+  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
+    {
+      error ("indirect function %q+D cannot be declared weak", *node);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
   else if (TREE_CODE (*node) == FUNCTION_DECL
           || TREE_CODE (*node) == VAR_DECL)
     declare_weak (*node);
@@ -6604,16 +6614,18 @@ handle_weak_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
-/* Handle an "alias" attribute; arguments as in
-   struct attribute_spec.handler.  */
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+   struct attribute_spec.handler, except that IS_ALIAS tells us
+   whether this is an alias as opposed to ifunc attribute.  */
 
 static tree
-handle_alias_attribute (tree *node, tree name, tree args,
-                       int ARG_UNUSED (flags), bool *no_add_attrs)
+handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
+                             bool *no_add_attrs)
 {
   tree decl = *node;
 
-  if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
+  if (TREE_CODE (decl) != FUNCTION_DECL
+      && (!is_alias || TREE_CODE (decl) != VAR_DECL))
     {
       warning (OPT_Wattributes, "%qE attribute ignored", name);
       *no_add_attrs = true;
@@ -6626,9 +6638,18 @@ handle_alias_attribute (tree *node, tree name, tree args,
       || (TREE_CODE (decl) != FUNCTION_DECL
          && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
     {
-      error ("%q+D defined both normally and as an alias", decl);
+      error ("%q+D defined both normally and as %qE attribute", decl, name);
       *no_add_attrs = true;
+      return NULL_TREE;
     }
+  else if (!is_alias
+          && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl)) 
+              || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
+    {
+      error ("weak %q+D cannot be defined %qE", decl, name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }                   
 
   /* Note that the very first time we process a nested declaration,
      decl_function_context will not be set.  Indeed, *would* never
@@ -6642,7 +6663,7 @@ handle_alias_attribute (tree *node, tree name, tree args,
       id = TREE_VALUE (args);
       if (TREE_CODE (id) != STRING_CST)
        {
-         error ("alias argument not a string");
+         error ("attribute %qE argument not a string", name);
          *no_add_attrs = true;
          return NULL_TREE;
        }
@@ -6660,6 +6681,11 @@ handle_alias_attribute (tree *node, tree name, tree args,
            DECL_EXTERNAL (decl) = 0;
          TREE_STATIC (decl) = 1;
        }
+
+      if (!is_alias)
+       /* ifuncs are also aliases, so set that attribute too. */
+       DECL_ATTRIBUTES (decl)
+         = tree_cons (get_identifier ("alias"), args, DECL_ATTRIBUTES (decl));
     }
   else
     {
@@ -6670,6 +6696,26 @@ handle_alias_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_ifunc_attribute (tree *node, tree name, tree args,
+                       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  return handle_alias_ifunc_attribute (false, node, name, args, no_add_attrs);
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_alias_attribute (tree *node, tree name, tree args,
+                       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
+}
+
 /* Handle a "weakref" attribute; arguments as in struct
    attribute_spec.handler.  */
 
@@ -6691,6 +6737,13 @@ handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       return NULL_TREE;
     }
 
+  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
+    {
+      error ("indirect function %q+D cannot be declared weakref", *node);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
   /* The idea here is that `weakref("name")' mutates into `weakref,
      alias("name")', and weakref without arguments, in turn,
      implicitly adds weak. */
index c451c5378e0549188e1fe6cea01be049fe3be81f..a03b65309dcfe1a7cbad6c8747e027ce86b7be09 100644 (file)
 /* Define if your assembler and linker support .hidden. */
 #undef HAVE_GAS_HIDDEN
 
+/* Define if your assembler supports indirect function type. */
+#undef HAVE_GAS_INDIRECT_FUNCTION
+
 /* Define if your assembler supports .lcomm with an alignment field. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GAS_LCOMM_WITH_ALIGNMENT
index 240a8765b7979d019f2ebef9e53b9836fb2181e2..ebbead293e35f3f887e8bc930efb5595351fec8f 100755 (executable)
 $as_echo "$gcc_cv_as_hidden" >&6; }
 
 
+# gnu_indirect_function type is an extension proposed at
+# http://groups.google/com/group/generic-abi/files. It allows dynamic runtime
+# selection of function implementation
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for gnu_indirect_function" >&5
+$as_echo_n "checking assembler for gnu_indirect_function... " >&6; }
+if test "${gcc_cv_as_indirect_function+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_indirect_function=no
+    if test $in_tree_gas = yes; then
+    if test $in_tree_gas_is_elf = yes \
+  && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 20 \) \* 1000 + 1`
+  then gcc_cv_as_indirect_function=yes
+fi
+  elif test x$gcc_cv_as != x; then
+    echo '     .type  Foo, @gnu_indirect_function
+Foo:' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+       gcc_cv_as_indirect_function=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_indirect_function" >&5
+$as_echo "$gcc_cv_as_indirect_function" >&6; }
+
+
+if test $gcc_cv_as_indirect_function = yes ; then
+
+$as_echo "#define HAVE_GAS_INDIRECT_FUNCTION 1" >>confdefs.h
+
+fi
+
 if test $in_tree_ld != yes ; then
   ld_ver=`$gcc_cv_ld --version 2>/dev/null | sed 1q`
   if test x"$ld_is_gold" = xyes; then
index 75cded6c79138e90c2c0b85eea635a2b2add18e8..e39ab87542c9ab98b38ef93f482bbd694206bbf6 100644 (file)
@@ -2158,6 +2158,19 @@ EOF
     ;;
 esac])
 
+# gnu_indirect_function type is an extension proposed at
+# http://groups.google/com/group/generic-abi/files. It allows dynamic runtime
+# selection of function implementation
+gcc_GAS_CHECK_FEATURE(gnu_indirect_function, gcc_cv_as_indirect_function,
+ [elf,2,20,1],,
+[      .type  Foo, @gnu_indirect_function
+Foo:])
+GCC_TARGET_TEMPLATE([HAVE_GAS_INDIRECT_FUNCTION])
+if test $gcc_cv_as_indirect_function = yes ; then
+  AC_DEFINE(HAVE_GAS_INDIRECT_FUNCTION, 1,
+  [Define if your assembler supports indirect function type.])
+fi
+
 changequote(,)dnl
 if test $in_tree_ld != yes ; then
   ld_ver=`$gcc_cv_ld --version 2>/dev/null | sed 1q`
index e30ec17f26b2b176ac240659e3b085c3e916f04a..62b8228247cc04e9ec5bf788ee67ff815307d9f4 100644 (file)
@@ -142,6 +142,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #endif
 #endif
 
+#ifndef IFUNC_ASM_TYPE
+#define IFUNC_ASM_TYPE "gnu_indirect_function"
+#endif
+
 #ifndef TLS_COMMON_ASM_OP
 #define TLS_COMMON_ASM_OP ".tls_common"
 #endif
index de6a30dd6927a51148d1094d4f2ff7115390cf5c..4f2cc07710116d60550468e3be9fc7dd30e0e09d 100644 (file)
@@ -1912,6 +1912,7 @@ the enclosing block.
 @cindex functions that do not pop the argument stack on the 386
 @cindex functions that have different compilation options on the 386
 @cindex functions that have different optimization options
+@cindex functions that are dynamically resolved
 
 In GNU C, you declare certain things about functions called in your program
 which help the compiler optimize function calls and check your code more
@@ -1927,13 +1928,13 @@ attributes are currently defined for functions on all targets:
 @code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg},
 @code{no_instrument_function}, @code{section}, @code{constructor},
 @code{destructor}, @code{used}, @code{unused}, @code{deprecated},
-@code{weak}, @code{malloc}, @code{alias}, @code{warn_unused_result},
-@code{nonnull}, @code{gnu_inline}, @code{externally_visible},
-@code{hot}, @code{cold}, @code{artificial}, @code{error} and
-@code{warning}.  Several other attributes are defined for functions on
-particular target systems.  Other attributes, including @code{section}
-are supported for variables declarations (@pxref{Variable Attributes})
-and for types (@pxref{Type Attributes}).
+@code{weak}, @code{malloc}, @code{alias}, @code{ifunc},
+@code{warn_unused_result}, @code{nonnull}, @code{gnu_inline},
+@code{externally_visible}, @code{hot}, @code{cold}, @code{artificial},
+@code{error} and @code{warning}.  Several other attributes are defined
+for functions on particular target systems.  Other attributes,
+including @code{section} are supported for variables declarations
+(@pxref{Variable Attributes}) and for types (@pxref{Type Attributes}).
 
 GCC plugins may provide their own attributes.
 
@@ -2585,6 +2586,51 @@ void __attribute__ ((interrupt, use_shadow_register_set,
                      use_debug_exception_return)) v7 ();
 @end smallexample
 
+@item ifunc ("@var{resolver}")
+@cindex @code{ifunc} attribute
+The @code{ifunc} attribute is used to mark a function as an indirect
+function using the STT_GNU_IFUNC symbol type extension to the ELF
+standard.  This allows the resolution of the symbol value to be
+determined dynamically at load time, and an optimized version of the
+routine can be selected for the particular processor or other system
+characteristics determined then.  To use this attribute, first define
+the implementation functions available, and a resolver function that
+returns a pointer to the selected implementation function.  The
+implementation functions' declarations must match the API of the
+function being implemented, the resolver's declaration is be a
+function returning pointer to void function returning void:
+
+@smallexample
+void *my_memcpy (void *dst, const void *src, size_t len)
+@{
+  @dots{}
+@}
+
+static void (*resolve_memcpy (void)) (void)
+@{
+  return my_memcpy; // we'll just always select this routine
+@}
+@end smallexample
+
+The exported header file declaring the function the user calls would
+contain:
+
+@smallexample
+extern void *memcpy (void *, const void *, size_t);
+@end smallexample
+
+allowing the user to call this as a regular function, unaware of the
+implementation.  Finally, the indirect function needs to be defined in
+the same translation unit as the resolver function:
+
+@smallexample
+void *memcpy (void *, const void *, size_t)
+     __attribute__ ((ifunc ("resolve_memcpy")));
+@end smallexample
+
+Indirect functions cannot be weak, and require a recent binutils (at
+least version 2.20.1), and GNU C library (at least version 2.11.1).
+
 @item interrupt_handler
 @cindex interrupt handler functions on the Blackfin, m68k, H8/300 and SH processors
 Use this attribute on the Blackfin, m68k, H8/300, H8/300H, H8S, and SH to
index cf6aa57d6152aae2e1b119f4fad69fdd35eec73b..c252a1fbd3cb1f493429c40da18f2344e6340534 100644 (file)
@@ -1,3 +1,17 @@
+2010-09-09  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * lib/target-supports-dg.exp (dg-require-ifunc): New.
+       * lib/target-supports.exp (check_ifunc_available): New.
+       * gcc.dg/attr-ifunc-1.c: New.
+       * gcc.dg/attr-ifunc-2.c: New.
+       * gcc.dg/attr-ifunc-3.c: New.
+       * gcc.dg/attr-ifunc-4.c: New.
+       * gcc.dg/attr-ifunc-5.c: New.
+       * testsuite/g++.dg/ext/attr-ifunc-1.C: New.
+       * testsuite/g++.dg/ext/attr-ifunc-2.C: New.
+       * testsuite/g++.dg/ext/attr-ifunc-3.C: New.
+       * testsuite/g++.dg/ext/attr-ifunc-4.C: New.
+
 2010-09-09  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR middle-end/40386
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
new file mode 100644 (file)
index 0000000..d41fa7d
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-Wno-pmf-conversions" } */
+
+#include <stdio.h>
+
+struct Klass
+{
+  int implementation ();
+  int magic ();
+  static void *resolver ();
+};
+
+int Klass::implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+void *Klass::resolver (void)
+{
+  int (Klass::*pmf) () = &Klass::implementation;
+  
+  return (void *)(int (*)(Klass *))(((Klass *)0)->*pmf);
+}
+
+int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
+
+int main ()
+{
+  Klass obj;
+  
+  return obj.magic () != 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
new file mode 100644 (file)
index 0000000..e205a2a
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-Wno-pmf-conversions" } */
+
+#include <stdio.h>
+
+struct Klass
+{
+  int implementation ();
+  int magic ();
+  static void *resolver ();
+};
+
+int Klass::implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+void *Klass::resolver (void)
+{
+  int (Klass::*pmf) () = &Klass::implementation;
+  
+  return (void *)(int (*)(Klass *))(((Klass *)0)->*pmf);
+}
+
+int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
+
+struct Klassier : Klass
+{
+};
+
+int main ()
+{
+  Klassier obj;
+  
+  return obj.magic () != 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
new file mode 100644 (file)
index 0000000..ba65976
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-Wno-pmf-conversions" } */
+
+#include <stdio.h>
+
+struct Klass
+{
+  int implementation ();
+  int magic ();
+  static void *resolver ();
+};
+
+int Klass::implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+void *Klass::resolver (void)
+{
+  int (Klass::*pmf) () = &Klass::implementation;
+  
+  return (void *)(int (*)(Klass *))(((Klass *)0)->*pmf);
+}
+
+int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
+
+int Foo (Klass &obj, int (Klass::*pmf) ())
+{
+  return (obj.*pmf) ();
+}
+
+int main ()
+{
+  Klass obj;
+  
+  return Foo (obj, &Klass::magic) != 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
new file mode 100644 (file)
index 0000000..0cae410
--- /dev/null
@@ -0,0 +1,44 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-Wno-pmf-conversions" } */
+
+#include <stdio.h>
+
+struct Klass
+{
+  virtual int magic () = 0;
+};
+
+struct Klassier : Klass
+{
+  int implementation ();
+  int magic ();
+  static void *resolver ();
+};
+
+int Klassier::implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+void *Klassier::resolver (void)
+{
+  int (Klassier::*pmf) () = &Klassier::implementation;
+  
+  return (void *)(int (*)(Klassier *))(((Klassier *)0)->*pmf);
+}
+
+int Klassier::magic (void) __attribute__ ((ifunc ("_ZN8Klassier8resolverEv")));
+
+int __attribute__ ((weak)) Foo (Klass &base)
+{
+  return base.magic ();
+}
+
+int main ()
+{
+  Klassier obj;
+  
+  return Foo (obj) != 0;
+}
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-1.c b/gcc/testsuite/gcc.dg/attr-ifunc-1.c
new file mode 100644 (file)
index 0000000..f9c6482
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "" } */
+
+#include <stdio.h>
+
+static int implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+static void *resolver (void)
+{
+  return (void *)implementation;
+}
+
+extern int magic (void) __attribute__ ((ifunc ("resolver")));
+
+int main ()
+{
+  return magic () != 0;
+}
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-2.c b/gcc/testsuite/gcc.dg/attr-ifunc-2.c
new file mode 100644 (file)
index 0000000..f717315
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-require-ifunc "" } */
+
+static void *resolver ()
+{
+  return 0;
+}
+
+extern int magic (void)  /* { dg-message "previous definition" } */
+     __attribute__ ((ifunc ("resolver")));
+extern int magic (void)  /* { dg-error "redefinition" "" } */
+     __attribute__ ((alias ("resolver")));
+
+extern int spell (void)  /* { dg-message "previous definition" } */
+{
+  return 0;
+}
+extern int spell (void)  /* { dg-error "redefinition" "" } */
+     __attribute__ ((ifunc ("resolver")));
+
+extern int mantra (void)  /* { dg-message "previous definition" } */
+     __attribute__ ((alias ("resolver")));
+extern int mantra (void)  /* { dg-error "redefinition" "" } */
+     __attribute__ ((ifunc ("resolver")));
+
+extern int saying (void)  /* { dg-error "weak .* cannot be defined" "" } */
+     __attribute__ ((weak,ifunc ("resolver")));
+extern int maxim (void) /* { dg-error "indirect function .* cannot be declared weak" "" } */
+     __attribute__ ((ifunc ("resolver"),weak));
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-3.c b/gcc/testsuite/gcc.dg/attr-ifunc-3.c
new file mode 100644 (file)
index 0000000..fbd972d
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "" } */
+
+#include <stdio.h>
+
+static int __attribute__((noinline))
+     implementation (void *ptr)
+{
+  if (ptr)
+    return ((int (*) (void *))ptr) (0);
+  
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+static void *resolver (void)
+{
+  return (void *)implementation;
+}
+
+extern int magic (void *) __attribute__ ((ifunc ("resolver")));
+
+int main ()
+{
+  return magic ((void *)magic);
+}
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-4.c b/gcc/testsuite/gcc.dg/attr-ifunc-4.c
new file mode 100644 (file)
index 0000000..698c06b
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "" } */
+
+#include <stdio.h>
+
+static void *implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+static void *resolver (void)
+{
+  return (void *)implementation;
+}
+
+static int magic (void) __attribute__ ((ifunc ("resolver")));
+
+int main ()
+{
+  return magic () != 0;
+}
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-5.c b/gcc/testsuite/gcc.dg/attr-ifunc-5.c
new file mode 100644 (file)
index 0000000..4dddec4
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do run }  */
+/* { dg-require-ifunc "" } */
+/* { dg-options "" } */
+
+#include <stdio.h>
+
+static void *implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+static void *resolver (void)
+{
+  return (void *)implementation;
+}
+
+extern int magic (void) __attribute__ ((ifunc ("resolver"),visibility ("hidden")));
+
+int main ()
+{
+  return magic () != 0;
+}
index 02f0bc19f57dddf07b0eca7a1f35a9b2ec52a5c3..ac5e8725addd7b7bee71bfbe71c3ce3f2679557f 100644 (file)
@@ -90,6 +90,21 @@ proc dg-require-alias { args } {
     }
 }
 
+# If this target does not support the "ifunc" attribute, skip this
+# test.
+
+proc dg-require-ifunc { args } {
+    set ifunc_available [ check_ifunc_available ]
+    if { $ifunc_available == -1 } {
+       upvar name name
+       unresolved "$name"
+    }
+    if { $ifunc_available < 2 } {
+       upvar dg-do-what dg-do-what
+       set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"]
+    }
+}
+
 # If this target's linker does not support the --gc-sections flag,
 # skip this test.
 
index 638c9eecd4124e54736e220a91036501c5a0b5d8..fc24b78a64f5c9896e35fad4695ce762f1acc7db 100644 (file)
@@ -368,6 +368,56 @@ proc check_alias_available { } {
     return $alias_available_saved
 }
 
+###############################
+# proc check_ifunc_available { }
+###############################
+
+# Determine if the target toolchain supports the alias attribute.
+
+# Returns 2 if the target supports aliases.  Returns 1 if the target
+# only supports weak aliased.  Returns 0 if the target does not
+# support aliases at all.  Returns -1 if support for aliases could not
+# be determined.
+
+proc check_ifunc_available { } {
+    global ifunc_available_saved
+    global tool
+
+    if [info exists ifunc_available_saved] {
+        verbose "check_ifunc_available  returning saved $ifunc_available_saved" 2
+    } else {
+       set src ifunc[pid].c
+       set obj ifunc[pid].o
+        verbose "check_ifunc_available  compiling testfile $src" 2
+       set f [open $src "w"]
+       # Compile a small test program.  The definition of "g" is
+       # necessary to keep the Solaris assembler from complaining
+       # about the program.
+       puts $f "#ifdef __cplusplus\nextern \"C\"\n#endif\n"
+       puts $f "void g() {} void f() __attribute__((ifunc(\"g\")));"
+       close $f
+       set lines [${tool}_target_compile $src $obj object ""]
+       file delete $src
+       remote_file build delete $obj
+
+       if [string match "" $lines] then {
+           # No error messages, everything is OK.
+           set ifunc_available_saved 2
+       } else {
+           if [regexp "ifunc is not supported" $lines] {
+               verbose "check_ifunc_available  target does not support ifunc" 2
+               set ifunc_available_saved 0
+           } else {
+               set ifunc_available_saved -1
+           }
+       }
+
+       verbose "check_ifunc_available  returning $ifunc_available_saved" 2
+    }
+
+    return $ifunc_available_saved
+}
+
 # Returns true if --gc-sections is supported on the target.
 
 proc check_gc_sections_available { } {
index c509219e3aa04496921b7a35421cd0e17d26bb01..9c2593f14c80f9f3a91afacd497fe7ca2eb58699 100644 (file)
@@ -993,7 +993,8 @@ use_blocks_for_decl_p (tree decl)
   if (DECL_INITIAL (decl) == decl)
     return false;
 
-  /* If this decl is an alias, then we don't want to emit a definition.  */
+  /* If this decl is an alias, then we don't want to emit a
+     definition.  */
   if (lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
     return false;
 
@@ -5354,6 +5355,17 @@ do_assemble_alias (tree decl, tree target)
       globalize_decl (decl);
       maybe_assemble_visibility (decl);
     }
+  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+    {
+#if defined (ASM_OUTPUT_TYPE_DIRECTIVE) && HAVE_GAS_INDIRECT_FUNCTION
+      ASM_OUTPUT_TYPE_DIRECTIVE
+       (asm_out_file, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+        IFUNC_ASM_TYPE);
+#else
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "ifunc is not supported in this configuration");
+#endif
+    }
 
 # ifdef ASM_OUTPUT_DEF_FROM_DECLS
   ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);