S390: Refactor ifunc resolvers due to false debuginfo.

Message ID nje4om$vo0$1@ger.gmane.org
State Superseded
Headers

Commit Message

Stefan Liebler June 10, 2016, 10:28 a.m. UTC
  Hi,

The current s390 ifunc resolver for vector optimized functions uses
something like that:
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 tosomething 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 contain
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.
Usage 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:
# define __strnlen __redirect___strnlen
# include <string.h>
# undef __strnlen
extern __typeof (__redirect___strnlen) __libc___strnlen;
__typeof (__libc___strnlen) __libc___strnlen __attribute__ ((ifunc 
("__resolve_strnlen")));
strong_alias (__libc___strnlen, __strnlen)
weak_alias (__libc___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 s390 specific ifunc helper macros in ifunc-
resolve.h to use gcc attribute ifunc to get rid of the false debuginfo.
Therefore the redirection construct is applied where needed.

Is this okay to commit?
Does anybody know a better solution for the trouble with internal symbols?

Perhaps in future we can switch some of the internal symbols __GI_*
from the fallback variant to the ifunc function. But this change is
also not straightforward due to a segmentation fault while linking
libc.so with older binutils.

Bye
Stefan

ChangeLog:

	* sysdeps/s390/multiarch/ifunc-resolve.h
	(s390_vx_libc_ifunc2): Use gcc attribute ifunc for ifunc symbols
	and make resolver function static.
	(s390_libc_ifunc): Align as most as possible to
	s390_vx_libc_ifunc2.
	* sysdeps/s390/multiarch/memchr.c: Redirect ifunced function in
	header and create a copy of the prototype for using as ifunc
	function.
	* sysdeps/s390/multiarch/mempcpy.c: Likewise.
	* sysdeps/s390/multiarch/rawmemchr.c: Likewise.
	* sysdeps/s390/multiarch/stpcpy.c: Likewise.
	* sysdeps/s390/multiarch/stpncpy.c: Likewise.
	* sysdeps/s390/multiarch/strcat.c: Likewise.
	* sysdeps/s390/multiarch/strchr.c: Likewise.
	* sysdeps/s390/multiarch/strcmp.c: Likewise.
	* sysdeps/s390/multiarch/strcpy.c: Likewise.
	* sysdeps/s390/multiarch/strcspn.c: Likewise.
	* sysdeps/s390/multiarch/strlen.c: Likewise.
	* sysdeps/s390/multiarch/strncmp.c: Likewise.
	* sysdeps/s390/multiarch/strncpy.c: Likewise.
	* sysdeps/s390/multiarch/strnlen.c: Likewise.
	* sysdeps/s390/multiarch/strpbrk.c: Likewise.
	* sysdeps/s390/multiarch/strrchr.c: Likewise.
	* sysdeps/s390/multiarch/strspn.c: Likewise.
	* sysdeps/s390/multiarch/wcschr.c: Likewise.
	* sysdeps/s390/multiarch/wcscmp.c: Likewise.
	* sysdeps/s390/multiarch/wcspbrk.c: Likewise.
	* sysdeps/s390/multiarch/wcsspn.c: Likewise.
	* sysdeps/s390/multiarch/wmemchr.c: Likewise.
	* sysdeps/s390/multiarch/wmemset.c: Likewise.
	* sysdeps/s390/s390-32/multiarch/memcmp.c: Likewise.
	* sysdeps/s390/s390-32/multiarch/memcpy.c: Likewise.
	* sysdeps/s390/s390-32/multiarch/memset.c: Likewise.
	* sysdeps/s390/s390-64/multiarch/memcmp.c: Likewise.
	* sysdeps/s390/s390-64/multiarch/memcpy.c: Likewise.
	* sysdeps/s390/s390-64/multiarch/memset.c: Likewise.
  

Comments

Joseph Myers June 10, 2016, 4:59 p.m. UTC | #1
Are the debug info issues you describe unique to S/390 because of some 
peculiarity of how S/390, and only S/390, defines IFUNC resolvers in 
glibc, or do they apply to any other architectures as well and so need 
fixes there?
  
Stefan Liebler June 13, 2016, noon UTC | #2
On 06/10/2016 06:59 PM, Joseph Myers wrote:
> Are the debug info issues you describe unique to S/390 because of some
> peculiarity of how S/390, and only S/390, defines IFUNC resolvers in
> glibc, or do they apply to any other architectures as well and so need
> fixes there?
>

The libc_ifunc macro in include/libc-symbols.h also uses the asm-name
and the debug-information contains the DW_AT_linkage_name field.
Here is the debug-info for strcmp on a power system:
  <1><297449>: Abbrev Number: 42 (DW_TAG_subprogram)
     <29744a>   DW_AT_external    : 1	
     <29744a>   DW_AT_name        : (indirect string, offset: 
0x11700): strcmp_ifunc	
     <29744e>   DW_AT_decl_file   : 1	
     <29744f>   DW_AT_decl_line   : 28	
     <297450>   DW_AT_linkage_name: (indirect string, offset: 0x4b89): 
strcmp	
     <297454>   DW_AT_prototyped  : 1	
     <297454>   DW_AT_type        : <0x295fd6>	
     <297458>   DW_AT_low_pc      : 0xc0520	
     <297460>   DW_AT_high_pc     : 0x0 0xb4	
     <297468>   DW_AT_frame_base  : 1 byte block: 9c 	(DW_OP_call_frame_cfa)
     <29746a>   Unknown AT value: 2117: 1	
     <29746a>   DW_AT_sibling     : <0x2974bc>	
  <2><29746e>: Abbrev Number: 43 (DW_TAG_variable)
     <29746f>   DW_AT_name        : (indirect string, offset: 0xaa4): hwcap
...

In contrast to the s390 ifunc-resolver, the ifunc-resolver does not have 
a parameter whereas on s390, the resolver gets hwcap as argument.
I don't have access to lldb on another architecture, so I don't know if 
this is an issue there.
So far there are multiple hits on power like strcmp, strchr, strcat, 
strcpy, memcmp, wcscpy, time, ... which uses the libc_ifunc macro and 
thus have the DW_AT_linkage_name field.
There are also a lot of "__" prefixed ifunc functions like __wcschr with 
an alias wcschr. The debug info for __wcschr contains the 
DW_AT_linkage_name field and wcschr does not have debug infos.

On intel the most ifunc resolvers for string functions are implemented 
directly in assembler files and thus have no debug information.
The libc_ifunc macro is used for e.g. strstr, memmove, but the functions 
are redirected to avoid the debug info for strstr, memmove.

There exist sparc ifunc macros which also uses the asm-name construct:
sparc_libm_ifunc and sparc_libc_ifunc in sysdeps/sparc/sparc-ifunc.h.

There also exist some symbol redirections for ABI compatibility.
The ones for libpthread are using an inline assembly with set, globl, 
type and thus do not produce debug information (See e.g. nptl/pt-fork.c).
But for librt I've found the asm-name construct for clock_getres & co in 
rt/clock-compat.c.

Bye
Stefan
  
Joseph Myers June 13, 2016, 2:39 p.m. UTC | #3
On Mon, 13 Jun 2016, Stefan Liebler wrote:

> On 06/10/2016 06:59 PM, Joseph Myers wrote:
> > Are the debug info issues you describe unique to S/390 because of some
> > peculiarity of how S/390, and only S/390, defines IFUNC resolvers in
> > glibc, or do they apply to any other architectures as well and so need
> > fixes there?
> 
> The libc_ifunc macro in include/libc-symbols.h also uses the asm-name
> and the debug-information contains the DW_AT_linkage_name field.

Then I think the goal should be to arrange things so that as much 
infrastructure as possible is shared between architectures defining IFUNC 
resolvers in C code, so that they all avoid this pitfall, rather than just 
fixing one architecture.
  
Stefan Liebler June 23, 2016, 11:59 a.m. UTC | #4
On 06/13/2016 04:39 PM, Joseph Myers wrote:
> On Mon, 13 Jun 2016, Stefan Liebler wrote:
>
>> On 06/10/2016 06:59 PM, Joseph Myers wrote:
>>> Are the debug info issues you describe unique to S/390 because of some
>>> peculiarity of how S/390, and only S/390, defines IFUNC resolvers in
>>> glibc, or do they apply to any other architectures as well and so need
>>> fixes there?
>>
>> The libc_ifunc macro in include/libc-symbols.h also uses the asm-name
>> and the debug-information contains the DW_AT_linkage_name field.
>
> Then I think the goal should be to arrange things so that as much
> infrastructure as possible is shared between architectures defining IFUNC
> resolvers in C code, so that they all avoid this pitfall, rather than just
> fixing one architecture.
>
Sorry for the delay. I had to wait for some test machines to be 
prepared. I have posted a patchset where the common libc_ifunc macro is 
adjusted and used by all architectures including s390.
Thus this patch is superseded by the patch series:
"[PATCH 1/8] Use gcc attribute ifunc in libc_ifunc macro instead of 
inline assembly due to false debuginfo."
https://www.sourceware.org/ml/libc-alpha/2016-06/msg00896.html
  

Patch

commit 528b86d124130cc97a283b668b17a868915f069e
Author: Stefan Liebler <stli@linux.vnet.ibm.com>
Date:   Thu Apr 14 16:56:51 2016 +0200

    S390: Refactor ifunc resolvers due to false debuginfo.
    
    The current s390 ifunc resolver for vector optimized functions uses something
    like that:
    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 tosomething 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.
    Usage 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:
    extern __typeof (__redirect___strnlen) __libc___strnlen;
    __typeof (__libc___strnlen) __libc___strnlen __attribute__ ((ifunc ("__resolve_strnlen")));
    strong_alias (__libc___strnlen, __strnlen)
    weak_alias (__libc___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 s390 specific ifunc helper macros in ifunc-resolve.h to
    use gcc attribute ifunc to get rid of the false debuginfo. Therefore the
    redirection construct is applied where needed.
    
    Is this okay to commit?
    Does anybody know a better solution for the trouble with internal symbols?
    
    Perhaps in future we can switch some of the internal symbols __GI_* from the
    fallback variant to the ifunc function. But this change is also not
    straightforward due to a segmentation fault while linking libc.so with older
    binutils.
    
    Bye
    Stefan
    
    ChangeLog:
    
    	* sysdeps/s390/multiarch/ifunc-resolve.h
    	(s390_vx_libc_ifunc2): Use gcc attribute ifunc for ifunc symbols
    	and make resolver function static.
    	(s390_libc_ifunc): Align as most as possible to s390_vx_libc_ifunc2.
    	* sysdeps/s390/multiarch/memchr.c: Redirect ifunced function in header
    	and create a copy of the prototype for using as ifunc function.
    	* sysdeps/s390/multiarch/mempcpy.c: Likewise.
    	* sysdeps/s390/multiarch/rawmemchr.c: Likewise.
    	* sysdeps/s390/multiarch/stpcpy.c: Likewise.
    	* sysdeps/s390/multiarch/stpncpy.c: Likewise.
    	* sysdeps/s390/multiarch/strcat.c: Likewise.
    	* sysdeps/s390/multiarch/strchr.c: Likewise.
    	* sysdeps/s390/multiarch/strcmp.c: Likewise.
    	* sysdeps/s390/multiarch/strcpy.c: Likewise.
    	* sysdeps/s390/multiarch/strcspn.c: Likewise.
    	* sysdeps/s390/multiarch/strlen.c: Likewise.
    	* sysdeps/s390/multiarch/strncmp.c: Likewise.
    	* sysdeps/s390/multiarch/strncpy.c: Likewise.
    	* sysdeps/s390/multiarch/strnlen.c: Likewise.
    	* sysdeps/s390/multiarch/strpbrk.c: Likewise.
    	* sysdeps/s390/multiarch/strrchr.c: Likewise.
    	* sysdeps/s390/multiarch/strspn.c: Likewise.
    	* sysdeps/s390/multiarch/wcschr.c: Likewise.
    	* sysdeps/s390/multiarch/wcscmp.c: Likewise.
    	* sysdeps/s390/multiarch/wcspbrk.c: Likewise.
    	* sysdeps/s390/multiarch/wcsspn.c: Likewise.
    	* sysdeps/s390/multiarch/wmemchr.c: Likewise.
    	* sysdeps/s390/multiarch/wmemset.c: Likewise.
    	* sysdeps/s390/s390-32/multiarch/memcmp.c: Likewise.
    	* sysdeps/s390/s390-32/multiarch/memcpy.c: Likewise.
    	* sysdeps/s390/s390-32/multiarch/memset.c: Likewise.
    	* sysdeps/s390/s390-64/multiarch/memcmp.c: Likewise.
    	* sysdeps/s390/s390-64/multiarch/memcpy.c: Likewise.
    	* sysdeps/s390/s390-64/multiarch/memset.c: Likewise.

diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/multiarch/ifunc-resolve.h
index 26e097a..b9e6148 100644
--- a/sysdeps/s390/multiarch/ifunc-resolve.h
+++ b/sysdeps/s390/multiarch/ifunc-resolve.h
@@ -41,18 +41,17 @@ 
 		       : "=QS" (STFLE_BITS), "+d" (reg0)		\
 		       : : "cc");
 
-#define s390_libc_ifunc(FUNC)						\
-  __asm__ (".globl " #FUNC "\n\t"					\
-	   ".type  " #FUNC ",@gnu_indirect_function\n\t"		\
-	   ".set   " #FUNC ",__resolve_" #FUNC "\n\t");			\
+#define s390_libc_ifunc(RESOLVERFUNC, FUNC)				\
+  extern __typeof (FUNC) FUNC						\
+		  __attribute__ ((ifunc ("__resolve_" #RESOLVERFUNC))); \
 									\
   /* Make the declarations of the optimized functions hidden in order
      to prevent GOT slots being generated for them. */			\
-  extern void *__##FUNC##_z196 attribute_hidden;			\
-  extern void *__##FUNC##_z10 attribute_hidden;				\
-  extern void *__##FUNC##_default attribute_hidden;			\
+  extern __typeof (FUNC) RESOLVERFUNC##_z196 attribute_hidden;		\
+  extern __typeof (FUNC) RESOLVERFUNC##_z10 attribute_hidden;           \
+  extern __typeof (FUNC) RESOLVERFUNC##_default attribute_hidden;       \
 									\
-  void *__resolve_##FUNC (unsigned long int dl_hwcap)			\
+  static void *__resolve_##RESOLVERFUNC (unsigned long int dl_hwcap)	\
   {									\
     if ((dl_hwcap & HWCAP_S390_STFLE)					\
 	&& (dl_hwcap & HWCAP_S390_ZARCH)				\
@@ -62,31 +61,32 @@ 
 	S390_STORE_STFLE (stfle_bits);					\
 									\
 	if (S390_IS_Z196 (stfle_bits))					\
-	  return &__##FUNC##_z196;					\
+	  return &RESOLVERFUNC##_z196;					\
 	else if (S390_IS_Z10 (stfle_bits))				\
-	  return &__##FUNC##_z10;					\
+	  return &RESOLVERFUNC##_z10;					\
 	else								\
-	  return &__##FUNC##_default;					\
+	  return &RESOLVERFUNC##_default;				\
       }									\
     else								\
-      return &__##FUNC##_default;					\
+      return &RESOLVERFUNC##_default;					\
   }
 
 #define s390_vx_libc_ifunc(FUNC)		\
   s390_vx_libc_ifunc2(FUNC, FUNC)
 
 #define s390_vx_libc_ifunc2(RESOLVERFUNC, FUNC)				\
+  extern __typeof (FUNC) FUNC						\
+		  __attribute__ ((ifunc ("__resolve_" #RESOLVERFUNC))); \
+									\
   /* Make the declarations of the optimized functions hidden in order
      to prevent GOT slots being generated for them.  */			\
   extern __typeof (FUNC) RESOLVERFUNC##_vx attribute_hidden;		\
   extern __typeof (FUNC) RESOLVERFUNC##_c attribute_hidden;		\
-  extern void *__resolve_##RESOLVERFUNC (unsigned long int) __asm__ (#FUNC); \
 									\
-  void *__resolve_##RESOLVERFUNC (unsigned long int dl_hwcap)		\
+  static void *__resolve_##RESOLVERFUNC (unsigned long int dl_hwcap)    \
   {									\
     if (dl_hwcap & HWCAP_S390_VX)					\
       return &RESOLVERFUNC##_vx;					\
     else								\
       return &RESOLVERFUNC##_c;						\
-  }									\
- __asm__ (".type " #FUNC ", %gnu_indirect_function");
+  }
diff --git a/sysdeps/s390/multiarch/memchr.c b/sysdeps/s390/multiarch/memchr.c
index f80de1c..e7661df 100644
--- a/sysdeps/s390/multiarch/memchr.c
+++ b/sysdeps/s390/multiarch/memchr.c
@@ -17,8 +17,13 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define memchr __redirect_memchr
 # include <string.h>
+# undef memchr
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__memchr, memchr)
+extern __typeof (__redirect_memchr) __libc_memchr;
+s390_vx_libc_ifunc2 (__memchr, __libc_memchr)
+strong_alias (__libc_memchr, memchr)
+
 #endif
diff --git a/sysdeps/s390/multiarch/mempcpy.c b/sysdeps/s390/multiarch/mempcpy.c
index 34d8329..709d167 100644
--- a/sysdeps/s390/multiarch/mempcpy.c
+++ b/sysdeps/s390/multiarch/mempcpy.c
@@ -18,9 +18,17 @@ 
 
 
 #if defined SHARED && IS_IN (libc)
+# define mempcpy __redirect_mempcpy
+# define __mempcpy __redirect___mempcpy
+/* Omit the mempcpy inline definitions because it would redefine mempcpy.  */
+# define _HAVE_STRING_ARCH_mempcpy 1
+# include <string.h>
+# undef mempcpy
+# undef __mempcpy
 # include <ifunc-resolve.h>
-s390_libc_ifunc (__mempcpy)
 
-__asm__ (".weak mempcpy\n\t"
-	 ".set mempcpy,__mempcpy\n\t");
+extern __typeof (__redirect_mempcpy) __libc___mempcpy;
+s390_libc_ifunc (____mempcpy, __libc___mempcpy)
+strong_alias (__libc___mempcpy, __mempcpy);
+weak_alias (__libc___mempcpy, mempcpy);
 #endif
diff --git a/sysdeps/s390/multiarch/rawmemchr.c b/sysdeps/s390/multiarch/rawmemchr.c
index 7186ccd..fac159f 100644
--- a/sysdeps/s390/multiarch/rawmemchr.c
+++ b/sysdeps/s390/multiarch/rawmemchr.c
@@ -17,11 +17,15 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define __rawmemchr __redirect___rawmemchr
 # include <string.h>
+# undef __rawmemchr
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__rawmemchr)
-weak_alias (__rawmemchr, rawmemchr)
+extern __typeof (__redirect___rawmemchr) __libc___rawmemchr;
+s390_vx_libc_ifunc2 (__rawmemchr, __libc___rawmemchr)
+strong_alias (__libc___rawmemchr, __rawmemchr)
+weak_alias (__libc___rawmemchr, rawmemchr)
 
 #else
 # include <string/rawmemchr.c>
diff --git a/sysdeps/s390/multiarch/stpcpy.c b/sysdeps/s390/multiarch/stpcpy.c
index dcde012..bae99ab 100644
--- a/sysdeps/s390/multiarch/stpcpy.c
+++ b/sysdeps/s390/multiarch/stpcpy.c
@@ -17,13 +17,20 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define stpcpy __redirect_stpcpy
+# define __stpcpy __redirect___stpcpy
+/* Omit the stpcpy inline definitions because it would redefine stpcpy.  */
+# define __NO_STRING_INLINES
 # define NO_MEMPCPY_STPCPY_REDIRECT
 # include <string.h>
+# undef stpcpy
+# undef __stpcpy
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__stpcpy)
-weak_alias (__stpcpy, stpcpy)
-libc_hidden_builtin_def (stpcpy)
+extern __typeof (__redirect___stpcpy) __libc___stpcpy;
+s390_vx_libc_ifunc2 (__stpcpy, __libc___stpcpy);
+strong_alias (__libc___stpcpy, __stpcpy)
+weak_alias (__libc___stpcpy, stpcpy)
 
 #else
 # include <string/stpcpy.c>
diff --git a/sysdeps/s390/multiarch/stpncpy.c b/sysdeps/s390/multiarch/stpncpy.c
index f5335b4..6c2b9bb 100644
--- a/sysdeps/s390/multiarch/stpncpy.c
+++ b/sysdeps/s390/multiarch/stpncpy.c
@@ -17,11 +17,17 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define stpncpy __redirect_stpncpy
+# define __stpncpy __redirect___stpncpy
 # include <string.h>
+# undef stpncpy
+# undef __stpncpy
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__stpncpy)
-weak_alias (__stpncpy, stpncpy)
+extern __typeof (__redirect___stpncpy) __libc___stpncpy;
+s390_vx_libc_ifunc2 (__stpncpy, __libc___stpncpy)
+strong_alias (__libc___stpncpy, __stpncpy)
+weak_alias (__libc___stpncpy, stpncpy)
 
 #else
 # include <string/stpncpy.c>
diff --git a/sysdeps/s390/multiarch/strcat.c b/sysdeps/s390/multiarch/strcat.c
index c3b5e1c..f1db424 100644
--- a/sysdeps/s390/multiarch/strcat.c
+++ b/sysdeps/s390/multiarch/strcat.c
@@ -17,10 +17,14 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strcat __redirect_strcat
 # include <string.h>
+# undef strcat
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strcat, strcat)
+extern __typeof (__redirect_strcat) __libc_strcat;
+s390_vx_libc_ifunc2 (__strcat, __libc_strcat)
+strong_alias (__libc_strcat, strcat)
 
 #else
 # include <string/strcat.c>
diff --git a/sysdeps/s390/multiarch/strchr.c b/sysdeps/s390/multiarch/strchr.c
index 3c8c7e4..c8d40e7 100644
--- a/sysdeps/s390/multiarch/strchr.c
+++ b/sysdeps/s390/multiarch/strchr.c
@@ -17,11 +17,17 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strchr __redirect_strchr
+/* Omit the strchr inline definitions because it would redefine strchr.  */
+# define __NO_STRING_INLINES
 # include <string.h>
+# undef strchr
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strchr, strchr)
-weak_alias (strchr, index)
+extern __typeof (__redirect_strchr) __libc_strchr;
+s390_vx_libc_ifunc2 (__strchr, __libc_strchr)
+strong_alias (__libc_strchr, strchr)
+weak_alias (__libc_strchr, index)
 
 #else
 # include <string/strchr.c>
diff --git a/sysdeps/s390/multiarch/strcmp.c b/sysdeps/s390/multiarch/strcmp.c
index c4ccd34..8839e8b 100644
--- a/sysdeps/s390/multiarch/strcmp.c
+++ b/sysdeps/s390/multiarch/strcmp.c
@@ -17,10 +17,15 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && 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 <ifunc-resolve.h>
+# undef strcmp
 
+extern __typeof (__redirect_strcmp) __libc_strcmp;
+s390_vx_libc_ifunc2 (__strcmp, __libc_strcmp)
+strong_alias (__libc_strcmp, strcmp)
 
-# undef strcmp
-s390_vx_libc_ifunc2 (__strcmp, strcmp)
 #endif
diff --git a/sysdeps/s390/multiarch/strcpy.c b/sysdeps/s390/multiarch/strcpy.c
index f348199..a901bcd 100644
--- a/sysdeps/s390/multiarch/strcpy.c
+++ b/sysdeps/s390/multiarch/strcpy.c
@@ -17,8 +17,13 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strcpy __redirect_strcpy
 # include <string.h>
+# undef strcpy
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strcpy, strcpy)
+extern __typeof (__redirect_strcpy) __libc_strcpy;
+s390_vx_libc_ifunc2 (__strcpy, __libc_strcpy)
+strong_alias (__libc_strcpy, strcpy)
+
 #endif
diff --git a/sysdeps/s390/multiarch/strcspn.c b/sysdeps/s390/multiarch/strcspn.c
index c23452a..a188f4b 100644
--- a/sysdeps/s390/multiarch/strcspn.c
+++ b/sysdeps/s390/multiarch/strcspn.c
@@ -17,10 +17,16 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strcspn __redirect_strcspn
+/* Omit the strcspn inline definitions because it would redefine strcspn.  */
+# define __NO_STRING_INLINES
 # include <string.h>
+# undef strcspn
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strcspn, strcspn)
+extern __typeof (__redirect_strcspn) __libc_strcspn;
+s390_vx_libc_ifunc2 (__strcspn, __libc_strcspn)
+strong_alias (__libc_strcspn, strcspn)
 
 #else
 # include <string/strcspn.c>
