WARNING: This server is unstable and will be retired in the next days. If you want to keep this forum available, please request immediately a migration on the Nabble Support forum. Forums that don't receive any migration request will be deleted forever.

indirect function support

View: New views
13 Messages — Rating Filter:   Alert me  

indirect function support

by Nathan Sidwell :: Rate this Message:

| View Threaded | Show Only this Message

This patch implements an 'ifunc' attribute, to allow support of the GNU_IFUNC
symbol type and associated relocations, as documented at
http://groups.google.com/group/generic-abi/files

The previous design, starting at
http://gcc.gnu.org/ml/gcc-patches/2009-06/msg00976.html was IIUC rejected for
being too invasive, after several iterations.  Binutils and GLIBC already have
the necessary support for this symbol type.

The approach I've taken is to build on the alias attribute support, and rather
than directly tag the resolver function as ifunc, one tags a separate function,
naming the resolver function.  Note that one concern previously mentioned
concerned C++ name mangling.  This patch has exactly the same name mangling
requirements as the alias attribute.  Unlike the previous iteration, the
mangling you need to know is that of the resolver function whose name is under
the implementors control.  You do not need to know the mangling of the external
function that the user calls.

built and tested on i686-pc-linux-gnu.  My ubuntu 10.4 system has glibc and
binutils support (and that's where I've taken the minimum version information
from, if earlier version support it, please let me know).

ok?

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery


[ifunc.patch]

2010-05-16  Nathan Sidwell  <nathan@...>

        * 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-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.

Index: doc/extend.texi
===================================================================
--- doc/extend.texi (revision 159385)
+++ doc/extend.texi (working copy)
@@ -1899,6 +1899,7 @@
 @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
@@ -1914,13 +1915,13 @@
 @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.
 
@@ -2572,6 +2573,51 @@
                      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:
+
+@smallexample
+void *my_memcpy (void *dst, const void *src, size_t len)
+@{
+  @dots{}
+@}
+
+static void *resolve_memcpy (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: defaults.h
===================================================================
--- defaults.h (revision 159385)
+++ defaults.h (working copy)
@@ -118,6 +118,10 @@
 #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: configure
===================================================================
--- configure (revision 159385)
+++ configure (working copy)
Index: testsuite/gcc.dg/attr-ifunc-1.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-1.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-1.c (revision 0)
@@ -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")));
+
+int main ()
+{
+  return magic () != 0;
+}
Index: testsuite/gcc.dg/attr-ifunc-2.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-2.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-2.c (revision 0)
@@ -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));
Index: testsuite/gcc.dg/attr-ifunc-3.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-3.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-3.c (revision 0)
@@ -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);
+}
Index: testsuite/lib/target-supports-dg.exp
===================================================================
--- testsuite/lib/target-supports-dg.exp (revision 159385)
+++ testsuite/lib/target-supports-dg.exp (working copy)
@@ -90,6 +90,21 @@
     }
 }
 
+# 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: testsuite/lib/target-supports.exp
===================================================================
--- testsuite/lib/target-supports.exp (revision 159385)
+++ testsuite/lib/target-supports.exp (working copy)
@@ -368,6 +368,56 @@
     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: config.in
===================================================================
--- config.in (revision 159385)
+++ config.in (working copy)
@@ -956,6 +956,9 @@
 /* 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: configure.ac
===================================================================
--- configure.ac (revision 159385)
+++ configure.ac (working copy)
@@ -2154,6 +2154,19 @@
 [ .hidden foobar
 foobar:])
 
+# 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: varasm.c
===================================================================
--- varasm.c (revision 159385)
+++ varasm.c (working copy)
@@ -1280,7 +1280,8 @@
   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;
 
@@ -5720,6 +5721,17 @@
       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_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);
Index: c-common.c
===================================================================
--- c-common.c (revision 159385)
+++ c-common.c (working copy)
@@ -501,6 +501,8 @@
 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,
@@ -775,6 +777,8 @@
       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,
@@ -6759,6 +6763,12 @@
       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);
@@ -6768,16 +6778,17 @@
   return NULL_TREE;
 }
 
-/* Handle an "alias" attribute; arguments as in
+/* 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)
+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;
@@ -6790,9 +6801,18 @@
       || (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
@@ -6806,7 +6826,7 @@
       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;
  }
@@ -6824,6 +6844,11 @@
     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
     {
@@ -6834,6 +6859,20 @@
   return NULL_TREE;
 }
 
+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);
+}
+
+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.  */
 
