diff mbox

[v3,2/9] Use gcc attribute ifunc in libc_ifunc macro instead of inline assembly due to false debuginfo.

Message ID 9027774f-dd0f-a502-ca81-1a0bceda21c0@linux.vnet.ibm.com
State New
Headers show

Commit Message

Stefan Liebler Sept. 30, 2016, 1:45 p.m. UTC
Hi Adhemerval,

thanks for reviewing. I've split the too long lines and added a comment 
block for libc_ifunc{_redirected,_hidden} macros in include/libc-symbols.h.

Yes you are right, review for patch 9 is still missing. I've tested the 
s390 part on s390x/s390. If patch 9 is okay, I'll commit the patch series.

Thanks.
Stefan

On 09/29/2016 08:38 PM, Adhemerval Zanella wrote:
> Patch LGTM and a powerpc32/power7 (to actually uses ifunc) and a build/run
> for powerpc64le seems ok.
>
> I see with recent Andreas ack of 4/9 that only 3/9 (s390 bits) and
> 9/9 (siglongjmp, longjmp in libpthread) seems to be the impending
> bits.  I plan to check on 9/9, but I won't be able to proper review
> 3/9 since I do not have access to a s390 machine anymore.
>
> Some comments below:
>
> On 24/08/2016 07:04, Stefan Liebler wrote:
>> diff --git a/include/libc-symbols.h b/include/libc-symbols.h
>> index c2b499a..44e5253 100644
>> --- a/include/libc-symbols.h
>> +++ b/include/libc-symbols.h
>> @@ -722,27 +722,64 @@ for linking")
>>  # define compat_data_section .section ".data.compat", "aw";
>>  #endif
>>
>> -/* Marker used for indirection function symbols.  */
>> -#define libc_ifunc(name, expr)						\
>> -  extern void *name##_ifunc (void) __asm__ (#name);			\
>> -  void *name##_ifunc (void)						\
>> +/* Helper / base  macros for indirect function symbols.  */
>> +#define __ifunc_resolver(type_name, name, expr, arg, init, classifier)	\
>> +  classifier void *name##_ifunc (arg)					\
>>    {									\
>> -    INIT_ARCH ();							\
>> -    __typeof (name) *res = expr;					\
>> +    init ();								\
>> +    __typeof (type_name) *res = expr;					\
>>      return res;								\
>> -  }									\
>> -  __asm__ (".type " #name ", %gnu_indirect_function");
>> +  }
>> +
>> +#ifdef HAVE_GCC_IFUNC
>> +# define __ifunc(type_name, name, expr, arg, init)			\
>> +  extern __typeof (type_name) name __attribute__			\
>> +			      ((ifunc (#name "_ifunc")));		\
>> +  __ifunc_resolver (type_name, name, expr, arg, init, static)
>> +
>> +# define __ifunc_hidden(type_name, name, expr, arg, init)	\
>> +  __ifunc (type_name, name, expr, arg, init)
>> +#else
>> +/* Gcc does not support __attribute__ ((ifunc (...))).  Use the old behaviour
>> +   as fallback.  But keep in mind that the debug information for the ifunc
>> +   resolver functions is not correct.  It contains the ifunc'ed function as
>> +   DW_AT_linkage_name.  E.g. lldb uses this field and an inferior function
>> +   call of the ifunc'ed function will fail due to "no matching function for call
>
> Line too long.
>
>> +   to ..." because the ifunc'ed function and the resolver function have
>> +   different signatures.  (Gcc support is disabled at least on a ppc64le
>> +   Ubuntu 14.04 system.)  */
>> +
>> +# define __ifunc(type_name, name, expr, arg, init)			\
>> +  extern __typeof (type_name) name;					\
>> +  void *name##_ifunc (arg) __asm__ (#name);				\
>> +  __ifunc_resolver (type_name, name, expr, arg, init,)			\
>> + __asm__ (".type " #name ", %gnu_indirect_function");
>> +
>> +# define __ifunc_hidden(type_name, name, expr, arg, init)		\
>> +  extern __typeof (type_name) __libc_##name;				\
>> +  __ifunc (type_name, __libc_##name, expr, arg, init)			\
>> +  strong_alias (__libc_##name, name);
>> +#endif /* !HAVE_GCC_IFUNC  */
>> +
>> +/* Use libc_ifunc if your ifunc'ed function has no internal symbol.  */
>> +#define libc_ifunc(name, expr) __ifunc (name, name, expr, void, INIT_ARCH)
>
> I think it will be valuable to add a comment like the one on same
> file at line 341 with a usage example on how to use
> libc_ifunc{_redirected,_hidden} and difference between each usage and
> the possible requirements (such as name redirection).
>
>> +
>> +/* Use libc_ifunc_redirected if your ifunc'ed function has an internal symbol
>> +   which should be a dedicated fallback function instead of ifunc'ed.
>> +   You have to redirect the function in the header file and use it as
>> +   redirected_name.  */
>> +#define libc_ifunc_redirected(redirected_name, name, expr)	\
>> +  __ifunc (redirected_name, name, expr, void, INIT_ARCH)
>> +
>> +/* Use libc_ifunc_hidden if your ifunc'ed function has an internal symbol
>> +   which should be the ifunc'ed function'.  */
>> +#define libc_ifunc_hidden(redirected_name, name, expr)			\
>> +  __ifunc_hidden (redirected_name, name, expr, void, INIT_ARCH)
>>
>>  /* The body of the function is supposed to use __get_cpu_features
>>     which will, if necessary, initialize the data first.  */
>> -#define libm_ifunc(name, expr)						\
>> -  extern void *name##_ifunc (void) __asm__ (#name);			\
>> -  void *name##_ifunc (void)						\
>> -  {									\
>> -    __typeof (name) *res = expr;					\
>> -    return res;								\
>> -  }									\
>> -  __asm__ (".type " #name ", %gnu_indirect_function");
>> +#define libm_ifunc_init()
>> +#define libm_ifunc(name, expr) __ifunc (name, name, expr, void, libm_ifunc_init)
>
> Line too long.
>

Comments

Adhemerval Zanella Netto Oct. 4, 2016, 1:14 p.m. UTC | #1
Thanks, LGTM.

On 30/09/2016 10:45, Stefan Liebler wrote:
> Hi Adhemerval,
> 
> thanks for reviewing. I've split the too long lines and added a comment block for libc_ifunc{_redirected,_hidden} macros in include/libc-symbols.h.
> 
> Yes you are right, review for patch 9 is still missing. I've tested the s390 part on s390x/s390. If patch 9 is okay, I'll commit the patch series.
> 
> Thanks.
> Stefan
> 
> On 09/29/2016 08:38 PM, Adhemerval Zanella wrote:
>> Patch LGTM and a powerpc32/power7 (to actually uses ifunc) and a build/run
>> for powerpc64le seems ok.
>>
>> I see with recent Andreas ack of 4/9 that only 3/9 (s390 bits) and
>> 9/9 (siglongjmp, longjmp in libpthread) seems to be the impending
>> bits.  I plan to check on 9/9, but I won't be able to proper review
>> 3/9 since I do not have access to a s390 machine anymore.
>>
>> Some comments below:
>>
>> On 24/08/2016 07:04, Stefan Liebler wrote:
>>> diff --git a/include/libc-symbols.h b/include/libc-symbols.h
>>> index c2b499a..44e5253 100644
>>> --- a/include/libc-symbols.h
>>> +++ b/include/libc-symbols.h
>>> @@ -722,27 +722,64 @@ for linking")
>>>  # define compat_data_section .section ".data.compat", "aw";
>>>  #endif
>>>
>>> -/* Marker used for indirection function symbols.  */
>>> -#define libc_ifunc(name, expr)                        \
>>> -  extern void *name##_ifunc (void) __asm__ (#name);            \
>>> -  void *name##_ifunc (void)                        \
>>> +/* Helper / base  macros for indirect function symbols.  */
>>> +#define __ifunc_resolver(type_name, name, expr, arg, init, classifier)    \
>>> +  classifier void *name##_ifunc (arg)                    \
>>>    {                                    \
>>> -    INIT_ARCH ();                            \
>>> -    __typeof (name) *res = expr;                    \
>>> +    init ();                                \
>>> +    __typeof (type_name) *res = expr;                    \
>>>      return res;                                \
>>> -  }                                    \
>>> -  __asm__ (".type " #name ", %gnu_indirect_function");
>>> +  }
>>> +
>>> +#ifdef HAVE_GCC_IFUNC
>>> +# define __ifunc(type_name, name, expr, arg, init)            \
>>> +  extern __typeof (type_name) name __attribute__            \
>>> +                  ((ifunc (#name "_ifunc")));        \
>>> +  __ifunc_resolver (type_name, name, expr, arg, init, static)
>>> +
>>> +# define __ifunc_hidden(type_name, name, expr, arg, init)    \
>>> +  __ifunc (type_name, name, expr, arg, init)
>>> +#else
>>> +/* Gcc does not support __attribute__ ((ifunc (...))).  Use the old behaviour
>>> +   as fallback.  But keep in mind that the debug information for the ifunc
>>> +   resolver functions is not correct.  It contains the ifunc'ed function as
>>> +   DW_AT_linkage_name.  E.g. lldb uses this field and an inferior function
>>> +   call of the ifunc'ed function will fail due to "no matching function for call
>>
>> Line too long.
>>
>>> +   to ..." because the ifunc'ed function and the resolver function have
>>> +   different signatures.  (Gcc support is disabled at least on a ppc64le
>>> +   Ubuntu 14.04 system.)  */
>>> +
>>> +# define __ifunc(type_name, name, expr, arg, init)            \
>>> +  extern __typeof (type_name) name;                    \
>>> +  void *name##_ifunc (arg) __asm__ (#name);                \
>>> +  __ifunc_resolver (type_name, name, expr, arg, init,)            \
>>> + __asm__ (".type " #name ", %gnu_indirect_function");
>>> +
>>> +# define __ifunc_hidden(type_name, name, expr, arg, init)        \
>>> +  extern __typeof (type_name) __libc_##name;                \
>>> +  __ifunc (type_name, __libc_##name, expr, arg, init)            \
>>> +  strong_alias (__libc_##name, name);
>>> +#endif /* !HAVE_GCC_IFUNC  */
>>> +
>>> +/* Use libc_ifunc if your ifunc'ed function has no internal symbol.  */
>>> +#define libc_ifunc(name, expr) __ifunc (name, name, expr, void, INIT_ARCH)
>>
>> I think it will be valuable to add a comment like the one on same
>> file at line 341 with a usage example on how to use
>> libc_ifunc{_redirected,_hidden} and difference between each usage and
>> the possible requirements (such as name redirection).
>>
>>> +
>>> +/* Use libc_ifunc_redirected if your ifunc'ed function has an internal symbol
>>> +   which should be a dedicated fallback function instead of ifunc'ed.
>>> +   You have to redirect the function in the header file and use it as
>>> +   redirected_name.  */
>>> +#define libc_ifunc_redirected(redirected_name, name, expr)    \
>>> +  __ifunc (redirected_name, name, expr, void, INIT_ARCH)
>>> +
>>> +/* Use libc_ifunc_hidden if your ifunc'ed function has an internal symbol
>>> +   which should be the ifunc'ed function'.  */
>>> +#define libc_ifunc_hidden(redirected_name, name, expr)            \
>>> +  __ifunc_hidden (redirected_name, name, expr, void, INIT_ARCH)
>>>
>>>  /* The body of the function is supposed to use __get_cpu_features
>>>     which will, if necessary, initialize the data first.  */
>>> -#define libm_ifunc(name, expr)                        \
>>> -  extern void *name##_ifunc (void) __asm__ (#name);            \
>>> -  void *name##_ifunc (void)                        \
>>> -  {                                    \
>>> -    __typeof (name) *res = expr;                    \
>>> -    return res;                                \
>>> -  }                                    \
>>> -  __asm__ (".type " #name ", %gnu_indirect_function");
>>> +#define libm_ifunc_init()
>>> +#define libm_ifunc(name, expr) __ifunc (name, name, expr, void, libm_ifunc_init)
>>
>> Line too long.
>>
>
diff mbox

Patch

commit 9e95c428798b86f8bf0c7c1eaf8434266220f1ab
Author: Stefan Liebler <stli@linux.vnet.ibm.com>
Date:   Wed Aug 24 10:18:14 2016 +0200

    Use gcc attribute ifunc in libc_ifunc macro instead of inline assembly due to false debuginfo.
    
    The current s390 ifunc resolver for vector optimized functions and the common
    libc_ifunc macro in include/libc-symbols.h uses something like that to generate ifunc'ed functions:
    extern void *__resolve___strlen(unsigned long int dl_hwcap) asm (strlen);
    asm (".type strlen, %gnu_indirect_function");
    
    This leads to false debug information:
    objdump --dwarf=info libc.so:
    ...
    <1><1e6424>: Abbrev Number: 43 (DW_TAG_subprogram)
        <1e6425>   DW_AT_external    : 1
        <1e6425>   DW_AT_name        : (indirect string, offset: 0x1146e): __resolve___strlen
        <1e6429>   DW_AT_decl_file   : 1
        <1e642a>   DW_AT_decl_line   : 23
        <1e642b>   DW_AT_linkage_name: (indirect string, offset: 0x1147a): strlen
        <1e642f>   DW_AT_prototyped  : 1
        <1e642f>   DW_AT_type        : <0x1e4ccd>
        <1e6433>   DW_AT_low_pc      : 0x998e0
        <1e643b>   DW_AT_high_pc     : 0x16
        <1e6443>   DW_AT_frame_base  : 1 byte block: 9c     (DW_OP_call_frame_cfa)
        <1e6445>   DW_AT_GNU_all_call_sites: 1
        <1e6445>   DW_AT_sibling     : <0x1e6459>
     <2><1e6449>: Abbrev Number: 44 (DW_TAG_formal_parameter)
        <1e644a>   DW_AT_name        : (indirect string, offset: 0x1845): dl_hwcap
        <1e644e>   DW_AT_decl_file   : 1
        <1e644f>   DW_AT_decl_line   : 23
        <1e6450>   DW_AT_type        : <0x1e4c8d>
        <1e6454>   DW_AT_location    : 0x122115 (location list)
    ...
    
    The debuginfo for the ifunc-resolver function contains the DW_AT_linkage_name
    field, which names the real function name "strlen". If you perform an inferior
    function call to strlen in lldb, then it fails due to something like that:
    "error: no matching function for call to 'strlen'
    candidate function not viable: no known conversion from 'const char [6]'
    to 'unsigned long' for 1st argument"
    
    The unsigned long is the dl_hwcap argument of the resolver function.
    The strlen function itself has no debufinfo.
    
    The s390 ifunc resolver for memset & co uses something like that:
    asm (".globl FUNC"
         ".type FUNC, @gnu_indirect_function"
         ".set FUNC, __resolve_FUNC");
    
    This way the debuginfo for the ifunc-resolver function does not conain the
    DW_AT_linkage_name field and the real function has no debuginfo, too.
    
    Using this strategy for the vector optimized functions leads to some troubles
    for functions like strnlen. Here we have __strnlen and a weak alias strnlen.
    The __strnlen function is the ifunc function, which is realized with the asm-
    statement above. The weak_alias-macro can't be used here due to undefined symbol:
    gcc ../sysdeps/s390/multiarch/strnlen.c -c ...
    In file included from <command-line>:0:0:
    ../sysdeps/s390/multiarch/strnlen.c:28:24: error: ‘strnlen’ aliased to undefined symbol ‘__strnlen’
     weak_alias (__strnlen, strnlen)
                            ^
    ./../include/libc-symbols.h:111:26: note: in definition of macro ‘_weak_alias’
       extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
                              ^
    ../sysdeps/s390/multiarch/strnlen.c:28:1: note: in expansion of macro ‘weak_alias’
     weak_alias (__strnlen, strnlen)
     ^
    make[2]: *** [build/string/strnlen.o] Error 1
    
    As the __strnlen function is defined with asm-statements the function name
    __strnlen isn't known by gcc. But the weak alias can also be done with an
    asm statement to resolve this issue:
    __asm__ (".weak  strnlen\n\t"
             ".set   strnlen,__strnlen\n");
    
    In order to use the weak_alias macro, gcc needs to know the ifunc function. The
    minimum gcc to build glibc is currently 4.7, which supports attribute((ifunc)).
    See https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html.
    It is only supported if gcc is configured with --enable-gnu-indirect-function
    or gcc supports it by default for at least intel and s390x architecture.
    This patch uses the old behaviour if gcc support is not available.
    Usage of attribute ifunc is something like that:
    __typeof (FUNC) FUNC __attribute__ ((ifunc ("__resolve_FUNC")));
    
    Then gcc produces the same .globl, .type, .set assembler instructions like above.
    And the debuginfo does not contain the DW_AT_linkage_name field and there is no
    debuginfo for the real function, too.
    
    But in order to get it work, there is also some extra work to do.
    Currently, the glibc internal symbol on s390x e.g. __GI___strnlen is not the
    ifunc symbol, but the fallback __strnlen_c symbol. Thus I have to omit the
    libc_hidden_def macro in strnlen.c (here is the ifunc function __strnlen)
    because it is already handled in strnlen-c.c (here is __strnlen_c).
    
    Due to libc_hidden_proto (__strnlen) in string.h, compiling fails:
    gcc ../sysdeps/s390/multiarch/strnlen.c -c ...
    In file included from <command-line>:0:0:
    ../sysdeps/s390/multiarch/strnlen.c:53:24: error: ‘strnlen’ aliased to undefined symbol ‘__strnlen’
     weak_alias (__strnlen, strnlen)
                            ^
    ./../include/libc-symbols.h:111:26: note: in definition of macro ‘_weak_alias’
       extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
                              ^
    ../sysdeps/s390/multiarch/strnlen.c:53:1: note: in expansion of macro ‘weak_alias’
     weak_alias (__strnlen, strnlen)
     ^
    make[2]: *** [build/string/strnlen.os] Error 1
    
    I have to redirect the prototypes for __strnlen in string.h and create a copy
    of the prototype for using as ifunc function:
    __typeof (__redirect___strnlen) __strnlen __attribute__ ((ifunc ("__resolve_strnlen")));
    weak_alias (__strnlen, strnlen)
    
    This way there is no trouble with the internal __GI_* symbols.
    Glibc builds fine with this construct and the debuginfo is "correct".
    For functions without a __GI_* symbol like memccpy this redirection is not needed.
    
    This patch adjusts the common libc_ifunc and libm_ifunc macro to use gcc
    attribute ifunc. Due to this change, the macro users where the __GI_* symbol
    does not target the ifunc symbol have to be prepared with the redirection
    construct.
    Furthermore a configure check to test gcc support is added. If it is not supported,
    the old behaviour is used.
    
    This patch also prepares the libc_ifunc macro to be useable in s390-ifunc-macro.
    The s390 ifunc-resolver-functions do have an hwcaps parameter and not all
    resolvers need the same initialization code. The next patch in this series
    changes the s390 ifunc macros to use this common one.
    
    ChangeLog:
    
    	* include/libc-symbols.h (__ifunc_resolver):
    	New macro is used by __ifunc* macros.
    	(__ifunc): New macro uses gcc attribute ifunc or inline assembly
    	depending on HAVE_GCC_IFUNC.
    	(libc_ifunc, libm_ifunc): Use __ifunc as base macro.
    	(libc_ifunc_redirected, libc_ifunc_hidden, libm_ifunc_init): New macro.
    	* sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finite.c:
    	Redirect ifunced function in header for using as type for ifunc function.
    	* sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finitef.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinf.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinff.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnan.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/memcmp.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/memcpy.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/memmove.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/mempcpy.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/memset.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/rawmemchr.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/strchr.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/strlen.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/strncmp.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/multiarch/strnlen.c: Likewise.
    	* sysdeps/powerpc/powerpc64/fpu/multiarch/s_finite.c: Likewise.
    	* sysdeps/powerpc/powerpc64/fpu/multiarch/s_finitef.c: Likewise.
    	* sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinf.c: Likewise.
    	* sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinff.c: Likewise.
    	* sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/memcmp.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/mempcpy.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/stpncpy.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strcat.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strchr.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strcmp.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strcpy.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strncmp.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strncpy.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strnlen.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strrchr.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/strstr.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/wcschr.c: Likewise.
    	* sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnanf.c:
    	Add libc_hidden_def() and use libc_ifunc_hidden() macro
    	instead of libc_ifunc() macro.
    	* sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnanf.c: Likewise.
    	* sysdeps/powerpc/powerpc64/multiarch/stpcpy.c: Likewise.

diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index e362d42..6ae309a 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -737,27 +737,137 @@  for linking")
 # define compat_data_section .section ".data.compat", "aw";
 #endif
 
-/* Marker used for indirection function symbols.  */
-#define libc_ifunc(name, expr)						\
-  extern void *name##_ifunc (void) __asm__ (#name);			\
-  void *name##_ifunc (void)						\
+/* Helper / base  macros for indirect function symbols.  */
+#define __ifunc_resolver(type_name, name, expr, arg, init, classifier)	\
+  classifier void *name##_ifunc (arg)					\
   {									\
-    INIT_ARCH ();							\
-    __typeof (name) *res = expr;					\
+    init ();								\
+    __typeof (type_name) *res = expr;					\
     return res;								\
-  }									\
-  __asm__ (".type " #name ", %gnu_indirect_function");
+  }
+
+#ifdef HAVE_GCC_IFUNC
+# define __ifunc(type_name, name, expr, arg, init)			\
+  extern __typeof (type_name) name __attribute__			\
+			      ((ifunc (#name "_ifunc")));		\
+  __ifunc_resolver (type_name, name, expr, arg, init, static)
+
+# define __ifunc_hidden(type_name, name, expr, arg, init)	\
+  __ifunc (type_name, name, expr, arg, init)
+#else
+/* Gcc does not support __attribute__ ((ifunc (...))).  Use the old behaviour
+   as fallback.  But keep in mind that the debug information for the ifunc
+   resolver functions is not correct.  It contains the ifunc'ed function as
+   DW_AT_linkage_name.  E.g. lldb uses this field and an inferior function
+   call of the ifunc'ed function will fail due to "no matching function for
+   call to ..." because the ifunc'ed function and the resolver function have
+   different signatures.  (Gcc support is disabled at least on a ppc64le
+   Ubuntu 14.04 system.)  */
+
+# define __ifunc(type_name, name, expr, arg, init)			\
+  extern __typeof (type_name) name;					\
+  void *name##_ifunc (arg) __asm__ (#name);				\
+  __ifunc_resolver (type_name, name, expr, arg, init,)			\
+ __asm__ (".type " #name ", %gnu_indirect_function");
+
+# define __ifunc_hidden(type_name, name, expr, arg, init)		\
+  extern __typeof (type_name) __libc_##name;				\
+  __ifunc (type_name, __libc_##name, expr, arg, init)			\
+  strong_alias (__libc_##name, name);
+#endif /* !HAVE_GCC_IFUNC  */
+
+/* The following macros are used for indirect function symbols in libc.so.
+   First of all, you need to have the function prototyped somewhere,
+   say in foo.h:
+
+   int foo (int __bar);
+
+   If you have an implementation for foo which e.g. uses a special hardware
+   feature which isn't available on all machines where this libc.so will be
+   used but decideable if available at runtime e.g. via hwcaps, you can provide
+   two or multiple implementations of foo:
+
+   int __foo_default (int __bar)
+   {
+     return __bar;
+   }
+
+   int __foo_special (int __bar)
+   {
+     return __bar;
+   }
+
+   If your function foo has no libc_hidden_proto (foo) defined for PLT
+   bypassing, you can use:
+
+   #define INIT_ARCH() unsigned long int hwcap = __GLRO(dl_hwcap);
+
+   libc_ifunc (foo, (hwcap & HWCAP_SPECIAL) ? __foo_special : __foo_default);
+
+   This will define a resolver function for foo which returns __foo_special or
+   __foo_default depending on your specified expression.  Please note that you
+   have to define a macro function INIT_ARCH before using libc_ifunc macro as
+   it is called by the resolver function before evaluating the specified
+   expression.  In this example it is used to prepare the hwcap variable.
+   The resolver function is assigned to an ifunc'ed symbol foo.  Calls to foo
+   from inside or outside of libc.so will be indirected by a PLT call.
+
+   If your function foo has a libc_hidden_proto (foo) defined for PLT bypassing
+   and calls to foo within libc.so should always go to one specific
+   implementation of foo e.g. __foo_default then you have to add:
+
+   __hidden_ver1 (__foo_default, __GI_foo, __foo_default);
+
+   or a tweaked definition of libc_hidden_def macro after the __foo_default
+   function definition.  Calls to foo within libc.so will always go directly to
+   __foo_default.  Calls to foo from outside libc.so will be indirected by a
+   PLT call to ifunc'ed symbol foo which you have to define in a separate
+   compile unit:
+
+   #define foo __redirect_foo
+   #include <foo.h>
+   #undef foo
+
+   extern __typeof (__redirect_foo) __foo_default attribute_hidden;
+   extern __typeof (__redirect_foo) __foo_special attribute_hidden;
+
+   libc_ifunc_redirected (__redirect_foo, foo,
+			  (hwcap & HWCAP_SPECIAL)
+			  ? __foo_special
+			  : __foo_default);
+
+   This will define the ifunc'ed symbol foo like above.  The redirection of foo
+   in header file is needed to omit an additional defintion of __GI_foo which
+   would end in a linker error while linking libc.so.  You have to specify
+   __redirect_foo as first parameter which is used within libc_ifunc_redirected
+   macro in conjunction with typeof to define the ifunc'ed symbol foo.
+
+   If your function foo has a libc_hidden_proto (foo) defined and calls to foo
+   within or from outside libc.so should go via ifunc'ed symbol, then you have
+   to use:
+
+   libc_ifunc_hidden (foo, foo,
+		      (hwcap & HWCAP_SPECIAL)
+		      ? __foo_special
+		      : __foo_default);
+   libc_hidden_def (foo)
+
+   The first parameter foo of libc_ifunc_hidden macro is used in the same way
+   as for libc_ifunc_redirected macro.  */
+
+#define libc_ifunc(name, expr) __ifunc (name, name, expr, void, INIT_ARCH)
+
+#define libc_ifunc_redirected(redirected_name, name, expr)	\
+  __ifunc (redirected_name, name, expr, void, INIT_ARCH)
+
+#define libc_ifunc_hidden(redirected_name, name, expr)			\
+  __ifunc_hidden (redirected_name, name, expr, void, INIT_ARCH)
 
 /* The body of the function is supposed to use __get_cpu_features
    which will, if necessary, initialize the data first.  */
-#define libm_ifunc(name, expr)						\
-  extern void *name##_ifunc (void) __asm__ (#name);			\
-  void *name##_ifunc (void)						\
-  {									\
-    __typeof (name) *res = expr;					\
-    return res;								\
-  }									\
-  __asm__ (".type " #name ", %gnu_indirect_function");
+#define libm_ifunc_init()
+#define libm_ifunc(name, expr)				\
+  __ifunc (name, name, expr, void, libm_ifunc_init)
 
 #ifdef HAVE_ASM_SET_DIRECTIVE
 # define libc_ifunc_hidden_def1(local, name)				\
diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finite.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finite.c
index c860a1b..0c0d128 100644
--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finite.c
+++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finite.c
@@ -16,6 +16,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __finite __redirect___finite
+#define __finitef __redirect___finitef
+#define __finitel __redirect___finitel
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -23,11 +26,14 @@ 
 
 extern __typeof (__finite) __finite_ppc32 attribute_hidden;
 extern __typeof (__finite) __finite_power7 attribute_hidden;
-
-libc_ifunc (__finite,
-	    (hwcap & PPC_FEATURE_ARCH_2_06)
-	    ? __finite_power7
-            : __finite_ppc32);
+#undef __finite
+#undef __finitef
+#undef __finitel
+
+libc_ifunc_redirected (__redirect___finite,  __finite,
+		       (hwcap & PPC_FEATURE_ARCH_2_06)
+		       ? __finite_power7
+		       : __finite_ppc32);
 
 weak_alias (__finite, finite)
 
diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finitef.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finitef.c
index 831c94f..683477a 100644
--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finitef.c
+++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_finitef.c
@@ -16,6 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __finitef __redirect___finitef
 #include <math.h>
 #include <shlib-compat.h>
 #include "init-arch.h"
@@ -23,10 +24,11 @@ 
 extern __typeof (__finitef) __finitef_ppc32 attribute_hidden;
 /* The power7 finite(double) works for float.  */
 extern __typeof (__finitef) __finite_power7 attribute_hidden;
+#undef __finitef
 
-libc_ifunc (__finitef,
-	    (hwcap & PPC_FEATURE_ARCH_2_06)
-	    ? __finite_power7
-            : __finitef_ppc32);
+libc_ifunc_redirected  (__redirect___finitef, __finitef,
+			(hwcap & PPC_FEATURE_ARCH_2_06)
+			? __finite_power7
+			: __finitef_ppc32);
 
 weak_alias (__finitef, finitef)
diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinf.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinf.c
index 506c111..fe6c912 100644
--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinf.c
+++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinf.c
@@ -16,6 +16,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __isinf __redirect___isinf
+#define __isinff __redirect___isinff
+#define __isinfl __redirect___isinfl
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -23,11 +26,14 @@ 
 
 extern __typeof (__isinf) __isinf_ppc32 attribute_hidden;
 extern __typeof (__isinf) __isinf_power7 attribute_hidden;
-
-libc_ifunc (__isinf,
-	    (hwcap & PPC_FEATURE_ARCH_2_06)
-	    ? __isinf_power7
-            : __isinf_ppc32);
+#undef __isinf
+#undef __isinff
+#undef __isinfl
+
+libc_ifunc_redirected (__redirect___isinf,  __isinf,
+		       (hwcap & PPC_FEATURE_ARCH_2_06)
+		       ? __isinf_power7
+		       : __isinf_ppc32);
 
 weak_alias (__isinf, isinf)
 
diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinff.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinff.c
index 2ab83ee..1706092 100644
--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinff.c
+++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isinff.c
@@ -16,6 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __isinff __redirect___isinff
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -24,10 +25,11 @@ 
 extern __typeof (__isinff) __isinff_ppc32 attribute_hidden;
 /* The power7 isinf(double) works for float.  */
 extern __typeof (__isinff) __isinf_power7 attribute_hidden;
+#undef __isinff
 
-libc_ifunc (__isinff,
-	    (hwcap & PPC_FEATURE_ARCH_2_06)
-	    ? __isinf_power7
-            : __isinff_ppc32);
+libc_ifunc_redirected (__redirect___isinff,  __isinff,
+		       (hwcap & PPC_FEATURE_ARCH_2_06)
+		       ? __isinf_power7
+		       : __isinff_ppc32);
 
 weak_alias (__isinff, isinff)
diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnan.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnan.c
index 8f848d7..3655b81 100644
--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnan.c
+++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnan.c
@@ -16,6 +16,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __isnan __redirect___isnan
+#define __isnanf __redirect___isnanf
+#define __isnanl __redirect___isnanl
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -25,15 +28,18 @@  extern __typeof (__isnan) __isnan_ppc32 attribute_hidden;
 extern __typeof (__isnan) __isnan_power5 attribute_hidden;
 extern __typeof (__isnan) __isnan_power6 attribute_hidden;
 extern __typeof (__isnan) __isnan_power7 attribute_hidden;
-
-libc_ifunc (__isnan,
-	    (hwcap & PPC_FEATURE_ARCH_2_06)
-	    ? __isnan_power7 :
-	      (hwcap & PPC_FEATURE_ARCH_2_05)
-	      ? __isnan_power6 :
-		(hwcap & PPC_FEATURE_POWER5)
-		? __isnan_power5
-            : __isnan_ppc32);
+#undef __isnan
+#undef __isnanf
+#undef __isnanl
+
+libc_ifunc_redirected (__redirect___isnan, __isnan,
+		       (hwcap & PPC_FEATURE_ARCH_2_06)
+		       ? __isnan_power7
+		       : (hwcap & PPC_FEATURE_ARCH_2_05)
+			 ? __isnan_power6
+			 : (hwcap & PPC_FEATURE_POWER5)
+			   ? __isnan_power5
+			   : __isnan_ppc32);
 
 weak_alias (__isnan, isnan)
 
diff --git a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnanf.c b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnanf.c
index c43c0f3..e1d6707 100644
--- a/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnanf.c
+++ b/sysdeps/powerpc/powerpc32/power4/fpu/multiarch/s_isnanf.c
@@ -26,13 +26,14 @@  extern __typeof (__isnanf) __isnanf_power5 attribute_hidden;
 extern __typeof (__isnanf) __isnanf_power6 attribute_hidden;
 extern __typeof (__isnanf) __isnan_power7 attribute_hidden;
 
-libc_ifunc (__isnanf,
-	    (hwcap & PPC_FEATURE_ARCH_2_06)
-	    ? __isnan_power7 :
-	      (hwcap & PPC_FEATURE_ARCH_2_05)
-	      ? __isnanf_power6 :
-		(hwcap & PPC_FEATURE_POWER5)
-		? __isnanf_power5
-            : __isnan_ppc32);
+libc_ifunc_hidden (__isnanf, __isnanf,
+		   (hwcap & PPC_FEATURE_ARCH_2_06)
+		   ? __isnan_power7
+		   : (hwcap & PPC_FEATURE_ARCH_2_05)
+		     ? __isnanf_power6
+		     : (hwcap & PPC_FEATURE_POWER5)
+		       ? __isnanf_power5
+		       : __isnan_ppc32);
 
+hidden_def (__isnanf)
 weak_alias (__isnanf, isnanf)
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp.c b/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp.c
index c08519c..49d424f 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp.c
@@ -18,17 +18,19 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if IS_IN (libc)
+# define memcmp __redirect_memcmp
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (memcmp) __memcmp_ppc attribute_hidden;
 extern __typeof (memcmp) __memcmp_power7 attribute_hidden;
+# undef memcmp
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (memcmp,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __memcmp_power7
-            : __memcmp_ppc);
+libc_ifunc_redirected (__redirect_memcmp, memcmp,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __memcmp_power7
+		       : __memcmp_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/memcpy.c b/sysdeps/powerpc/powerpc32/power4/multiarch/memcpy.c
index f379e47..1a5da21 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/memcpy.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/memcpy.c
@@ -20,6 +20,8 @@ 
    DSO.  In static binaries we need memcpy before the initialization
    happened.  */
 #if defined SHARED && IS_IN (libc)
+# undef memcpy
+# define memcpy __redirect_memcpy
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -29,17 +31,18 @@  extern __typeof (memcpy) __memcpy_cell attribute_hidden;
 extern __typeof (memcpy) __memcpy_power6 attribute_hidden;
 extern __typeof (memcpy) __memcpy_a2 attribute_hidden;
 extern __typeof (memcpy) __memcpy_power7 attribute_hidden;
+# undef memcpy
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (memcpy,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __memcpy_power7 :
-	      (hwcap & PPC_FEATURE_ARCH_2_06)
-	      ? __memcpy_a2 :
-		(hwcap & PPC_FEATURE_ARCH_2_05)
-		? __memcpy_power6 :
-		  (hwcap & PPC_FEATURE_CELL_BE)
-		  ? __memcpy_cell
-            : __memcpy_ppc);
+libc_ifunc_redirected (__redirect_memcpy, memcpy,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __memcpy_power7
+		       : (hwcap & PPC_FEATURE_ARCH_2_06)
+			 ? __memcpy_a2
+			 : (hwcap & PPC_FEATURE_ARCH_2_05)
+			   ? __memcpy_power6
+			   : (hwcap & PPC_FEATURE_CELL_BE)
+			     ? __memcpy_cell
+			     : __memcpy_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/memmove.c b/sysdeps/powerpc/powerpc32/power4/multiarch/memmove.c
index 4173184..1dfb5be 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/memmove.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/memmove.c
@@ -19,16 +19,18 @@ 
 #if defined SHARED && IS_IN (libc)
 /* Redefine memmove so that the compiler won't complain about the type
    mismatch with the IFUNC selector in strong_alias, below.  */
+# define memmove __redirect_memmove
 # include <string.h>
 # include "init-arch.h"
 
 extern __typeof (memmove) __memmove_ppc attribute_hidden;
 extern __typeof (memmove) __memmove_power7 attribute_hidden;
+# undef memmove
 
-libc_ifunc (memmove,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __memmove_power7
-            : __memmove_ppc);
+libc_ifunc_redirected (__redirect_memmove, memmove,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __memmove_power7
+		       : __memmove_ppc);
 #else
 # include <string/memmove.c>
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/mempcpy.c b/sysdeps/powerpc/powerpc32/power4/multiarch/mempcpy.c
index 3c77b5f..3c7c644 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/mempcpy.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/mempcpy.c
@@ -17,23 +17,28 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define mempcpy __redirect_mempcpy
+# define __mempcpy __redirect___mempcpy
 # define NO_MEMPCPY_STPCPY_REDIRECT
+/* Omit the mempcpy inline definitions because it would redefine mempcpy.  */
+# define _HAVE_STRING_ARCH_mempcpy 1
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (__mempcpy) __mempcpy_ppc attribute_hidden;
 extern __typeof (__mempcpy) __mempcpy_power7 attribute_hidden;
+# undef mempcpy
+# undef __mempcpy
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (__mempcpy,
-	    (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __mempcpy_power7
-            : __mempcpy_ppc);
+libc_ifunc_redirected (__redirect___mempcpy,  __mempcpy,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __mempcpy_power7
+		       : __mempcpy_ppc);
 
 weak_alias (__mempcpy, mempcpy)
-libc_hidden_def (mempcpy)
 #else
 # include <string/mempcpy.c>
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/memset.c b/sysdeps/powerpc/powerpc32/power4/multiarch/memset.c
index 1d7fc7f..a5c0142 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/memset.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/memset.c
@@ -18,6 +18,7 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if defined SHARED && IS_IN (libc)
+# define memset __redirect_memset
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -25,13 +26,14 @@ 
 extern __typeof (memset) __memset_ppc attribute_hidden;
 extern __typeof (memset) __memset_power6 attribute_hidden;
 extern __typeof (memset) __memset_power7 attribute_hidden;
+# undef memset
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (memset,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __memset_power7 :
-	      (hwcap & PPC_FEATURE_ARCH_2_05)
-		? __memset_power6
-            : __memset_ppc);
+libc_ifunc_redirected (__redirect_memset, memset,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __memset_power7
+		       : (hwcap & PPC_FEATURE_ARCH_2_05)
+			 ? __memset_power6
+			 : __memset_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/rawmemchr.c b/sysdeps/powerpc/powerpc32/power4/multiarch/rawmemchr.c
index f06030e..d72b5df 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/rawmemchr.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/rawmemchr.c
@@ -17,20 +17,21 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define __rawmemchr __redirect___rawmemchr
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (__rawmemchr) __rawmemchr_ppc attribute_hidden;
 extern __typeof (__rawmemchr) __rawmemchr_power7 attribute_hidden;
+# undef __rawmemchr
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (__rawmemchr,
-	    (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __rawmemchr_power7
-            : __rawmemchr_ppc);
-
+libc_ifunc_redirected (__redirect___rawmemchr, __rawmemchr,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __rawmemchr_power7
+		       : __rawmemchr_ppc);
 weak_alias (__rawmemchr, rawmemchr)
 #else
 #include <string/rawmemchr.c>
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/strchr.c b/sysdeps/powerpc/powerpc32/power4/multiarch/strchr.c
index 2cfde63..c23384f 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/strchr.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/strchr.c
@@ -18,18 +18,22 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if defined SHARED && IS_IN (libc)
+# define strchr __redirect_strchr
+/* Omit the strchr inline definitions because it would redefine strchr.  */
+# define __NO_STRING_INLINES
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (strchr) __strchr_ppc attribute_hidden;
 extern __typeof (strchr) __strchr_power7 attribute_hidden;
+# undef strchr
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (strchr,
-	    (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strchr_power7
-            : __strchr_ppc);
+libc_ifunc_redirected (__redirect_strchr,  strchr,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strchr_power7
+		       : __strchr_ppc);
 weak_alias (strchr, index)
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/strlen.c b/sysdeps/powerpc/powerpc32/power4/multiarch/strlen.c
index af5921a..b676b26 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/strlen.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/strlen.c
@@ -17,15 +17,17 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined SHARED && IS_IN (libc)
+# define strlen __redirect_strlen
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (strlen) __strlen_ppc attribute_hidden;
 extern __typeof (strlen) __strlen_power7 attribute_hidden;
+# undef strlen
 
-libc_ifunc (strlen,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strlen_power7
-            : __strlen_ppc);
+libc_ifunc_redirected (__redirect_strlen, strlen,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strlen_power7
+		       : __strlen_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/strncmp.c b/sysdeps/powerpc/powerpc32/power4/multiarch/strncmp.c
index 7cc7628..c384b4c 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/strncmp.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/strncmp.c
@@ -18,6 +18,9 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if defined SHARED && IS_IN (libc)
+# define strncmp __redirect_strncmp
+/* Omit the strncmp inline definitions because it would redefine strncmp.  */
+# define __NO_STRING_INLINES
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -25,11 +28,12 @@ 
 extern __typeof (strncmp) __strncmp_ppc attribute_hidden;
 extern __typeof (strncmp) __strncmp_power4 attribute_hidden;
 extern __typeof (strncmp) __strncmp_power7 attribute_hidden;
+# undef strncmp
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (strncmp,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strncmp_power7
-            : __strncmp_ppc);
+libc_ifunc_redirected (__redirect_strncmp, strncmp,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strncmp_power7
+		       : __strncmp_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/strnlen.c b/sysdeps/powerpc/powerpc32/power4/multiarch/strnlen.c
index 8f1e7c9..c3681be 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/strnlen.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/strnlen.c
@@ -17,17 +17,20 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define strnlen __redirect_strnlen
+# define __strnlen __redirect___strnlen
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (__strnlen) __strnlen_ppc attribute_hidden;
 extern __typeof (__strnlen) __strnlen_power7 attribute_hidden;
+# undef strnlen
+# undef __strnlen
 
-libc_ifunc (__strnlen,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strnlen_power7
-            : __strnlen_ppc);
+libc_ifunc_redirected (__redirect___strnlen, __strnlen,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strnlen_power7
+		       : __strnlen_ppc);
 weak_alias (__strnlen, strnlen)
-libc_hidden_def (strnlen)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finite.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finite.c
index 067edc2..c7d67f1 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finite.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finite.c
@@ -16,6 +16,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __finite __redirect___finite
+#define __finitef __redirect___finitef
+#define __finitel __redirect___finitel
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -24,13 +27,16 @@ 
 extern __typeof (__finite) __finite_ppc64 attribute_hidden;
 extern __typeof (__finite) __finite_power7 attribute_hidden;
 extern __typeof (__finite) __finite_power8 attribute_hidden;
-
-libc_ifunc (__finite,
-	    (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-	    ? __finite_power8 :
-	      (hwcap & PPC_FEATURE_ARCH_2_06)
-	      ? __finite_power7
-            : __finite_ppc64);
+#undef __finite
+#undef __finitef
+#undef __finitel
+
+libc_ifunc_redirected (__redirect___finite, __finite,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __finite_power8
+		       : (hwcap & PPC_FEATURE_ARCH_2_06)
+			 ? __finite_power7
+			 : __finite_ppc64);
 
 weak_alias (__finite, finite)
 
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finitef.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finitef.c
index e0b4686..c9ecd0d 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finitef.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_finitef.c
@@ -16,6 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __finitef __redirect___finitef
 #include <math.h>
 #include <shlib-compat.h>
 #include "init-arch.h"
@@ -24,12 +25,13 @@  extern __typeof (__finitef) __finitef_ppc64 attribute_hidden;
 /* The double-precision version also works for single-precision.  */
 extern __typeof (__finitef) __finite_power7 attribute_hidden;
 extern __typeof (__finitef) __finite_power8 attribute_hidden;
+#undef __finitef
 
-libc_ifunc (__finitef,
-	    (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-	    ? __finite_power8 :
-	      (hwcap & PPC_FEATURE_ARCH_2_06)
-	      ? __finite_power7
-            : __finitef_ppc64);
+libc_ifunc_redirected (__redirect___finitef, __finitef,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __finite_power8
+		       : (hwcap & PPC_FEATURE_ARCH_2_06)
+			 ? __finite_power7
+			 : __finitef_ppc64);
 
 weak_alias (__finitef, finitef)
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinf.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinf.c
index 07e159d..a13ec27 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinf.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinf.c
@@ -16,6 +16,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __isinf __redirect___isinf
+#define __isinff __redirect___isinff
+#define __isinfl __redirect___isinfl
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -24,13 +27,16 @@ 
 extern __typeof (__isinf) __isinf_ppc64 attribute_hidden;
 extern __typeof (__isinf) __isinf_power7 attribute_hidden;
 extern __typeof (__isinf) __isinf_power8 attribute_hidden;
-
-libc_ifunc (__isinf,
-	    (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-	    ? __isinf_power8 :
-	      (hwcap & PPC_FEATURE_ARCH_2_06)
-	      ? __isinf_power7
-            : __isinf_ppc64);
+#undef __isinf
+#undef __isinff
+#undef __isinfl
+
+libc_ifunc_redirected (__redirect___isinf, __isinf,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __isinf_power8
+		       : (hwcap & PPC_FEATURE_ARCH_2_06)
+			 ? __isinf_power7
+			 : __isinf_ppc64);
 
 weak_alias (__isinf, isinf)
 
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinff.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinff.c
index 2cb161b..cafc118 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinff.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isinff.c
@@ -16,6 +16,7 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __isinff __redirect___isinff
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -25,12 +26,13 @@  extern __typeof (__isinff) __isinff_ppc64 attribute_hidden;
 /* The double-precision version also works for single-precision.  */
 extern __typeof (__isinff) __isinf_power7 attribute_hidden;
 extern __typeof (__isinff) __isinf_power8 attribute_hidden;
+#undef __isinff
 
-libc_ifunc (__isinff,
-	    (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-	    ? __isinf_power8 :
-	      (hwcap & PPC_FEATURE_ARCH_2_06)
-	      ? __isinf_power7
-            : __isinff_ppc64);
+libc_ifunc_redirected (__redirect___isinff, __isinff,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __isinf_power8
+		       : (hwcap & PPC_FEATURE_ARCH_2_06)
+			 ? __isinf_power7
+			 : __isinff_ppc64);
 
 weak_alias (__isinff, isinff)
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan.c
index a614f25..fce3c9d 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnan.c
@@ -16,6 +16,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#define __isnan __redirect___isnan
+#define __isnanf __redirect___isnanf
+#define __isnanl __redirect___isnanl
 #include <math.h>
 #include <math_ldbl_opt.h>
 #include <shlib-compat.h>
@@ -27,19 +30,22 @@  extern __typeof (__isnan) __isnan_power6 attribute_hidden;
 extern __typeof (__isnan) __isnan_power6x attribute_hidden;
 extern __typeof (__isnan) __isnan_power7 attribute_hidden;
 extern __typeof (__isnan) __isnan_power8 attribute_hidden;
-
-libc_ifunc (__isnan,
-	    (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-	    ? __isnan_power8 :
-	      (hwcap & PPC_FEATURE_ARCH_2_06)
-	      ? __isnan_power7 :
-		(hwcap & PPC_FEATURE_POWER6_EXT)
-		? __isnan_power6x :
-		  (hwcap & PPC_FEATURE_ARCH_2_05)
-		    ? __isnan_power6 :
-		    (hwcap & PPC_FEATURE_POWER5)
-		      ? __isnan_power5
-            : __isnan_ppc64);
+#undef __isnan
+#undef __isnanf
+#undef __isnanl
+
+libc_ifunc_redirected (__redirect___isnan, __isnan,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __isnan_power8
+		       : (hwcap & PPC_FEATURE_ARCH_2_06)
+			 ? __isnan_power7
+			 : (hwcap & PPC_FEATURE_POWER6_EXT)
+			   ? __isnan_power6x
+			   : (hwcap & PPC_FEATURE_ARCH_2_05)
+			     ? __isnan_power6
+			     : (hwcap & PPC_FEATURE_POWER5)
+			       ? __isnan_power5
+			       : __isnan_ppc64);
 
 weak_alias (__isnan, isnan)
 
diff --git a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnanf.c b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnanf.c
index acbc131..903ea86 100644
--- a/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnanf.c
+++ b/sysdeps/powerpc/powerpc64/fpu/multiarch/s_isnanf.c
@@ -27,17 +27,18 @@  extern __typeof (__isnanf) __isnan_power6x attribute_hidden;
 extern __typeof (__isnanf) __isnan_power7 attribute_hidden;
 extern __typeof (__isnanf) __isnan_power8 attribute_hidden;
 
-libc_ifunc (__isnanf,
-	    (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-	    ? __isnan_power8 :
-	      (hwcap & PPC_FEATURE_ARCH_2_06)
-	      ? __isnan_power7 :
-		(hwcap & PPC_FEATURE_POWER6_EXT)
-		  ? __isnan_power6x :
-		  (hwcap & PPC_FEATURE_ARCH_2_05)
-		    ? __isnan_power6 :
-		    (hwcap & PPC_FEATURE_POWER5)
-		      ? __isnan_power5
-            : __isnan_ppc64);
+libc_ifunc_hidden (__isnanf, __isnanf,
+		   (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		   ? __isnan_power8
+		   : (hwcap & PPC_FEATURE_ARCH_2_06)
+		     ? __isnan_power7
+		     : (hwcap & PPC_FEATURE_POWER6_EXT)
+		       ? __isnan_power6x
+		       : (hwcap & PPC_FEATURE_ARCH_2_05)
+			 ? __isnan_power6
+			 : (hwcap & PPC_FEATURE_POWER5)
+			   ? __isnan_power5
+			   : __isnan_ppc64);
 
+hidden_def (__isnanf)
 weak_alias (__isnanf, isnanf)
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c
index e8cf6ae..a45ebd7 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp.c
@@ -18,6 +18,7 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if IS_IN (libc)
+# define memcmp __redirect_memcmp
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -25,15 +26,16 @@ 
 extern __typeof (memcmp) __memcmp_ppc attribute_hidden;
 extern __typeof (memcmp) __memcmp_power4 attribute_hidden;
 extern __typeof (memcmp) __memcmp_power7 attribute_hidden;
+# undef memcmp
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (memcmp,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __memcmp_power7 :
-	      (hwcap & PPC_FEATURE_POWER4)
-		? __memcmp_power4
-            : __memcmp_ppc);
+libc_ifunc_redirected (__redirect_memcmp, memcmp,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __memcmp_power7
+		       : (hwcap & PPC_FEATURE_POWER4)
+			 ? __memcmp_power4
+			 : __memcmp_ppc);
 #else
 #include <string/memcmp.c>
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c b/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c
index 3c77b5f..36ec954 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/mempcpy.c
@@ -17,23 +17,28 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define mempcpy __redirect_mempcpy
+# define __mempcpy __redirect___mempcpy
 # define NO_MEMPCPY_STPCPY_REDIRECT
+/* Omit the mempcpy inline definitions because it would redefine mempcpy.  */
+# define _HAVE_STRING_ARCH_mempcpy 1
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (__mempcpy) __mempcpy_ppc attribute_hidden;
 extern __typeof (__mempcpy) __mempcpy_power7 attribute_hidden;
+# undef mempcpy
+# undef __mempcpy
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (__mempcpy,
-	    (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __mempcpy_power7
-            : __mempcpy_ppc);
+libc_ifunc_redirected (__redirect___mempcpy, __mempcpy,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __mempcpy_power7
+		       : __mempcpy_ppc);
 
 weak_alias (__mempcpy, mempcpy)
-libc_hidden_def (mempcpy)
 #else
 # include <string/mempcpy.c>
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c
index f06030e..b53b148 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/rawmemchr.c
@@ -17,19 +17,21 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define __rawmemchr __redirect___rawmemchr
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (__rawmemchr) __rawmemchr_ppc attribute_hidden;
 extern __typeof (__rawmemchr) __rawmemchr_power7 attribute_hidden;
+# undef __rawmemchr
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (__rawmemchr,
-	    (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __rawmemchr_power7
-            : __rawmemchr_ppc);
+libc_ifunc_redirected (__redirect___rawmemchr, __rawmemchr,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __rawmemchr_power7
+		       : __rawmemchr_ppc);
 
 weak_alias (__rawmemchr, rawmemchr)
 #else
diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c b/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c
index bbc1691..e378138 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/stpcpy.c
@@ -26,14 +26,15 @@  extern __typeof (__stpcpy) __stpcpy_ppc attribute_hidden;
 extern __typeof (__stpcpy) __stpcpy_power7 attribute_hidden;
 extern __typeof (__stpcpy) __stpcpy_power8 attribute_hidden;
 
-libc_ifunc (__stpcpy,
-            (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-            ? __stpcpy_power8 :
-              (hwcap & PPC_FEATURE_HAS_VSX)
-              ? __stpcpy_power7
-            : __stpcpy_ppc);
+libc_ifunc_hidden (__stpcpy, __stpcpy,
+		   (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		   ? __stpcpy_power8
+		   : (hwcap & PPC_FEATURE_HAS_VSX)
+		     ? __stpcpy_power7
+		     : __stpcpy_ppc);
 
 weak_alias (__stpcpy, stpcpy)
+libc_hidden_def (__stpcpy)
 libc_hidden_def (stpcpy)
 #else
 # include <string/stpcpy.c>
diff --git a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c
index b1484b1..fb3b529 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/stpncpy.c
@@ -17,6 +17,8 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define stpncpy __redirect_stpncpy
+# define __stpncpy __redirect___stpncpy
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -24,13 +26,14 @@ 
 extern __typeof (__stpncpy) __stpncpy_ppc attribute_hidden;
 extern __typeof (__stpncpy) __stpncpy_power7 attribute_hidden;
 extern __typeof (__stpncpy) __stpncpy_power8 attribute_hidden;
+# undef stpncpy
+# undef __stpncpy
 
-libc_ifunc (__stpncpy,
-            (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-            ? __stpncpy_power8 :
-              (hwcap & PPC_FEATURE_HAS_VSX)
-              ? __stpncpy_power7
-            : __stpncpy_ppc);
-
+libc_ifunc_redirected (__redirect___stpncpy, __stpncpy,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __stpncpy_power8
+		       : (hwcap & PPC_FEATURE_HAS_VSX)
+			 ? __stpncpy_power7
+			 : __stpncpy_ppc);
 weak_alias (__stpncpy, stpncpy)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcat.c b/sysdeps/powerpc/powerpc64/multiarch/strcat.c
index a2894ae..5080ed1 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strcat.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strcat.c
@@ -17,6 +17,7 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define strcat __redirect_strcat
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -24,11 +25,12 @@ 
 extern __typeof (strcat) __strcat_ppc attribute_hidden;
 extern __typeof (strcat) __strcat_power7 attribute_hidden;
 extern __typeof (strcat) __strcat_power8 attribute_hidden;
+# undef strcat
 
-libc_ifunc (strcat,
-            (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-            ? __strcat_power8 :
-              (hwcap & PPC_FEATURE_HAS_VSX)
-              ? __strcat_power7
-            : __strcat_ppc);
+libc_ifunc_redirected (__redirect_strcat, strcat,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __strcat_power8
+		       : (hwcap & PPC_FEATURE_HAS_VSX)
+			 ? __strcat_power7
+			 : __strcat_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strchr.c b/sysdeps/powerpc/powerpc64/multiarch/strchr.c
index 2cfde63..e24d6b3 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strchr.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strchr.c
@@ -18,18 +18,22 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if defined SHARED && IS_IN (libc)
+# define strchr __redirect_strchr
+/* Omit the strchr inline definitions because it would redefine strchr.  */
+# define __NO_STRING_INLINES
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (strchr) __strchr_ppc attribute_hidden;
 extern __typeof (strchr) __strchr_power7 attribute_hidden;
+# undef strchr
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (strchr,
-	    (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strchr_power7
-            : __strchr_ppc);
+libc_ifunc_redirected (__redirect_strchr, strchr,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strchr_power7
+		       : __strchr_ppc);
 weak_alias (strchr, index)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
index aee888a..06f89cb 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
@@ -17,6 +17,9 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined SHARED && IS_IN (libc)
+# define strcmp __redirect_strcmp
+/* Omit the strcmp inline definitions because it would redefine strcmp.  */
+# define __NO_STRING_INLINES
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -24,11 +27,12 @@ 
 extern __typeof (strcmp) __strcmp_ppc attribute_hidden;
 extern __typeof (strcmp) __strcmp_power7 attribute_hidden;
 extern __typeof (strcmp) __strcmp_power8 attribute_hidden;
+# undef strcmp
 
-libc_ifunc (strcmp,
-            (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-              ? __strcmp_power8 :
-              (hwcap & PPC_FEATURE_HAS_VSX)
-              ? __strcmp_power7
-            : __strcmp_ppc);
+libc_ifunc_redirected (__redirect_strcmp, strcmp,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __strcmp_power8
+		       : (hwcap & PPC_FEATURE_HAS_VSX)
+			 ? __strcmp_power7
+			 : __strcmp_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c
index d2c3858..8708fc7 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c
@@ -17,6 +17,7 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined SHARED && IS_IN (libc)
+# define strcpy __redirect_strcpy
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -24,11 +25,12 @@ 
 extern __typeof (strcpy) __strcpy_ppc attribute_hidden;
 extern __typeof (strcpy) __strcpy_power7 attribute_hidden;
 extern __typeof (strcpy) __strcpy_power8 attribute_hidden;
+#undef strcpy
 
-libc_ifunc (strcpy,
-            (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-            ? __strcpy_power8 :
-              (hwcap & PPC_FEATURE_HAS_VSX)
-              ? __strcpy_power7
-            : __strcpy_ppc);
+libc_ifunc_redirected (__redirect_strcpy, strcpy,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __strcpy_power8
+		       : (hwcap & PPC_FEATURE_HAS_VSX)
+			 ? __strcpy_power7
+			 : __strcpy_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c
index 1eb6e51..63a1aa0 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c
@@ -18,6 +18,9 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if defined SHARED && IS_IN (libc)
+# define strncmp __redirect_strncmp
+/* Omit the strncmp inline definitions because it would redefine strncmp.  */
+# define __NO_STRING_INLINES
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -26,15 +29,16 @@  extern __typeof (strncmp) __strncmp_ppc attribute_hidden;
 extern __typeof (strncmp) __strncmp_power4 attribute_hidden;
 extern __typeof (strncmp) __strncmp_power7 attribute_hidden;
 extern __typeof (strncmp) __strncmp_power8 attribute_hidden;
+# undef strncmp
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (strncmp,
-            (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-            ? __strncmp_power8 :
-              (hwcap & PPC_FEATURE_HAS_VSX)
-              ? __strncmp_power7 :
-		(hwcap & PPC_FEATURE_POWER4)
-		? __strncmp_power4
-            : __strncmp_ppc);
+libc_ifunc_redirected (__redirect_strncmp, strncmp,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __strncmp_power8
+		       : (hwcap & PPC_FEATURE_HAS_VSX)
+			 ? __strncmp_power7
+			 : (hwcap & PPC_FEATURE_POWER4)
+			   ? __strncmp_power4
+			   : __strncmp_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c
index 0176514..64495df 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strncpy.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strncpy.c
@@ -18,6 +18,9 @@ 
 
 /* Define multiple versions only for definition in libc. */
 #if IS_IN (libc)
+# define strncpy __redirect_strncpy
+/* Omit the strncpy inline definitions because it would redefine strncpy.  */
+# define __NO_STRING_INLINES
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -25,14 +28,15 @@ 
 extern __typeof (strncpy) __strncpy_ppc attribute_hidden;
 extern __typeof (strncpy) __strncpy_power7 attribute_hidden;
 extern __typeof (strncpy) __strncpy_power8 attribute_hidden;
+# undef strncpy
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
  ifunc symbol properly. */
-libc_ifunc (strncpy,
-            (hwcap2 & PPC_FEATURE2_ARCH_2_07)
-            ? __strncpy_power8 :
-              (hwcap & PPC_FEATURE_HAS_VSX)
-              ? __strncpy_power7
-            : __strncpy_ppc);
+libc_ifunc_redirected (__redirect_strncpy, strncpy,
+		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
+		       ? __strncpy_power8
+		       : (hwcap & PPC_FEATURE_HAS_VSX)
+			 ? __strncpy_power7
+			 : __strncpy_ppc);
 
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strnlen.c b/sysdeps/powerpc/powerpc64/multiarch/strnlen.c
index c4907e9..71dc12d 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strnlen.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strnlen.c
@@ -17,19 +17,21 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define strnlen __redirect_strnlen
+# define __strnlen __redirect___strnlen
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (__strnlen) __strnlen_ppc attribute_hidden;
 extern __typeof (__strnlen) __strnlen_power7 attribute_hidden;
-
-libc_ifunc (__strnlen,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strnlen_power7
-            : __strnlen_ppc);
+# undef strnlen
+# undef __strnlen
+libc_ifunc_redirected (__redirect___strnlen, __strnlen,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strnlen_power7
+		       : __strnlen_ppc);
 weak_alias (__strnlen, strnlen)
-libc_hidden_def (strnlen)
 
 #else
 #include <string/strnlen.c>
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strrchr.c b/sysdeps/powerpc/powerpc64/multiarch/strrchr.c
index 45742bc..e485b02 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strrchr.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strrchr.c
@@ -18,18 +18,20 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if IS_IN (libc)
+# define strrchr __redirect_strrchr
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (strrchr) __strrchr_ppc attribute_hidden;
 extern __typeof (strrchr) __strrchr_power7 attribute_hidden;
+#undef strrchr
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (strrchr,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strrchr_power7
-            : __strrchr_ppc);
+libc_ifunc_redirected (__redirect_strrchr, strrchr,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strrchr_power7
+		       : __strrchr_ppc);
 weak_alias (strrchr, rindex)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strstr.c b/sysdeps/powerpc/powerpc64/multiarch/strstr.c
index 7efc4b0..9a390c2 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/strstr.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/strstr.c
@@ -18,17 +18,19 @@ 
 
 /* Define multiple versions only for definition in libc.  */
 #if IS_IN (libc)
+# define strstr __redirect_strstr
 # include <string.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
 
 extern __typeof (strstr) __strstr_ppc attribute_hidden;
 extern __typeof (strstr) __strstr_power7 attribute_hidden;
+# undef strstr
 
 /* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
    ifunc symbol properly.  */
-libc_ifunc (strstr,
-            (hwcap & PPC_FEATURE_HAS_VSX)
-            ? __strstr_power7
-            : __strstr_ppc);
+libc_ifunc_redirected (__redirect_strstr, strstr,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __strstr_power7
+		       : __strstr_ppc);
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/wcschr.c b/sysdeps/powerpc/powerpc64/multiarch/wcschr.c
index 44c9b97..a470542 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/wcschr.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/wcschr.c
@@ -17,6 +17,8 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define wcschr __redirect_wcschr
+# define __wcschr __redirect___wcschr
 # include <wchar.h>
 # include <shlib-compat.h>
 # include "init-arch.h"
@@ -24,15 +26,16 @@ 
 extern __typeof (wcschr) __wcschr_ppc attribute_hidden;
 extern __typeof (wcschr) __wcschr_power6 attribute_hidden;
 extern __typeof (wcschr) __wcschr_power7 attribute_hidden;
+# undef wcschr
+# undef __wcschr
 
-libc_ifunc (__wcschr,
-	     (hwcap & PPC_FEATURE_HAS_VSX)
-             ? __wcschr_power7 :
-	       (hwcap & PPC_FEATURE_ARCH_2_05)
-	       ? __wcschr_power6
-             : __wcschr_ppc);
+libc_ifunc_redirected (__redirect___wcschr, __wcschr,
+		       (hwcap & PPC_FEATURE_HAS_VSX)
+		       ? __wcschr_power7
+		       : (hwcap & PPC_FEATURE_ARCH_2_05)
+			 ? __wcschr_power6
+			 : __wcschr_ppc);
 weak_alias (__wcschr, wcschr)
-libc_hidden_builtin_def (wcschr)
 #else
 #undef libc_hidden_def
 #define libc_hidden_def(a)