diff --git a/sysdeps/s390/multiarch/strlen.c b/sysdeps/s390/multiarch/strlen.c
index 098d4e1..186b4e5 100644
--- a/sysdeps/s390/multiarch/strlen.c
+++ b/sysdeps/s390/multiarch/strlen.c
@@ -17,10 +17,14 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strlen __redirect_strlen
 # include <string.h>
 # include <ifunc-resolve.h>
+# undef strlen
 
-s390_vx_libc_ifunc2 (__strlen, strlen)
+extern __typeof (__redirect_strlen) __libc_strlen;
+s390_vx_libc_ifunc2 (__strlen, __libc_strlen)
+strong_alias (__libc_strlen, strlen)
 
 #else
 # include <string/strlen.c>
diff --git a/sysdeps/s390/multiarch/strncmp.c b/sysdeps/s390/multiarch/strncmp.c
index 9a72c79..6c130cc 100644
--- a/sysdeps/s390/multiarch/strncmp.c
+++ b/sysdeps/s390/multiarch/strncmp.c
@@ -17,13 +17,16 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strncmp __redirect_strncmp
+/* Omit the strncmp inline definitions because it would redefine strncmp.  */
+# define __NO_STRING_INLINES
 # include <string.h>
+# undef strncmp
 # include <ifunc-resolve.h>
 