@@ -6855,6 +6894,13 @@
       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. */


Re: indirect function support

by H.J. Lu-30 :: Rate this Message:

| View Threaded | Show Only this Message

On Sun, May 16, 2010 at 11:32 AM, Nathan Sidwell
<nathan@...> wrote:

> This patch implements an 'ifunc' attribute, to allow support of the
> GNU_IFUNC symbol type and associated relocations, as documented at
> http://groups.google.com/group/generic-abi/files
>
> The previous design, starting at
> http://gcc.gnu.org/ml/gcc-patches/2009-06/msg00976.html was IIUC rejected
> for being too invasive, after several iterations.  Binutils and GLIBC
> already have the necessary support for this symbol type.
>
> The approach I've taken is to build on the alias attribute support, and
> rather than directly tag the resolver function as ifunc, one tags a separate
> function, naming the resolver function.  Note that one concern previously
> mentioned concerned C++ name mangling.  This patch has exactly the same name
> mangling requirements as the alias attribute.  Unlike the previous
> iteration, the mangling you need to know is that of the resolver function
> whose name is under the implementors control.  You do not need to know the
> mangling of the external function that the user calls.
>
> built and tested on i686-pc-linux-gnu.  My ubuntu 10.4 system has glibc and
> binutils support (and that's where I've taken the minimum version
> information from, if earlier version support it, please let me know).
>
> ok?
>

I have a a few questions:

1. Does it work with static ifunc functions like

static int magic (void *) __attribute__ ((ifunc ("resolver")));

2. Does it work with symbol visibility?
3. Can you take an address of the ifunc function?
4. Do you have C++ testcases?
     Does it work with member functions?
     Does it work with virtual functions.
     Does it work with inheritance?
     Can you take an address of an ifunc member functiom?

Thanks.


--
H.J.

Re: indirect function support

by Nathan Sidwell :: Rate this Message:

| View Threaded | Show Only this Message

On 05/17/10 04:13, H.J. Lu wrote:

> I have a a few questions:
>
> 1. Does it work with static ifunc functions like
>
> static int magic (void *) __attribute__ ((ifunc ("resolver")));

yes -- added a testcase

> 2. Does it work with symbol visibility?

yes - added a testcase

> 3. Can you take an address of the ifunc function?

yes

> 4. Do you have C++ testcases?
>       Does it work with member functions?
>       Does it work with virtual functions.
>       Does it work with inheritance?
>       Can you take an address of an ifunc member functiom?

yes, added testcases, and augmented C++ to allow alias on (static & non-static)
member functions.  there was an interesting interaction with a class's key method.

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery


Index: doc/extend.texi
===================================================================
--- doc/extend.texi (revision 159500)
+++ doc/extend.texi (working copy)
@@ -1899,6 +1899,7 @@
 @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
@@ -1914,13 +1915,13 @@
 @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.
 
@@ -2572,6 +2573,51 @@
                      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:
