Binutils and glibc implemented STT_GNU_IFUNC: http://groups.google.com/group/generic-abi A new ifunc attribute can provide user access to this feature at C language level. Several options: 1. Ifunc attribute with argument: int foo (…); __typeof (foo) * __attribute__ ((ifunc ("foo"))) foo_ifunc (void) { <return address of foo_{1,2,3}> } foo_ifunc is a dummy place holder which isn't necessary. 2. Ifunc attribute without argument: void * __attribute__ ((ifunc)) foo (void) { <return address of foo_{1,2,3}> } We can't call foo in the same file where foo is defined since we need a different prototype when calling foo. 3. Ifunc attribute with prototype, but without argument: int __attribute__ ((ifunc)) foo (...) { <return address of foo_{1,2,3}> } We can call foo in the same file. Gcc checks the return value for foo.
With option 3, we can check the return value of an ifunc function since we know the return value is a pointer to the ifunc function. We don't need a separate prototype nor asm statement.
Created attachment 18060 [details] Ifunc examples Here are some ifunc examples with option 3.
Option 2) is certainly the least intrusive in the compiler and you can use it even with foo's prototype and calling it from the same CU, just use asm. __typeof (foo) * __attribute__ ((ifunc)) foo_ifunc (void) __asm ("foo") { <return address of foo_{1,2,3}> } If you don't have a prototype, you can use the variant originally mentioned in option 2). Most users will wrap this stuff in a macro anyway and in that case whether they use just an attribute or attribute and __asm is not a big deal.
(In reply to comment #3) > Option 2) is certainly the least intrusive in the compiler and you can use it > even with foo's prototype and calling it from the same CU, just use asm. > __typeof (foo) * > __attribute__ ((ifunc)) > foo_ifunc (void) __asm ("foo") > { > <return address of foo_{1,2,3}> > } > If you don't have a prototype, you can use the variant originally mentioned in > option 2). Most users will wrap this stuff in a macro anyway and in that case > whether they use just an attribute or attribute and __asm is not a big deal. I think we enforce type check on return value of ifunc function. This is a user feature. Option 3 is the most user friendly. We only need to change the return type to a pointer to function prototype inside ifunc function body. I have a patch for option 3. It isn't too bad.
What do you do if the function has arguments, because ifunc shouldn't have arguments? While C++ has unnamed arguments and you could perhaps enforce them, C does not. How do you handle option 3 with: __attribute__((ifunc)) int foo (int a, int b) { if (a) return foo_1; if (b) return foo_2; return foo_3; } ?
(In reply to comment #5) > What do you do if the function has arguments, because ifunc shouldn't have > arguments? While C++ has unnamed arguments and you could perhaps enforce them, For unnamed arguments, see ifunc-1.c in http://gcc.gnu.org/bugzilla/attachment.cgi?id=18060 > C does not. How do you handle option 3 with: > __attribute__((ifunc)) int > foo (int a, int b) > { > if (a) return foo_1; > if (b) return foo_2; > return foo_3; > } > ? > [hjl@gnu-6 examples]$ cat x.c int foo_1 (int, int); int foo_2 (int, int); int foo_3 (int, int); __attribute__((ifunc)) int foo (int a, int b) { if (a) return foo_1; if (b) return foo_2; return foo_3; } [hjl@gnu-6 examples]$ make x.s /export/build/gnu/gcc-work/build-x86_64-linux/gcc/xgcc -B/export/build/gnu/gcc-work/build-x86_64-linux/gcc/ -S -o x.s -O2 -Wall -Wextra x.c x.c: In function ‘foo’: x.c:6:1: error: parameter ‘a’ used in indirect function ‘foo’ x.c:6:1: error: parameter ‘b’ used in indirect function ‘foo’ make: *** [x.s] Error 1 [hjl@gnu-6 examples]$
It is easier to support C++ with option 3.
For C++: 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 () { return &Bar::foo1; } }; Should Bar::foo inherit the ifun attribute from Foo::foo?
Created attachment 18076 [details] Ifunc examples in C and C++ Here are some C/C++ examples with valid and invalid cases.
Created attachment 18077 [details] A C++ program with ifunc attribute
Created attachment 18078 [details] Static Linux/ia32 binary of prog.C I got [hjl@gnu-6 c++]$ ./static I have SSE4.2 I support 64bit. I have SSE4.2 I support 64bit. I have SSE4.2 I support 64bit. I have SSE4.2 I support 64bit. I have SSE4.2 I support 64bit. I am virtual void Foo::foo1() I am virtual void Bar::foo() I am virtual void X::foo1() I am virtual void Y::foo() [hjl@gnu-6 c++]$
Subject: Bug 40528 Author: hjl Date: Sun Jun 28 15:14:09 2009 New Revision: 149026 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=149026 Log: gcc/ 2009-06-28 H.J. Lu <hongjiu.lu@intel.com> PR c/40528 * c-common.c (handle_ifunc_attribute): New. (c_common_attribute_table): Add "ifunc". * c-decl.c (merge_decls): Only allow IFUNC attribute on definition. Merge the IFUNC information. (start_function): Use function_return_type to get function return type. (store_parm_decls_newstyle): Don't warn omitted parameter name on IFUNC function. (finish_function): Issue an error if control reaches end of IFUNC function. (c_write_global_declarations_1): Add an argument to indicate global scope. Issue an error for undefined IFUNC function. (c_write_global_declarations): Updated. * c-typeck.c (c_finish_return): Use function_return_type to get function return type. * gimplify.c (gimplify_return_expr): Likewise. * stmt.c (expand_return): Likewise. * cgraphunit.c (cgraph_finalize_function): Don't allow parameter usage in ifunc function. (process_function_and_variable_attributes): Check ifunc attribute. * tree-cfg.c (verify_gimple_return): Use function_return_type to get function return type. (execute_warn_function_return): Issue an error if control reaches end of ifunc function. * tree.h (tree_decl_with_vis): Add ifunc_flag. (DECL_IS_IFUNC): New. * varasm.c (default_binds_local_p_1): Return false for IFUNC function. * config/elfos.h (ASM_DECLARE_FUNCTION_NAME): Output "gnu_indirect_function" instead of "function" for IFUNC function. * doc/extend.texi: Document ifunc attribute. gcc/cp/ 2009-06-28 H.J. Lu <hongjiu.lu@intel.com> PR c/40528 * typeck.c (cp_build_unary_op): Take the address of non-static member function for IFUNC member function. (check_return_expr): Use function_return_type to get function return type. * decl.c (check_function_type): Change return type to bool. Return true if the function type is changed to void. (wrapup_globals_for_namespace): Check undefined IFUNC symbols. (duplicate_decls): Only allow IFUNC attribute on definition. Merge the IFUNC information. (start_preparsed_function): Use function_return_type to build the return declaration for the function if its type isn't changed to void. (finish_function): Use function_return_type to get function return type. Issue an error if control reaches end of IFUNC function. gcc/testsuite/ 2009-06-28 H.J. Lu <hongjiu.lu@intel.com> PR c/40528 * g++.dg/torture/ifunc-1.C: New. * g++.dg/torture/ifunc-2.C: Likewise. * g++.dg/torture/ifunc-3.C: Likewise. * g++.dg/torture/ifunc-4.C: Likewise. * g++.dg/torture/ifunc-5.C: Likewise. * g++.dg/torture/ifunc-6.C: Likewise. * g++.dg/torture/ifunc-7.C: Likewise. * g++.dg/torture/ifunc-8.C: Likewise. * g++.dg/torture/ifunc-9.C: Likewise. * g++.dg/torture/ifunc-10.C: Likewise. * g++.dg/torture/ifunc-11.C: Likewise. * g++.dg/torture/ifunc-12.C: Likewise. * g++.dg/torture/ifunc-13.C: Likewise. * g++.dg/torture/ifunc-14.C: Likewise. * g++.dg/torture/ifunc-15.C: Likewise. * g++.dg/torture/ifunc-16.C: Likewise. * g++.dg/torture/ifunc-17.C: Likewise. * g++.dg/torture/ifunc-18.C: Likewise. * g++.dg/torture/ifunc-19.C: Likewise. * g++.dg/torture/ifunc-20.C: Likewise. * gcc.dg/torture/ifunc-1.c: Likewise. * gcc.dg/torture/ifunc-2.c: Likewise. * gcc.dg/torture/ifunc-3.c: Likewise. * gcc.dg/torture/ifunc-4.c: Likewise. * gcc.dg/torture/ifunc-5.c: Likewise. * gcc.dg/torture/ifunc-6.c: Likewise. * gcc.dg/torture/ifunc-7.c: Likewise. * gcc.dg/torture/ifunc-8.c: Likewise. * gcc.dg/torture/ifunc-9.c: Likewise. * gcc.dg/torture/ifunc-10.c: Likewise. * gcc.dg/torture/ifunc-11.c: Likewise. * gcc.dg/torture/ifunc-12.c: Likewise. * gcc.dg/torture/ifunc-13.c: Likewise. * gcc.dg/torture/ifunc-14.c: Likewise. * gcc.dg/torture/ifunc-15.c: Likewise. * gcc.dg/torture/ifunc-16.c: Likewise. * gcc.dg/torture/ifunc-17.c: Likewise. * gcc.dg/torture/ifunc-18.c: Likewise. Added: branches/ifunc/gcc/ChangeLog.ifunc branches/ifunc/gcc/cp/ChangeLog.ifunc branches/ifunc/gcc/testsuite/ChangeLog.ifunc branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-1.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-10.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-11.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-12.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-13.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-14.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-15.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-16.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-17.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-18.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-19.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-2.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-20.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-3.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-4.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-5.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-6.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-7.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-8.C branches/ifunc/gcc/testsuite/g++.dg/torture/ifunc-9.C branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-1.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-10.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-11.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-12.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-13.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-14.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-15.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-16.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-17.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-18.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-2.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-3.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-4.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-5.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-6.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-7.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-8.c branches/ifunc/gcc/testsuite/gcc.dg/torture/ifunc-9.c Modified: branches/ifunc/gcc/c-common.c branches/ifunc/gcc/c-decl.c branches/ifunc/gcc/c-typeck.c branches/ifunc/gcc/cgraphunit.c branches/ifunc/gcc/config/elfos.h branches/ifunc/gcc/cp/decl.c branches/ifunc/gcc/cp/typeck.c branches/ifunc/gcc/doc/extend.texi branches/ifunc/gcc/gimplify.c branches/ifunc/gcc/stmt.c branches/ifunc/gcc/tree-cfg.c branches/ifunc/gcc/tree.h branches/ifunc/gcc/varasm.c
What is the status of this issue? Is option 3 implemented? Which versions of Linux and binutils support IFUNC? Any plans for BSD and Mac?
(In reply to comment #13) > What is the status of this issue? It is implemented on ifunc branch. > Is option 3 implemented? Yes, on ifunc branch. > Which versions of Linux and binutils support IFUNC? You need at least glibc 2.11 and binutils 2.20. > Any plans for BSD and Mac? > You have to ask BSD and Mac people since IFUNC support needs to be implemented in both binutils and the C library.
(In reply to comment #14) > (In reply to comment #13) > > What is the status of this issue? > > It is implemented on ifunc branch. > > > Is option 3 implemented? > > Yes, on ifunc branch. > > > Which versions of Linux and binutils support IFUNC? > > You need at least glibc 2.11 and binutils 2.20. > > > Any plans for BSD and Mac? > > > > You have to ask BSD and Mac people since IFUNC support > needs to be implemented in both binutils and the C > library. Still doesn't work. "warning: ‘ifunc’ attribute directive ignored" GNU Binutils for Ubuntu 2.21.0.20110327 Where can I find an implementation with ifunc branch?
(In reply to comment #15) > (In reply to comment #14) > > (In reply to comment #13) > > > What is the status of this issue? > > > > It is implemented on ifunc branch. > > > > > Is option 3 implemented? > > > > Yes, on ifunc branch. > > > > > Which versions of Linux and binutils support IFUNC? > Still doesn't work. > "warning: ‘ifunc’ attribute directive ignored" > GNU Binutils for Ubuntu 2.21.0.20110327 The ifunc attribute is described in http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html but it doesn't work (see my previous comment). After some experimentation I found that the method described below works. Either the compiler should be fixed or the onlinedocs should be changed. // Example of gnu indirect function #include <stdio.h> #include <time.h> // Define different versions of my function int myfunc1() { return 1; } int myfunc2() { return 2; } // Type definition for pointer to my function typedef int (*MyFunctionPointer)(void); // Prototype for the common entry point extern "C" // remove this line if not C++ int myfunc(); __asm__ (".type myfunc, @gnu_indirect_function"); // Make the dispatcher function MyFunctionPointer myfunc_dispatch (void) __asm__ ("myfunc"); MyFunctionPointer myfunc_dispatch (void) { if (time(0) & 1) { // If time is odd at first call, use version 1 return myfunc1; } else { // else use version 2 return myfunc2; } } int main() { // Test the call to myfunc printf("\nCalled function number %i\n", myfunc()); return 0; }
(In reply to Agner Fog from comment #16) > (In reply to comment #15) > > (In reply to comment #14) > > > (In reply to comment #13) > > > > What is the status of this issue? > > > > > > It is implemented on ifunc branch. > > > > > > > Is option 3 implemented? > > > > > > Yes, on ifunc branch. > > > > > > > Which versions of Linux and binutils support IFUNC? > > Still doesn't work. > > "warning: ‘ifunc’ attribute directive ignored" > > GNU Binutils for Ubuntu 2.21.0.20110327 > > The ifunc attribute is described in > http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html but it doesn't > work (see my previous comment). Works fine in Ubuntu 16.04 (GCC 5.4, BU 2.26, Glibc 2.23). Could someone close this?
Fixed long ago.