Bug 40528 - Add a new ifunc attribute
Summary: Add a new ifunc attribute
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.5.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-06-23 17:17 UTC by H.J. Lu
Modified: 2017-07-03 15:19 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2009-06-24 09:38:49


Attachments
Ifunc examples (1.74 KB, application/octet-stream)
2009-06-24 15:31 UTC, H.J. Lu
Details
Ifunc examples in C and C++ (2.57 KB, application/octet-stream)
2009-06-26 20:20 UTC, H.J. Lu
Details
A C++ program with ifunc attribute (750 bytes, text/plain)
2009-06-26 20:39 UTC, H.J. Lu
Details
Static Linux/ia32 binary of prog.C (984.61 KB, application/octet-stream)
2009-06-26 20:41 UTC, H.J. Lu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2009-06-23 17:17:01 UTC
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.
Comment 1 H.J. Lu 2009-06-24 15:28:48 UTC
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.
Comment 2 H.J. Lu 2009-06-24 15:31:36 UTC
Created attachment 18060 [details]
Ifunc examples

Here are some ifunc examples with option 3.
Comment 3 Jakub Jelinek 2009-06-24 15:54:25 UTC
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.
Comment 4 H.J. Lu 2009-06-24 16:07:30 UTC
(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.
Comment 5 Jakub Jelinek 2009-06-24 19:26:12 UTC
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;
}
?
Comment 6 H.J. Lu 2009-06-24 19:31:53 UTC
(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]$ 
Comment 7 H.J. Lu 2009-06-25 14:12:11 UTC
It is easier to support C++ with option 3.
Comment 8 H.J. Lu 2009-06-26 16:14:14 UTC
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?
Comment 9 H.J. Lu 2009-06-26 20:20:17 UTC
Created attachment 18076 [details]
Ifunc examples in C and C++

Here are some C/C++ examples with valid and invalid cases.
Comment 10 H.J. Lu 2009-06-26 20:39:04 UTC
Created attachment 18077 [details]
A C++ program with ifunc attribute
Comment 11 H.J. Lu 2009-06-26 20:41:02 UTC
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++]$
Comment 12 hjl@gcc.gnu.org 2009-06-28 15:14:27 UTC
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

Comment 13 Agner Fog 2010-02-21 16:21:36 UTC
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?
Comment 14 H.J. Lu 2010-02-21 16:34:15 UTC
(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.
Comment 15 Agner Fog 2011-05-30 13:13:06 UTC
(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?
Comment 16 Agner Fog 2011-07-08 08:52:32 UTC
(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;
}
Comment 17 Yuri Gribov 2017-01-24 21:38:45 UTC
(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?
Comment 18 Jeffrey A. Law 2017-07-03 15:19:23 UTC
Fixed long ago.