+
+@smallexample
+void *my_memcpy (void *dst, const void *src, size_t len)
+@{
+  @dots{}
+@}
+
+static void *resolve_memcpy (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: defaults.h
===================================================================
--- defaults.h (revision 159500)
+++ defaults.h (working copy)
@@ -118,6 +118,10 @@
 #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: configure
===================================================================
--- configure (revision 159500)
+++ configure (working copy)
@@ -21270,6 +21270,48 @@
 $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: testsuite/gcc.dg/attr-ifunc-1.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-1.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-1.c (revision 0)
@@ -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;
+}
Index: testsuite/gcc.dg/attr-ifunc-5.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-5.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-5.c (revision 0)
@@ -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: testsuite/gcc.dg/attr-ifunc-2.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-2.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-2.c (revision 0)
@@ -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));
Index: testsuite/gcc.dg/attr-ifunc-3.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-3.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-3.c (revision 0)
@@ -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);
+}
Index: testsuite/gcc.dg/attr-ifunc-4.c
===================================================================
--- testsuite/gcc.dg/attr-ifunc-4.c (revision 0)
+++ testsuite/gcc.dg/attr-ifunc-4.c (revision 0)
@@ -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;
+}
Index: testsuite/g++.dg/ext/attr-ifunc-1.C
===================================================================
--- testsuite/g++.dg/ext/attr-ifunc-1.C (revision 0)
+++ testsuite/g++.dg/ext/attr-ifunc-1.C (revision 0)
@@ -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;
+}
Index: testsuite/g++.dg/ext/attr-alias-1.C
===================================================================
--- testsuite/g++.dg/ext/attr-alias-1.C (revision 0)
+++ testsuite/g++.dg/ext/attr-alias-1.C (revision 0)
@@ -0,0 +1,25 @@
+/* { dg-do run }  */
+/* { dg-require-alias "" } */
+
+#include <stdio.h>
+
+struct Klass
+{
+  int implementation ();
+  int magic ();
+};
+
+int Klass::implementation (void)
+{
+  printf ("'ere I am JH\n");
+  return 0;
+}
+
+int Klass::magic (void) __attribute__ ((alias ("_ZN5Klass14implementationEv")));
+
+int main ()
+{
+  Klass obj;
+  
+  return obj.magic () != 0;
+}
Index: testsuite/g++.dg/ext/attr-ifunc-2.C
===================================================================
--- testsuite/g++.dg/ext/attr-ifunc-2.C (revision 0)
+++ testsuite/g++.dg/ext/attr-ifunc-2.C (revision 0)
@@ -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;
+}
Index: testsuite/g++.dg/ext/attr-ifunc-3.C
===================================================================
--- testsuite/g++.dg/ext/attr-ifunc-3.C (revision 0)
+++ testsuite/g++.dg/ext/attr-ifunc-3.C (revision 0)
@@ -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;
+}
Index: testsuite/g++.dg/ext/attr-ifunc-4.C
===================================================================
--- testsuite/g++.dg/ext/attr-ifunc-4.C (revision 0)
+++ testsuite/g++.dg/ext/attr-ifunc-4.C (revision 0)
@@ -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;
+}
Index: testsuite/lib/target-supports-dg.exp
===================================================================
--- testsuite/lib/target-supports-dg.exp (revision 159500)
+++ testsuite/lib/target-supports-dg.exp (working copy)
@@ -90,6 +90,21 @@
     }
 }
 
+# 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: testsuite/lib/target-supports.exp
===================================================================
--- testsuite/lib/target-supports.exp (revision 159500)
+++ testsuite/lib/target-supports.exp (working copy)
@@ -368,6 +368,56 @@
     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: cp/decl.c
===================================================================
--- cp/decl.c (revision 159500)
+++ cp/decl.c (working copy)
@@ -91,6 +91,7 @@
 static void finish_constructor_body (void);
 static void begin_destructor_body (void);
 static void finish_destructor_body (void);
+static void record_key_method_defined (tree);
 static tree create_array_type_for_decl (tree, tree, tree);
 static tree get_atexit_node (void);
 static tree get_dso_handle_node (void);
@@ -4120,6 +4121,7 @@
   tree context;
   bool was_public;
   int flags;
+  bool alias;
 
   *pushed_scope_p = NULL_TREE;
 
@@ -4181,6 +4183,10 @@
       if (toplevel_bindings_p ())
  TREE_STATIC (decl) = 1;
     }
+  alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)) != 0;
+  
+  if (alias && TREE_CODE (decl) == FUNCTION_DECL)
+    record_key_method_defined (decl);
 
   /* If this is a typedef that names the class for linkage purposes
      (7.1.3p8), apply any attributes directly to the type.  */
@@ -4283,7 +4289,9 @@
     DECL_EXTERNAL (decl) = 1;
  }
 
-      if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl))
+      if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
+  /* Aliases are definitions. */
+  && !alias)
  permerror (input_location, "declaration of %q#D outside of class is not definition",
    decl);
 
@@ -12449,6 +12457,22 @@
   return block;
 }
 
+/* If FNDECL is a class's key method, add the class to the list of
+   keyed classes that should be emitted.  */
+
+static void
+record_key_method_defined (tree fndecl)
+{
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
+      && DECL_VIRTUAL_P (fndecl)
+      && !processing_template_decl)
+    {
+      tree fnclass = DECL_CONTEXT (fndecl);
+      if (fndecl == CLASSTYPE_KEY_METHOD (fnclass))
+ keyed_classes = tree_cons (NULL_TREE, fnclass, keyed_classes);
+    }
+}
+
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition.
@@ -12475,14 +12499,7 @@
   gcc_assert (!defer_mark_used_calls);
   defer_mark_used_calls = true;
 