-
-# undef strcmp
-extern __typeof (strncmp) __strncmp;
-s390_vx_libc_ifunc2 (__strncmp, strncmp)
+extern __typeof (__redirect_strncmp) __libc_strncmp;
+s390_vx_libc_ifunc2 (__strncmp, __libc_strncmp)
+strong_alias (__libc_strncmp, strncmp)
 
 #else
 # include <string/strncmp.c>
diff --git a/sysdeps/s390/multiarch/strncpy.c b/sysdeps/s390/multiarch/strncpy.c
index 1464551..2c294d2 100644
--- a/sysdeps/s390/multiarch/strncpy.c
+++ b/sysdeps/s390/multiarch/strncpy.c
@@ -17,8 +17,15 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strncpy __redirect_strncpy
+/* Omit the strncpy inline definitions because it would redefine strncpy.  */
+# define __NO_STRING_INLINES
 # include <string.h>
+# undef strncpy
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strncpy, strncpy)
+extern __typeof (__redirect_strncpy) __libc_strncpy;
+s390_vx_libc_ifunc2 (__strncpy, __libc_strncpy);
+strong_alias (__libc_strncpy, strncpy)
+
 #endif
diff --git a/sysdeps/s390/multiarch/strnlen.c b/sysdeps/s390/multiarch/strnlen.c
index 48c3bb7..79edb236 100644
--- a/sysdeps/s390/multiarch/strnlen.c
+++ b/sysdeps/s390/multiarch/strnlen.c
@@ -17,12 +17,17 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strnlen __redirect_strnlen
+# define __strnlen __redirect___strnlen
 # include <string.h>
