I came across some very interesting behavior regarding to built-in functions:

int __builtin_popcount( unsigned x ); is a gcc bult-in, which actually
returns the number of 1 bits in x.

   int foo( unsigned x )
   {
      return __builtin_popcount( x );
   }

generates a call to the __popcountsi2 function in libgcc, for any target I
tried it for (well, I tried for x86, ARM and m68k).

However:

   int (*bar( void ))( unsigned )
   {
      return __builtin_popcount;
   }

returns the address of the label "__builtin_popcount", which does not exist:

   int main( int arcg, char *argv[] )
   {
      (void) argv;
      return (*bar())( argc );
   }

fails to compile because of an undefined reference to __builtin_popcount.

The compiler does not give any warning with -Wall -Wextra -pedantic
but it spits the dummy during the linking phase. 

The next quite interesting thing is the effect of optimisation.
With -O1 or above bar() returns the address of the non-existent function
__builtin_popcount() *but* main(), which dereferences bar() is optimised
to simply call __popcountsi2 in the library. So the linking fails because
bar() (which is not actually called by main()) refers to the nonexistent
function, but if bar() is made static, the optimisiation gets rid of it and
everything is fine and the linking succeeds.

A further point is that the compiler generates a .globl for __popcountsi2 but
it does not do that for __builtin_popcount, which is rather unusual (although
not fatal, since gas treats all undefined symbols as globals). Nevertheless,
gcc normally pedanticly emits a .globl for every global symbol it generates
or refers to, but not in this case.

At least the 4.5.x compiler behaves like that. The info page does not say that
one can not take the address of a built-in function (and the compiler does not
issue a warning on it), so a link time failure, which depends on whether the
optimiser could eliminate the need to the actual function pointer or not, is
somewhat surprising.

I understand that there are very special built-in functions, some that work
only at compile time, some show very funky argument handling behaviour and so
on. However, many are (well, seem to be) stock standard functions, realised
either as a call to libgcc or as a few machine instructions, that is,
behaving like inline asm() wrapped in a static inline. 
Those functions, I think, should really behave like ordinary (possibly static
inline asm) functions. Or, if not, at least one should be warned.

I believe that the above is an issue, but I don't know if it is bug or a
feature, i.e. a compiler or a documentation issue?

Thanks,

Zoltan

Reply via email to