-  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
-      && DECL_VIRTUAL_P (fndecl)
-      && !processing_template_decl)
-    {
-      tree fnclass = DECL_CONTEXT (fndecl);
-      if (fndecl == CLASSTYPE_KEY_METHOD (fnclass))
- keyed_classes = tree_cons (NULL_TREE, fnclass, keyed_classes);
-    }
+  record_key_method_defined (fndecl);
 
   nested = function_depth > 1;
   fntype = TREE_TYPE (fndecl);
Index: config.in
===================================================================
--- config.in (revision 159500)
+++ config.in (working copy)
@@ -956,6 +956,9 @@
 /* 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: configure.ac
===================================================================
--- configure.ac (revision 159500)
+++ configure.ac (working copy)
@@ -2154,6 +2154,19 @@
 [ .hidden foobar
 foobar:])
 
+# 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: varasm.c
===================================================================
--- varasm.c (revision 159500)
+++ varasm.c (working copy)
@@ -1280,7 +1280,8 @@
   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;
 
@@ -5720,6 +5721,17 @@
       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);
Index: c-common.c
===================================================================
--- c-common.c (revision 159500)
+++ c-common.c (working copy)
@@ -500,6 +500,8 @@
 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,
@@ -775,6 +777,8 @@
       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,
@@ -6759,6 +6763,12 @@
       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);
@@ -6768,16 +6778,17 @@
   return NULL_TREE;
 }
 
-/* Handle an "alias" attribute; arguments as in
+/* 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)
+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;
@@ -6790,9 +6801,18 @@
       || (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
@@ -6806,7 +6826,7 @@
       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;
  }
@@ -6824,6 +6844,11 @@
     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
     {
@@ -6834,6 +6859,20 @@
   return NULL_TREE;
 }
 
+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);
+}
+
+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.  */
 
@@ -6855,6 +6894,13 @@
       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. */

Re: indirect function support

by H.J. Lu-30 :: Rate this Message:

| View Threaded | Show Only this Message

On Tue, May 18, 2010 at 1:00 AM, Nathan Sidwell <nathan@...> wrote:

> On 05/17/10 04:13, H.J. Lu wrote:
>
>> I have a a few questions:
>>
>> 1. Does it work with static ifunc functions like
>>
>> static int magic (void *) __attribute__ ((ifunc ("resolver")));
>
> yes -- added a testcase
>
>> 2. Does it work with symbol visibility?
>
> yes - added a testcase
>
>> 3. Can you take an address of the ifunc function?
>
> yes
>
>> 4. Do you have C++ testcases?
>>      Does it work with member functions?
>>      Does it work with virtual functions.
>>      Does it work with inheritance?
>>      Can you take an address of an ifunc member functiom?
>
> yes, added testcases, and augmented C++ to allow alias on (static &
> non-static) member functions.  there was an interesting interaction with a
> class's key method.
>

Is that a good idea to ask programmers to do name mangling by
hand?  It can be quite complicated for  complex C++ classes
and they have to update the alias when member functions are changed.
We need to make it easy to use.


--
H.J.

Re: indirect function support

by Nathan Sidwell :: Rate this Message:

| View Threaded | Show Only this Message

H.J. Lu wrote:

> Is that a good idea to ask programmers to do name mangling by
> hand?  It can be quite complicated for  complex C++ classes
> and they have to update the alias when member functions are changed.
> We need to make it easy to use.

The alias attribute already requires this (for non-member functions, for member
functions, alias was simply broken).  While it would be nice to improve alias, I
don't see why that should be a requirement of adding ifunc support to alias.

Do you have a use case of using ifunc for member functions?  Perhaps that would
help.

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery


Re: indirect function support

by H.J. Lu-30 :: Rate this Message:

| View Threaded | Show Only this Message

On Tue, May 18, 2010 at 3:37 PM, Nathan Sidwell <nathan@...> wrote:

> H.J. Lu wrote:
>
>> Is that a good idea to ask programmers to do name mangling by
>> hand?  It can be quite complicated for  complex C++ classes
>> and they have to update the alias when member functions are changed.
>> We need to make it easy to use.
>
> The alias attribute already requires this (for non-member functions, for
> member functions, alias was simply broken).  While it would be nice to
> improve alias, I don't see why that should be a requirement of adding ifunc
> support to alias.

It is not about adding ifunc support to alias. It is about providing a user
friendly ifunc implementation.

> Do you have a use case of using ifunc for member functions?  Perhaps that
> would help.
>