+# undef strnlen
+# undef __strnlen
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__strnlen)
-weak_alias (__strnlen, strnlen)
-libc_hidden_def (strnlen)
+extern __typeof (__redirect___strnlen) __libc___strnlen;
+s390_vx_libc_ifunc2 (__strnlen, __libc___strnlen)
+strong_alias (__libc___strnlen, __strnlen)
+weak_alias (__libc___strnlen, strnlen)
 
 #else
 # include <string/strnlen.c>
diff --git a/sysdeps/s390/multiarch/strpbrk.c b/sysdeps/s390/multiarch/strpbrk.c
index cdc1399..dc267db 100644
--- a/sysdeps/s390/multiarch/strpbrk.c
+++ b/sysdeps/s390/multiarch/strpbrk.c
@@ -17,10 +17,16 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strpbrk __redirect_strpbrk
+/* Omit the strpbrk inline definitions because it would redefine strpbrk.  */
+# define __NO_STRING_INLINES
 # include <string.h>
+# undef strpbrk
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strpbrk, strpbrk)
+extern __typeof (__redirect_strpbrk) __libc_strpbrk;
+s390_vx_libc_ifunc2 (__strpbrk, __libc_strpbrk)
+strong_alias (__libc_strpbrk, strpbrk)
 
 #else
 # include <string/strpbrk.c>