I am enclosing a C++ testcase for my ifunc attribute proposal. It shows
how one can use ifunc on member functions.

How does your proposal work with C++ template and C++ member function
overload?

Thanks.

--
H.J.
---
/* This is a demo for STT_GNU_IFUNC.  See ifunc.txt at

   http://groups.google.com/group/generic-abi
 */

#include <stdio.h>
#include <cpuid.h>
#include <iostream>

using namespace std;

class cpuid
{
private:
  static void x86 (void)
    {
      printf ("I am an x86\n");
    }

  static void sse (void)
    {
      printf ("I have SSE\n");
    }

  static void sse2 (void)
    {
      printf ("I have SSE2\n");
    }

  static void sse3 (void)
    {
      printf ("I have SSE3\n");
    }

  static void ssse3 (void)
    {
      printf ("I have SSSE3\n");
    }

  static void sse4_1 (void)
    {
      printf ("I have SSE4.1\n");
    }

  static void sse4_2 (void)
    {
      printf ("I have SSE4.2\n");
    }

public:
  /* feature is an indirec function.  */
  static void __attribute__ ((ifunc)) feature (void)
    {
      unsigned int eax, ebx, ecx, edx;

      __cpuid (1, eax, ebx, ecx, edx);

      if (ecx & bit_SSE4_2)
        return cpuid::sse4_2;
      if (ecx & bit_SSE4_1)
        return cpuid::sse4_1;
      if (ecx & bit_SSSE3)
        return cpuid::ssse3;
      if (ecx & bit_SSE3)
        return cpuid::sse3;
      if (edx & bit_SSE2)
        return cpuid::sse2;
      if (edx & bit_SSE)
        return cpuid::sse;
      return cpuid::x86;
    }
};

class long_mode
{
private:
  void lm_yes (void)
    {
      printf ("I support 64bit.\n");
    }

  void lm_no (void)
    {
      printf ("I don't support 64bit.\n");
    }

public:
  /* lm is an indirec function.  */
  void __attribute__ ((ifunc)) lm (void)
    {
      unsigned int eax, ebx, ecx, edx;

      __cpuid (0x80000001, eax, ebx, ecx, edx);

      if (edx & bit_LM)
        return &long_mode::lm_yes;
      else
        return &long_mode::lm_no;
    }
};

class Foo
{
private:
  virtual void foo1 ()
    {
      printf ("I am %s\n", __PRETTY_FUNCTION__);
    }
public:
  virtual void  __attribute__ ((ifunc)) foo ()
    {
      return &Foo::foo1;
    }
};

class Bar : public Foo
{
private:
  void foo1 ()
    {
      printf ("I am %s\n", __PRETTY_FUNCTION__);
    }
public:
  void foo ()
    {
      printf ("I am %s\n", __PRETTY_FUNCTION__);
    }
};

class X
{
private:
  virtual void foo1 ()
    {
      printf ("I am %s\n", __PRETTY_FUNCTION__);
    }
  virtual void foo1 (int x)
    {
      printf ("%d: I am %s\n", x,  __PRETTY_FUNCTION__);
    }
public:
  virtual void foo ();
  virtual void foo (int);
};

void
__attribute__ ((ifunc))
X::foo ()
{
  return &X::foo1;
}

void
__attribute__ ((ifunc))
X::foo (int)
{
  return &X::foo1;
}

class Y : public X
{
private:
  void foo1 ()
    {
      printf ("I am %s\n", __PRETTY_FUNCTION__);
    }
  void foo1 (int x)
    {
      printf ("%d: I am %s\n", x, __PRETTY_FUNCTION__);
    }
public:
  void foo ()
    {
      printf ("I am %s\n", __PRETTY_FUNCTION__);
    }
  void foo (int x)
    {
      printf ("%d: I am %s\n", x, __PRETTY_FUNCTION__);
    }
};

template <class T>
class Z
{
private:
  virtual void foo1 ()
    {
      cout << __PRETTY_FUNCTION__ << endl;
    }
  virtual void foo1 (T x)
    {
      cout << x << ": " << __PRETTY_FUNCTION__ << endl;
    }
public:
  virtual void foo ();
  virtual void foo (int);
};

template <class T>
void
__attribute__ ((ifunc))
Z<T>::foo ()
{
  return &Z<T>::foo1;
}

template <class T>
void
__attribute__ ((ifunc))
Z<T>::foo (int)
{
  return &Z<T>::foo1;
}