diff --git a/sysdeps/s390/multiarch/strrchr.c b/sysdeps/s390/multiarch/strrchr.c
index e515d6b..b9c0fca 100644
--- a/sysdeps/s390/multiarch/strrchr.c
+++ b/sysdeps/s390/multiarch/strrchr.c
@@ -17,11 +17,15 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strrchr __redirect_strrchr
 # include <string.h>
+# undef strrchr
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strrchr, strrchr)
-weak_alias (strrchr, rindex)
+extern __typeof (__redirect_strrchr) __libc_strrchr;
+s390_vx_libc_ifunc2 (__strrchr, __libc_strrchr)
+strong_alias (__libc_strrchr, strrchr);
+weak_alias (__libc_strrchr, rindex);
 
 #else
 # include <string/strrchr.c>
diff --git a/sysdeps/s390/multiarch/strspn.c b/sysdeps/s390/multiarch/strspn.c
index 7c26af8..218ecdb 100644
--- a/sysdeps/s390/multiarch/strspn.c
+++ b/sysdeps/s390/multiarch/strspn.c
@@ -17,10 +17,16 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define strspn __redirect_strspn
+/* Omit the strspn inline definitions because it would redefine strspn.  */
+# define __NO_STRING_INLINES
 # include <string.h>
+# undef strspn
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__strspn, strspn)
+extern __typeof (__redirect_strspn) __libc_strspn;
+s390_vx_libc_ifunc2 (__strspn, __libc_strspn)
+strong_alias (__libc_strspn, strspn);
 
 #else
 # include <string/strspn.c>