template <class T>
class FOO : public Z<T>
{
private:
  void foo1 ()
    {
      cout << __PRETTY_FUNCTION__ << endl;
    }
  void foo1 (T x)
    {
      cout << x << ": " << __PRETTY_FUNCTION__ << endl;
    }
public:
  void foo ()
    {
      cout << __PRETTY_FUNCTION__ << endl;
    }
  void foo (int x)
    {
      cout << x << ": " << __PRETTY_FUNCTION__ << endl;
    }
};

int
main ()
{
  int i;
  class cpuid c;
  class long_mode l;

  /* Run it under gdb to see how feature and lm are called.  */
  for (i = 0; i < 5; i++)
    {
      c.feature ();
      l.lm ();
    }

  Foo f;
  f.foo ();

  Bar b;
  b.foo ();

  X x;
  x.foo ();
  x.foo (30);

  Y y;
  y.foo ();
  y.foo (50);

  Z<int> z;
  z.foo ();
  z.foo (300);

  FOO<int> foo;
  foo.foo ();
  foo.foo (-300);

  return 0;
}

Re: indirect function support

by Richard Guenther-2 :: Rate this Message:

| View Threaded | Show Only this Message

On Tue, May 18, 2010 at 11:49 AM, H.J. Lu <hjl.tools@...> wrote:

> On Tue, May 18, 2010 at 3:37 PM, Nathan Sidwell <nathan@...> wrote:
>> H.J. Lu wrote:
>>
>>> Is that a good idea to ask programmers to do name mangling by
>>> hand?  It can be quite complicated for  complex C++ classes
>>> and they have to update the alias when member functions are changed.
>>> We need to make it easy to use.
>>
>> The alias attribute already requires this (for non-member functions, for
>> member functions, alias was simply broken).  While it would be nice to
>> improve alias, I don't see why that should be a requirement of adding ifunc
>> support to alias.
>
> It is not about adding ifunc support to alias. It is about providing a user
> friendly ifunc implementation.

I don't think we need something beyond what Nathan implemented.

The easiest way for the user is to forward to C linkage ifuncs from
templates, members, etc. and this is what we should encourage
in our documentation.

Any support for mangling should be orthogonal, maybe by a
C++ extension like __mangle decltype(...) or __mangle decl
resulting in a string literal.

Richard.

Re: indirect function support

by Pedro Alves-10 :: Rate this Message:

| View Threaded | Show Only this Message

On Tuesday 18 May 2010 09:00:22, Nathan Sidwell wrote:
> +static void *resolve_memcpy (void)
> +@{
> +  return my_memcpy; // we'll just always select this routine
> +@}

Shouldn't these examples be returning a function pointer instead of a
data pointer?  That's what the ifunc specification says an ifunc returns.
I know that under posix you can convert between these and back, and that
this is only implemented on glibc presently, but it feels like the docs
shouldn't be showing undefined behaviour, non-posix, C confirming,
pedantically speaking.  Returning `void (*)(void)' would be good already,
though `typeof(memcpy) *' would even be nicer.  Just 2c. from a bystander.

--
Pedro Alves

Re: indirect function support

by H.J. Lu-30 :: Rate this Message:

| View Threaded | Show Only this Message

On Tue, May 18, 2010 at 5:53 PM, Richard Guenther
<richard.guenther@...> wrote:

> On Tue, May 18, 2010 at 11:49 AM, H.J. Lu <hjl.tools@...> wrote:
>> On Tue, May 18, 2010 at 3:37 PM, Nathan Sidwell <nathan@...> wrote:
>>> H.J. Lu wrote:
>>>
>>>> Is that a good idea to ask programmers to do name mangling by
>>>> hand?  It can be quite complicated for  complex C++ classes
>>>> and they have to update the alias when member functions are changed.
>>>> We need to make it easy to use.
>>>
>>> The alias attribute already requires this (for non-member functions, for
>>> member functions, alias was simply broken).  While it would be nice to
>>> improve alias, I don't see why that should be a requirement of adding ifunc
>>> support to alias.
>>
>> It is not about adding ifunc support to alias. It is about providing a user
>> friendly ifunc implementation.
>
> I don't think we need something beyond what Nathan implemented.
>
> The easiest way for the user is to forward to C linkage ifuncs from
> templates, members, etc. and this is what we should encourage
> in our documentation.
>
> Any support for mangling should be orthogonal, maybe by a
> C++ extension like __mangle decltype(...) or __mangle decl
> resulting in a string literal.
>

I am enclosing what we have today for ifunc. Glibc has

---
extern double __fma_sse2 (double x, double y, double z) attribute_hidden;

static double
__fma_fma (double x, double y, double z)
{
  asm ("vfmadd213sd %3, %2, %0" : "=x" (x) : "0" (x), "x" (y), "xm" (z));
  return x;
}

libm_ifunc (__fma, HAS_FMA ? __fma_fma : __fma_sse2);
----

But there are no type check and programmers have to know what
the symbol name is at assembly level. This ifunc proposal doesn't help
those areas. I am not sure how much this approach brings to programmers
than what we have now with some macros.


--
H.J.
---
static int
one (void)
{
  return 1;
}

static int
minus_one (void)
{
  return -1;
}

static int
zero (void)
{
  return 0;
}

void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function");

void *
foo_ifunc (void)
{
  return ifunc_sel (one, minus_one, zero);
}

Re: indirect function support

by Nathan Sidwell :: Rate this Message:

| View Threaded | Show Only this Message

On 05/18/10 10:49, H.J. Lu wrote:

> It is not about adding ifunc support to alias. It is about providing a user
> friendly ifunc implementation.

alias is the mechanism GCC has for one function to name another.

>> Do you have a use case of using ifunc for member functions?  Perhaps that
>> would help.
>>
>
> I am enclosing a C++ testcase for my ifunc attribute proposal. It shows
> how one can use ifunc on member functions.

Do you have a use case?

> How does your proposal work with C++ template and C++ member function
> overload?

Exactly the same as alias behaves.

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery


Re: indirect function support

by H.J. Lu-30 :: Rate this Message:

| View Threaded | Show Only this Message

On Mon, May 24, 2010 at 5:54 AM, Nathan Sidwell <nathan@...> wrote:

> On 05/18/10 10:49, H.J. Lu wrote:
>
>> It is not about adding ifunc support to alias. It is about providing a
>> user
>> friendly ifunc implementation.
>
> alias is the mechanism GCC has for one function to name another.
>
>>> Do you have a use case of using ifunc for member functions?  Perhaps that
>>> would help.
>>>
>>
>> I am enclosing a C++ testcase for my ifunc attribute proposal. It shows
>> how one can use ifunc on member functions.
>
> Do you have a use case?

I don't have a real use case in C++. But I can ask around.
It may be similar to the C++ testcases I provided.

>
>> How does your proposal work with C++ template and C++ member function
>> overload?
>
> Exactly the same as alias behaves.
>

Programmers can't provide the assembly name since they don't know the
assembly name of C++ template.

I am not sure what real benefit your proposal brings to the table. See my
followup at:

http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01384.html

Thanks.


--
H.J.

Re: indirect function support

by Nathan Sidwell :: Rate this Message:

| View Threaded | Show Only this Message

On 05/24/10 15:11, H.J. Lu wrote:

> I am not sure what real benefit your proposal brings to the table. See my
> followup at:
>
> http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01384.html

You've hidden the glibc implementation behind some unrevealed macros.   Those
macros will be non-standard, forcing every library that wishes to use ifunc
features to reinvent them.

Furthermore, I presume it is easier to write a function as a regular function
body, rather than as a single operand to the libm_ifunc macro you're invoking.

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery


Re: indirect function support

by H.J. Lu-30 :: Rate this Message:

| View Threaded | Show Only this Message

On Mon, May 24, 2010 at 7:52 AM, Nathan Sidwell <nathan@...> wrote:

> On 05/24/10 15:11, H.J. Lu wrote:
>
>> I am not sure what real benefit your proposal brings to the table. See my
>> followup at:
>>
>> http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01384.html
>
> You've hidden the glibc implementation behind some unrevealed macros.
> Those macros will be non-standard, forcing every library that wishes to use
> ifunc features to reinvent them.
>
> Furthermore, I presume it is easier to write a function as a regular
> function body, rather than as a single operand to the libm_ifunc macro
> you're invoking.
>

The macro used in glibc is to implement to

--
void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function");

void *
foo_ifunc (void)
{
  return function address;
}
----

Your proposal doesn't solve 2 flaws in the current implementation:

1. There is no type check.
2. Programmers have to know what the symbol name is at assembly level,
which makes it hard to use, especially in C++ template.

--
H.J.