diff --git a/sysdeps/s390/multiarch/wcschr.c b/sysdeps/s390/multiarch/wcschr.c
index fb51097..abc4e20 100644
--- a/sysdeps/s390/multiarch/wcschr.c
+++ b/sysdeps/s390/multiarch/wcschr.c
@@ -17,12 +17,17 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define wcschr __redirect_wcschr
+# define __wcschr __redirect___wcschr
 # include <wchar.h>
+# undef wcschr
+# undef __wcschr
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__wcschr)
-weak_alias (__wcschr, wcschr)
-libc_hidden_weak (wcschr)
+extern __typeof (__redirect___wcschr) __libc___wcschr;
+s390_vx_libc_ifunc2 (__wcschr, __libc___wcschr)
+strong_alias (__libc___wcschr, __wcschr)
+weak_alias (__libc___wcschr, wcschr)
 
 #else
 # include <wcsmbs/wcschr.c>
diff --git a/sysdeps/s390/multiarch/wcscmp.c b/sysdeps/s390/multiarch/wcscmp.c
index 705ef45..6675a73 100644
--- a/sysdeps/s390/multiarch/wcscmp.c
+++ b/sysdeps/s390/multiarch/wcscmp.c
@@ -17,11 +17,15 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define __wcscmp __redirect___wcscmp
 # include <wchar.h>
+# undef __wcscmp
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__wcscmp)
-weak_alias (__wcscmp, wcscmp)
+extern __typeof (__redirect___wcscmp) __libc__wcscmp;
+s390_vx_libc_ifunc2 (__wcscmp, __libc__wcscmp)
+strong_alias (__libc__wcscmp, __wcscmp)
+weak_alias (__libc__wcscmp, wcscmp)
 
 #else
 # include <wcsmbs/wcscmp.c>
diff --git a/sysdeps/s390/multiarch/wcspbrk.c b/sysdeps/s390/multiarch/wcspbrk.c
index 198144d..e3258a5 100644
--- a/sysdeps/s390/multiarch/wcspbrk.c
+++ b/sysdeps/s390/multiarch/wcspbrk.c
@@ -17,10 +17,14 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define wcspbrk __redirect_wcspbrk
 # include <wchar.h>
+# undef wcspbrk
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__wcspbrk, wcspbrk)
+extern __typeof (__redirect_wcspbrk) __libc_wcspbrk;
+s390_vx_libc_ifunc2 (__wcspbrk, __libc_wcspbrk)
+strong_alias (__libc_wcspbrk, wcspbrk)
 
 #else
 # include <wcsmbs/wcspbrk.c>
diff --git a/sysdeps/s390/multiarch/wcsspn.c b/sysdeps/s390/multiarch/wcsspn.c
index 167a881..45cde8c 100644
--- a/sysdeps/s390/multiarch/wcsspn.c
+++ b/sysdeps/s390/multiarch/wcsspn.c
@@ -17,10 +17,14 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define wcsspn __redirect_wcsspn
 # include <wchar.h>
+# undef wcsspn
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc2 (__wcsspn, wcsspn)
+extern __typeof (__redirect_wcsspn) __libc_wcsspn;
+s390_vx_libc_ifunc2 (__wcsspn, __libc_wcsspn)
+strong_alias (__libc_wcsspn, wcsspn)
 
 #else
 # include <wcsmbs/wcsspn.c>
diff --git a/sysdeps/s390/multiarch/wmemchr.c b/sysdeps/s390/multiarch/wmemchr.c
index f2bfe3c..19b5fba 100644
--- a/sysdeps/s390/multiarch/wmemchr.c
+++ b/sysdeps/s390/multiarch/wmemchr.c
@@ -17,12 +17,17 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define wmemchr __redirect_wmemchr
+# define __wmemchr __redirect___wmemchr
 # include <wchar.h>
+# undef wmemchr
+# undef __wmemchr
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__wmemchr)
-weak_alias (__wmemchr, wmemchr)
-libc_hidden_weak (wmemchr)
+extern __typeof (__redirect___wmemchr) __libc___wmemchr;
+s390_vx_libc_ifunc2 (__wmemchr, __libc___wmemchr)
+strong_alias (__libc___wmemchr, __wmemchr)
+weak_alias (__libc___wmemchr, wmemchr)
 
 #else
 # include <wcsmbs/wmemchr.c>
diff --git a/sysdeps/s390/multiarch/wmemset.c b/sysdeps/s390/multiarch/wmemset.c
index e9e695f..6434917 100644
--- a/sysdeps/s390/multiarch/wmemset.c
+++ b/sysdeps/s390/multiarch/wmemset.c
@@ -17,12 +17,17 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if defined HAVE_S390_VX_ASM_SUPPORT && IS_IN (libc)
+# define wmemset __redirect_wmemset
+# define __wmemset __redirect___wmemset
 # include <wchar.h>
+# undef wmemset
+# undef __wmemset
 # include <ifunc-resolve.h>
 
-s390_vx_libc_ifunc (__wmemset)
-weak_alias (__wmemset, wmemset)
-libc_hidden_weak (wmemset)
+extern __typeof (__redirect___wmemset) __libc___wmemset;
+s390_vx_libc_ifunc2 (__wmemset, __libc___wmemset)
+strong_alias (__libc___wmemset, __wmemset)
+weak_alias (__libc___wmemset, wmemset)
 
 #else
 # include <wcsmbs/wmemset.c>
diff --git a/sysdeps/s390/s390-32/multiarch/memcmp.c b/sysdeps/s390/s390-32/multiarch/memcmp.c
index 44f72dc..a3f5f07 100644
--- a/sysdeps/s390/s390-32/multiarch/memcmp.c
+++ b/sysdeps/s390/s390-32/multiarch/memcmp.c
@@ -17,8 +17,13 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define memcmp __redirect_memcmp
+# include <string.h>
+# undef memcmp
 # include <ifunc-resolve.h>
 
-s390_libc_ifunc (memcmp)
-__asm__(".weak bcmp ; bcmp = memcmp");
+extern __typeof (__redirect_memcmp) __libc_memcmp;
+s390_libc_ifunc (__memcmp, __libc_memcmp)
+strong_alias (__libc_memcmp, memcmp);
+weak_alias (__libc_memcmp, bcmp);
 #endif
diff --git a/sysdeps/s390/s390-32/multiarch/memcpy.c b/sysdeps/s390/s390-32/multiarch/memcpy.c
index 2a98aa0..3b91871 100644
--- a/sysdeps/s390/s390-32/multiarch/memcpy.c
+++ b/sysdeps/s390/s390-32/multiarch/memcpy.c
@@ -18,7 +18,12 @@ 
 
 /* In the static lib memcpy is needed before the reloc is resolved.  */
 #if defined SHARED && IS_IN (libc)
+# define memcpy __redirect_memcpy
+# include <string.h>
+# undef memcpy
 # include <ifunc-resolve.h>
 
-s390_libc_ifunc (memcpy)
+extern __typeof (__redirect_memcpy) __libc_memcpy;
+s390_libc_ifunc (__memcpy, __libc_memcpy)
+strong_alias (__libc_memcpy, memcpy);
 #endif
diff --git a/sysdeps/s390/s390-32/multiarch/memset.c b/sysdeps/s390/s390-32/multiarch/memset.c
index 89b8102..db62760 100644
--- a/sysdeps/s390/s390-32/multiarch/memset.c
+++ b/sysdeps/s390/s390-32/multiarch/memset.c
@@ -17,7 +17,12 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define memset __redirect_memset
+# include <string.h>
+# undef memset
 # include <ifunc-resolve.h>
 
-s390_libc_ifunc (memset)
+extern __typeof (__redirect_memset) __libc_memset;
+s390_libc_ifunc (__memset, __libc_memset)
+strong_alias (__libc_memset, memset);
 #endif
diff --git a/sysdeps/s390/s390-64/multiarch/memcmp.c b/sysdeps/s390/s390-64/multiarch/memcmp.c
index 44f72dc..a3f5f07 100644
--- a/sysdeps/s390/s390-64/multiarch/memcmp.c
+++ b/sysdeps/s390/s390-64/multiarch/memcmp.c
@@ -17,8 +17,13 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define memcmp __redirect_memcmp
+# include <string.h>
+# undef memcmp
 # include <ifunc-resolve.h>
 
-s390_libc_ifunc (memcmp)
-__asm__(".weak bcmp ; bcmp = memcmp");
+extern __typeof (__redirect_memcmp) __libc_memcmp;
+s390_libc_ifunc (__memcmp, __libc_memcmp)
+strong_alias (__libc_memcmp, memcmp);
+weak_alias (__libc_memcmp, bcmp);
 #endif
diff --git a/sysdeps/s390/s390-64/multiarch/memcpy.c b/sysdeps/s390/s390-64/multiarch/memcpy.c
index 2a98aa0..3b91871 100644
--- a/sysdeps/s390/s390-64/multiarch/memcpy.c
+++ b/sysdeps/s390/s390-64/multiarch/memcpy.c
@@ -18,7 +18,12 @@ 
 
 /* In the static lib memcpy is needed before the reloc is resolved.  */
 #if defined SHARED && IS_IN (libc)
+# define memcpy __redirect_memcpy
+# include <string.h>
+# undef memcpy
 # include <ifunc-resolve.h>
 
-s390_libc_ifunc (memcpy)
+extern __typeof (__redirect_memcpy) __libc_memcpy;
+s390_libc_ifunc (__memcpy, __libc_memcpy)
+strong_alias (__libc_memcpy, memcpy);
 #endif
diff --git a/sysdeps/s390/s390-64/multiarch/memset.c b/sysdeps/s390/s390-64/multiarch/memset.c
index 89b8102..db62760 100644
--- a/sysdeps/s390/s390-64/multiarch/memset.c
+++ b/sysdeps/s390/s390-64/multiarch/memset.c
@@ -17,7 +17,12 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #if IS_IN (libc)
+# define memset __redirect_memset
+# include <string.h>
+# undef memset
 # include <ifunc-resolve.h>
 
-s390_libc_ifunc (memset)
+extern __typeof (__redirect_memset) __libc_memset;
+s390_libc_ifunc (__memset, __libc_memset)
+strong_alias (__libc_memset, memset);
 #endif