This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] S/390: STT_GNU_IFUNC support


Hi,

the attached patch adds support for STT_GNU_IFUNC symbols on S/390.

The patch also adds optimized version for z10 and z196 of memcpy,
memset, and memcmp.  Starting with z10 these function are much faster
when using the prefetch data instruction (pfd).

With the patch glibc for S/390 needs the proper Binutils support to be
in place as well:

http://sourceware.org/ml/binutils/2012-07/msg00011.html

All ifunc tests are clean on s390 and s390x.

Bye,

-Andreas-


2012-07-02  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* elf/elf.h (R_390_IRELATIVE): New definition.
	* sysdeps/s390/s390-64/dl-machine.h (elf_machine_rela): Invoke the
	resolver function for IFUNC symbols.  Support R_390_IRELATIVE.
	(elf_machine_lazy_rel): Support R_390_IRELATIVE.
	* sysdeps/s390/s390-32/dl-machine.h (elf_machine_rela):
	(elf_machine_lazy_rel): Likewise.
	* sysdeps/s390/dl-irel.h: New file.
	* sysdeps/s390/s390-64/memset.S: Remove.
	* sysdeps/s390/s390-64/multiarch/memset.S: New file.
	* sysdeps/s390/s390-64/multiarch/ifunc-resolve.c: New file.
	* sysdeps/s390/s390-64/multiarch/memcmp.S: New file.
	* sysdeps/s390/s390-64/multiarch/memcpy.S: New file.
	* sysdeps/s390/s390-64/multiarch/Makefile: New file.
	* sysdeps/s390/s390-32/multiarch/ifunc-resolve.c: New file.
	* sysdeps/s390/s390-32/multiarch/Makefile: New file.
	* sysdeps/s390/s390-32/multiarch/memcmp.S: New file.
	* sysdeps/s390/s390-32/multiarch/memcpy.S: New file.
	* sysdeps/s390/s390-32/multiarch/memset.S: New file.
	* sysdeps/s390/s390-32/memcpy.S: Remove.
	* sysdeps/s390/s390-32/memset.S: Remove.
	* sysdeps/s390/s390-64/memcpy.S: Remove.

---
 elf/elf.h                                      |    3 
 sysdeps/s390/dl-irel.h                         |   52 +++++++++
 sysdeps/s390/s390-32/dl-machine.h              |   21 +++
 sysdeps/s390/s390-32/memcpy.S                  |   58 ----------
 sysdeps/s390/s390-32/memset.S                  |   44 --------
 sysdeps/s390/s390-32/multiarch/Makefile        |    9 +
 sysdeps/s390/s390-32/multiarch/ifunc-resolve.c |   40 +++++++
 sysdeps/s390/s390-32/multiarch/memcmp.S        |  120 ++++++++++++++++++++++
 sysdeps/s390/s390-32/multiarch/memcpy.S        |  136 +++++++++++++++++++++++++
 sysdeps/s390/s390-32/multiarch/memset.S        |  110 ++++++++++++++++++++
 sysdeps/s390/s390-64/dl-machine.h              |   23 ++++
 sysdeps/s390/s390-64/memcpy.S                  |   57 ----------
 sysdeps/s390/s390-64/memset.S                  |   43 -------
 sysdeps/s390/s390-64/multiarch/Makefile        |    3 
 sysdeps/s390/s390-64/multiarch/ifunc-resolve.c |   45 ++++++++
 sysdeps/s390/s390-64/multiarch/memcmp.S        |  118 +++++++++++++++++++++
 sysdeps/s390/s390-64/multiarch/memcpy.S        |  131 ++++++++++++++++++++++++
 sysdeps/s390/s390-64/multiarch/memset.S        |  106 +++++++++++++++++++
 18 files changed, 916 insertions(+), 203 deletions(-)

Index: glibc/elf/elf.h
===================================================================
--- glibc.orig/elf/elf.h
+++ glibc/elf/elf.h
@@ -2627,8 +2627,9 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
 #define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
 					   block offset.  */
+#define R_390_IRELATIVE         61      /* STT_GNU_IFUNC relocation.  */
 /* Keep this the last entry.  */
-#define R_390_NUM		61
+#define R_390_NUM		62
 
 
 /* CRIS relocations.  */
Index: glibc/sysdeps/s390/s390-64/dl-machine.h
===================================================================
--- glibc.orig/sysdeps/s390/s390-64/dl-machine.h
+++ glibc/sysdeps/s390/s390-64/dl-machine.h
@@ -26,6 +26,9 @@
 #include <sys/param.h>
 #include <string.h>
 #include <link.h>
+#include <dl-irel.h>
+
+#define ELF_MACHINE_IRELATIVE       R_390_IRELATIVE
 
 /* This is an older, now obsolete value.  */
 #define EM_S390_OLD	0xA390
@@ -280,8 +283,21 @@ elf_machine_rela (struct link_map *map, 
       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
       Elf64_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
 
+      if (sym != NULL
+	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
+			       0)
+	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
+	  && __builtin_expect (!skip_ifunc, 1))
+	value = elf_ifunc_invoke (value);
+
       switch (r_type)
 	{
+	case R_390_IRELATIVE:
+	  value = map->l_addr + reloc->r_addend;
+	  if (__builtin_expect (!skip_ifunc, 1))
+	    value = elf_ifunc_invoke (value);
+	  *reloc_addr = value;
+	  break;
 	case R_390_GLOB_DAT:
 	case R_390_JMP_SLOT:
 	  *reloc_addr = value + reloc->r_addend;
@@ -426,6 +442,13 @@ elf_machine_lazy_rel (struct link_map *m
 	  map->l_mach.plt
 	  + (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 4;
     }
+  else if (__builtin_expect (r_type == R_390_IRELATIVE, 1))
+    {
+      Elf64_Addr value = map->l_addr + reloc->r_addend;
+      if (__builtin_expect (!skip_ifunc, 1))
+  	value = elf_ifunc_invoke (value);
+      *reloc_addr = value;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
Index: glibc/sysdeps/s390/dl-irel.h
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/dl-irel.h
@@ -0,0 +1,52 @@
+/* Machine-dependent ELF indirect relocation inline functions.
+   s390x version.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_IREL_H
+#define _DL_IREL_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+
+#define ELF_MACHINE_IRELA	1
+
+static inline ElfW(Addr)
+__attribute ((always_inline))
+elf_ifunc_invoke (ElfW(Addr) addr)
+{
+  return ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap));
+}
+
+static inline void
+__attribute ((always_inline))
+elf_irela (const ElfW(Rela) *reloc)
+{
+  ElfW(Addr) *const reloc_addr = (void *) reloc->r_offset;
+  const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
+
+  if (__builtin_expect (r_type == R_390_IRELATIVE, 1))
+    {
+      ElfW(Addr) value = elf_ifunc_invoke(reloc->r_addend);
+      *reloc_addr = value;
+    }
+  else
+    __libc_fatal ("unexpected reloc type in static binary");
+}
+
+#endif /* dl-irel.h */
Index: glibc/sysdeps/s390/s390-64/memset.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-64/memset.S
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Set a block of memory to some byte value.  64 bit S/390 version.
-   Copyright (C) 2001, 2003 Free Software Foundation, Inc.
-   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-/* INPUT PARAMETERS
-     %r2 = address of memory area
-     %r3 = byte to fill memory with
-     %r4 = number of bytes to fill.  */
-
-#include "sysdep.h"
-#include "asm-syntax.h"
-
-	.text
-ENTRY(memset)
-	ltgr	%r4,%r4
-	jz	.L1
-	lgr	%r0,%r2		    # save source address
-	lgr	%r1,%r3		    # move pad byte to R1
-	lgr	%r3,%r4
-	sgr	%r4,%r4		    # no source for MVCLE, only a pad byte
-	sgr	%r5,%r5
-.L0:	mvcle	%r2,%r4,0(%r1)	    # thats it, MVCLE is your friend
-	jo	.L0
-	lgr	%r2,%r0		    # return value is source address
-.L1:
-	br	%r14
-END(memset)
-libc_hidden_builtin_def (memset)
Index: glibc/sysdeps/s390/s390-64/multiarch/memset.S
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-64/multiarch/memset.S
@@ -0,0 +1,106 @@
+/* Set a block of memory to some byte value.  64 bit S/390 version.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Andreas Krebbel (krebbel@linux.vnet.ibm.com)
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+/* INPUT PARAMETERS
+     %r2 = address of memory area
+     %r3 = byte to fill memory with
+     %r4 = number of bytes to fill.  */
+
+	.text
+ENTRY(memset_z196)
+	.machine "z196"
+        ltgr    %r4,%r4
+        je      .L_Z196_4
+        stc     %r3,0(%r2)
+        lgr     %r1,%r2
+        cghi    %r4,1
+        je      .L_Z196_4
+        aghi    %r4,-2
+        srlg    %r3,%r4,8
+        ltgr    %r3,%r3
+        jne     .L_Z196_2
+.L_Z196_3:
+        exrl    %r4,.L_Z196_17
+.L_Z196_4:
+        br      %r14
+.L_Z196_2:
+        pfd     2,1024(%r1)
+        mvc     1(256,%r1),0(%r1)
+        aghi    %r3,-1
+        la      %r1,256(%r1)
+        jne     .L_Z196_2
+        j       .L_Z196_3
+.L_Z196_17:
+        mvc     1(1,%r1),0(%r1)
+END(memset_z196)
+
+ENTRY(memset_z10)
+	.machine "z10"
+        cgije   %r4,0,.L_Z10_4
+        stc     %r3,0(%r2)
+        lgr     %r1,%r2
+        cgije   %r4,1,.L_Z10_4
+        aghi    %r4,-2
+        srlg    %r3,%r4,8
+        cgijlh  %r3,0,.L_Z10_14
+.L_Z10_3:
+        exrl    %r4,.L_Z10_18
+.L_Z10_4:
+        br      %r14
+.L_Z10_14:
+        pfd     2,1024(%r1)
+        mvc     1(256,%r1),0(%r1)
+        la      %r1,256(%r1)
+        brctg   %r3,.L_Z10_14
+        j       .L_Z10_3
+.L_Z10_18:
+        mvc     1(1,%r1),0(%r1)
+END(memset_z10)
+
+ENTRY(memset_z900)
+	.machine "z900"
+        ltgr    %r4,%r4
+        je      .L_Z900_4
+        stc     %r3,0(%r2)
+        cghi    %r4,1
+        lgr     %r1,%r2
+        je      .L_Z900_4
+        aghi    %r4,-2
+        srlg    %r3,%r4,8
+        ltgr    %r3,%r3
+        jne     .L_Z900_14
+.L_Z900_3:
+        larl    %r3,.L_Z900_18
+        ex      %r4,0(%r3)
+.L_Z900_4:
+        br      %r14
+.L_Z900_14:
+        mvc     1(256,%r1),0(%r1)
+        la      %r1,256(%r1)
+        brctg   %r3,.L_Z900_14
+        j       .L_Z900_3
+.L_Z900_18:
+        mvc     1(1,%r1),0(%r1)
+END(memset_z900)
+
+libc_hidden_builtin_def (memset)
Index: glibc/sysdeps/s390/s390-64/multiarch/ifunc-resolve.c
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-64/multiarch/ifunc-resolve.c
@@ -0,0 +1,45 @@
+#include <unistd.h>
+#include <dl-procinfo.h>
+
+#define STFLE_BITS_Z10  34 /* General instructions extension */
+#define STFLE_BITS_Z196 45 /* Distinct operands, pop ... */
+
+#define IFUNC_RESOLVE(FUNC)						\
+  asm (".globl " #FUNC "\n"						\
+       ".type  " #FUNC ",@gnu_indirect_function\n"			\
+       ".set   " #FUNC ",resolve_" #FUNC "\n");				\
+									\
+  extern void *FUNC##_z10;						\
+  extern void *FUNC##_z196;						\
+  extern void *FUNC##_z900;						\
+									\
+  void *resolve_##FUNC (unsigned long int dl_hwcap)			\
+  {									\
+    if (dl_hwcap & HWCAP_S390_STFLE)					\
+      {									\
+	/* We want just 1 double word to be returned.  */		\
+	register unsigned long reg0 asm("0") = 0;			\
+	unsigned long stfle_bits;					\
+									\
+	asm volatile(".machine push"        "\n\t"			\
+		     ".machine \"z9-109\""  "\n\t"			\
+		     "stfle %0"             "\n\t"			\
+		     ".machine pop"         "\n"			\
+		     : "=QS" (stfle_bits), "+d" (reg0)			\
+		     : : "cc");						\
+									\
+	if ((stfle_bits & (1UL << (63 - STFLE_BITS_Z196))) != 0)	\
+	  return &FUNC##_z196;						\
+	else if ((stfle_bits & (1UL << (63 - STFLE_BITS_Z10))) != 0)	\
+	  return &FUNC##_z10;						\
+	else								\
+	  return &FUNC##_z900;						\
+      }									\
+    else								\
+      return &FUNC##_z900;						\
+    }
+
+IFUNC_RESOLVE(memset)
+IFUNC_RESOLVE(memcpy)
+IFUNC_RESOLVE(memcmp)
+asm(".weak bcmp ; bcmp = memcmp");
Index: glibc/sysdeps/s390/s390-64/multiarch/memcmp.S
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-64/multiarch/memcmp.S
@@ -0,0 +1,118 @@
+/* CPU specific memcmp implementations.  64 bit S/390 version.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Andreas Krebbel (krebbel@linux.vnet.ibm.com)
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+/* INPUT PARAMETERS
+     %r2 = address of first memory area
+     %r3 = address of second memory area
+     %r4 = number of bytes to compare.  */
+
+	.text
+ENTRY(memcmp_z196)
+	.machine "z196"
+        ltgr    %r4,%r4
+        je      .L_Z196_4
+        aghi    %r4,-1
+        srlg    %r1,%r4,8
+        ltgr    %r1,%r1
+        jne     .L_Z196_2
+.L_Z196_3:
+        exrl    %r4,.L_Z196_14
+.L_Z196_4:
+        ipm     %r2
+        sllg    %r2,%r2,34
+        srag    %r2,%r2,62
+        br      %r14
+.L_Z196_17:
+        la      %r3,256(%r3)
+        la      %r2,256(%r2)
+        aghi    %r1,-1
+        je      .L_Z196_3
+.L_Z196_2:
+        pfd     1,512(%r3)
+        pfd     1,512(%r2)
+        clc     0(256,%r3),0(%r2)
+        je      .L_Z196_17
+        ipm     %r2
+        sllg    %r2,%r2,34
+        srag    %r2,%r2,62
+        br      %r14
+.L_Z196_14:
+        clc     0(1,%r3),0(%r2)
+END(memcmp_z196)
+
+
+ENTRY(memcmp_z10)
+	.machine "z10"
+        ltgr    %r4,%r4
+        je      .L_Z10_4
+        aghi    %r4,-1
+        srlg    %r1,%r4,8
+        cgijlh  %r1,0,.L_Z10_12
+.L_Z10_3:
+        exrl    %r4,.L_Z10_15
+.L_Z10_4:
+        ipm     %r2
+        sllg    %r2,%r2,34
+        srag    %r2,%r2,62
+        br      %r14
+.L_Z10_12:
+        pfd     1,512(%r3)
+        pfd     1,512(%r2)
+        clc     0(256,%r3),0(%r2)
+        jne     .L_Z10_4
+        la      %r3,256(%r3)
+        la      %r2,256(%r2)
+        brctg   %r1,.L_Z10_12
+        j       .L_Z10_3
+.L_Z10_15:
+        clc     0(1,%r3),0(%r2)
+END(memcmp_z10)
+
+ENTRY(memcmp_z900)
+	.machine "z900"
+        ltgr    %r4,%r4
+        je      .L_Z900_4
+        aghi    %r4,-1
+        srlg    %r1,%r4,8
+        ltgr    %r1,%r1
+        jne     .L_Z900_12
+.L_Z900_3:
+        larl    %r1,.L_Z900_15
+        ex      %r4,0(%r1)
+.L_Z900_4:
+        ipm     %r2
+        sllg    %r2,%r2,34
+        srag    %r2,%r2,62
+        br      %r14
+.L_Z900_12:
+        clc     0(256,%r3),0(%r2)
+        jne     .L_Z900_4
+        la      %r3,256(%r3)
+        la      %r2,256(%r2)
+        brctg   %r1,.L_Z900_12
+        j       .L_Z900_3
+.L_Z900_15:
+        clc     0(1,%r3),0(%r2)
+END(memcmp_z900)
+
+libc_hidden_builtin_def (memcmp)
Index: glibc/sysdeps/s390/s390-64/multiarch/memcpy.S
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-64/multiarch/memcpy.S
@@ -0,0 +1,131 @@
+/* CPU specific memcpy implementations.  64 bit S/390 version.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Andreas Krebbel (krebbel@linux.vnet.ibm.com)
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+/* INPUT PARAMETERS
+     %r2 = target operands address
+     %r3 = source operands address
+     %r4 = number of bytes to copy.  */
+
+.text
+
+ENTRY(memcpy_z196)
+	.machine "z196"
+        ltgr    %r4,%r4
+        je      .L_Z196_4
+        aghi    %r4,-1
+        lgr     %r1,%r2
+        srlg    %r5,%r4,8
+        ltgr    %r5,%r5
+        jne     .L_Z196_5
+.L_Z196_3:
+        exrl    %r4,.L_Z196_14
+.L_Z196_4:
+        br      %r14
+.L_Z196_5:
+        cghi    %r5,4096
+        jh      memcpy_mvcle
+.L_Z196_2:
+        pfd     1,768(%r3)
+        pfd     2,768(%r1)
+        mvc     0(256,%r1),0(%r3)
+        aghi    %r5,-1
+        la      %r1,256(%r1)
+        la      %r3,256(%r3)
+        jne     .L_Z196_2
+        j       .L_Z196_3
+.L_Z196_14:
+        mvc     0(1,%r1),0(%r3)
+END(memcpy_z196)
+
+ENTRY(memcpy_z10)
+	.machine "z10"
+        cgije   %r4,0,.L_Z10_4
+        aghi    %r4,-1
+        lgr     %r1,%r2
+        srlg    %r5,%r4,8
+	chi     %r5,255
+	jh      memcpy_mvcle
+        cgijlh  %r5,0,.L_Z10_13
+.L_Z10_3:
+        exrl    %r4,.L_Z10_15
+.L_Z10_4:
+        br      %r14
+.L_Z10_13:
+        cghi    %r5,4096
+        jh      memcpy_mvcle
+.L_Z10_12:
+        pfd     1,768(%r3)
+        pfd     2,768(%r1)
+        mvc     0(256,%r1),0(%r3)
+        la      %r1,256(%r1)
+        la      %r3,256(%r3)
+        brctg   %r5,.L_Z10_12
+        j       .L_Z10_3
+.L_Z10_15:
+        mvc     0(1,%r1),0(%r3)
+END(memcpy_z10)
+
+ENTRY(memcpy_z900)
+	.machine "z900"
+        ltgr    %r4,%r4
+        je      .L_Z900_4
+        aghi    %r4,-1
+        srlg    %r5,%r4,8
+        ltgr    %r5,%r5
+        lgr     %r1,%r2
+        jne     .L_Z900_13
+.L_Z900_3:
+        larl    %r5,.L_Z900_15
+        ex      %r4,0(%r5)
+.L_Z900_4:
+        br      %r14
+.L_Z900_13:
+        chi     %r5,4096
+        jh      memcpy_mvcle
+.L_Z900_12:
+        mvc     0(256,%r1),0(%r3)
+        la      %r1,256(%r1)
+        la      %r3,256(%r3)
+        brctg   %r5,.L_Z900_12
+        j       .L_Z900_3
+.L_Z900_15:
+        mvc     0(1,%r1),0(%r3)
+END(memcpy_z900)
+
+ENTRY(memcpy_mvcle)
+       # Using as standalone function will result in unexpected
+       # results since the length field is incremented by 1 in order to
+       # compensate the changes already done in the functions above.
+       # data copies > 1MB are faster with mvcle.
+       aghi    %r4,1               # length + 1
+       lgr     %r5,%r4             # source length
+       lgr     %r4,%r3             # source address
+       lgr     %r3,%r5             # destination length = source length
+.L_MVCLE_1:
+       mvcle   %r2,%r4,0           # thats it, MVCLE is your friend
+       jo      .L_MVCLE_1
+       lgr     %r2,%r1             # return destination address
+       br      %r14
+END(memcpy_mvcle)
+
+libc_hidden_builtin_def (memcpy)
Index: glibc/sysdeps/s390/s390-64/multiarch/Makefile
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-64/multiarch/Makefile
@@ -0,0 +1,3 @@
+ifeq ($(subdir),string)
+sysdep_routines += ifunc-resolve memset memcpy memcmp
+endif
Index: glibc/sysdeps/s390/s390-32/multiarch/ifunc-resolve.c
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-32/multiarch/ifunc-resolve.c
@@ -0,0 +1,40 @@
+#include <unistd.h>
+#include <dl-procinfo.h>
+
+#define STFLE_BITS_Z10  34 /* General instructions extension */
+#define STFLE_BITS_Z196 45 /* Distinct operands, pop ... */
+
+#define IFUNC_RESOLVE(FUNC)						\
+  asm (".globl " #FUNC "\n"						\
+       ".type  " #FUNC ",@gnu_indirect_function\n"			\
+       ".set   " #FUNC ",resolve_" #FUNC "\n");				\
+									\
+  extern void *FUNC##_z10;						\
+  extern void *FUNC##_z196;						\
+  extern void *FUNC##_g5;						\
+									\
+  void *resolve_##FUNC (unsigned long int dl_hwcap)			\
+  {									\
+    if ((dl_hwcap & HWCAP_S390_STFLE)					\
+	&& (dl_hwcap & HWCAP_S390_HIGH_GPRS)) /* Implies zarch */	\
+      {									\
+	/* We want just 1 double word to be returned.  */		\
+	register unsigned long reg0 asm("0") = 0;			\
+	unsigned long long stfle_bits;					\
+									\
+	asm volatile(".insn s,0xb2b00000,%0" "\n\t"  /* stfle */	\
+		     : "=QS" (stfle_bits), "+d" (reg0)			\
+		     : : "cc");						\
+									\
+	if ((stfle_bits & (1ULL << (63 - STFLE_BITS_Z196))) != 0)	\
+	  return &FUNC##_z196;						\
+	else if ((stfle_bits & (1ULL << (63 - STFLE_BITS_Z10))) != 0)	\
+	  return &FUNC##_z10;						\
+      }									\
+    return &FUNC##_g5;							\
+  }
+
+IFUNC_RESOLVE(memset)
+IFUNC_RESOLVE(memcmp)
+IFUNC_RESOLVE(memcpy)
+asm(".weak bcmp ; bcmp = memcmp");
Index: glibc/sysdeps/s390/s390-32/multiarch/Makefile
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-32/multiarch/Makefile
@@ -0,0 +1,9 @@
+ASFLAGS-.o += -Wa,-mzarch
+ASFLAGS-.os += -Wa,-mzarch
+ASFLAGS-.op += -Wa,-mzarch
+ASFLAGS-.og += -Wa,-mzarch
+ASFLAGS-.ob += -Wa,-mzarch
+ASFLAGS-.oS += -Wa,-mzarch
+ifeq ($(subdir),string)
+sysdep_routines += ifunc-resolve memset memcpy memcmp
+endif
Index: glibc/sysdeps/s390/s390-32/multiarch/memcmp.S
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-32/multiarch/memcmp.S
@@ -0,0 +1,120 @@
+/* CPU specific memcmp implementations.  32 bit S/390 version.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Andreas Krebbel (krebbel@linux.vnet.ibm.com)
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+/* INPUT PARAMETERS
+     %r2 = address of first memory area
+     %r3 = address of second memory area
+     %r4 = number of bytes to compare.  */
+
+	.text
+ENTRY(memcmp_z196)
+	.machine "z196"
+        ltr     %r4,%r4
+        je      .L_Z196_4
+        ahi     %r4,-1
+        srlk    %r1,%r4,8
+        ltr     %r1,%r1
+        jne     .L_Z196_2
+.L_Z196_3:
+        exrl    %r4,.L_Z196_14
+.L_Z196_4:
+        ipm     %r2
+        sll     %r2,2
+        sra     %r2,30
+        br      %r14
+.L_Z196_17:
+        la      %r3,256(%r3)
+        la      %r2,256(%r2)
+        ahi     %r1,-1
+        je      .L_Z196_3
+.L_Z196_2:
+        pfd     1,512(%r3)
+        pfd     1,512(%r2)
+        clc     0(256,%r3),0(%r2)
+        je      .L_Z196_17
+        ipm     %r2
+        sll     %r2,2
+        sra     %r2,30
+        br      %r14
+.L_Z196_14:
+        clc     0(1,%r3),0(%r2)
+END(memcmp_z196)
+
+ENTRY(memcmp_z10)
+	.machine "z10"
+        ltr     %r4,%r4
+        je      .L_Z10_4
+        ahi     %r4,-1
+        lr      %r1,%r4
+        srl     %r1,8
+        cijlh   %r1,0,.L_Z10_12
+.L_Z10_3:
+        exrl    %r4,.L_Z10_15
+.L_Z10_4:
+        ipm     %r2
+        sll     %r2,2
+        sra     %r2,30
+        br      %r14
+.L_Z10_12:
+        pfd     1,512(%r3)
+        pfd     1,512(%r2)
+        clc     0(256,%r3),0(%r2)
+        jne     .L_Z10_4
+        la      %r3,256(%r3)
+        la      %r2,256(%r2)
+        brct    %r1,.L_Z10_12
+        j       .L_Z10_3
+.L_Z10_15:
+        clc     0(1,%r3),0(%r2)
+END(memcmp_z10)
+
+ENTRY(memcmp_g5)
+	.machine "g5"
+        basr    %r5,0
+.L_G5_16:
+        ltr     %r4,%r4
+        je      .L_G5_4
+        ahi     %r4,-1
+        lr      %r1,%r4
+        srl     %r1,8
+        ltr     %r1,%r1
+        jne     .L_G5_12
+        ex      %r4,.L_G5_17-.L_G5_16(%r5)
+.L_G5_4:
+        ipm     %r2
+        sll     %r2,2
+        sra     %r2,30
+        br      %r14
+.L_G5_12:
+        clc     0(256,%r3),0(%r2)
+        jne     .L_G5_4
+        la      %r3,256(%r3)
+        la      %r2,256(%r2)
+        brct    %r1,.L_G5_12
+        ex      %r4,.L_G5_17-.L_G5_16(%r5)
+        j       .L_G5_4
+.L_G5_17:
+        clc     0(1,%r3),0(%r2)
+END(memcmp_g5)
+
+libc_hidden_builtin_def (memcmp)
Index: glibc/sysdeps/s390/s390-32/multiarch/memcpy.S
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-32/multiarch/memcpy.S
@@ -0,0 +1,136 @@
+/* CPU specific memcpy implementations.  32 bit S/390 version.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Andreas Krebbel (krebbel@linux.vnet.ibm.com)
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+/* INPUT PARAMETERS
+     %r2 = target operands address
+     %r3 = source operands address
+     %r4 = number of bytes to copy.  */
+
+.text
+
+ENTRY(memcpy_z196)
+	.machine "z196"
+        llgfr   %r4,%r4
+        ltgr    %r4,%r4
+        je      .L_Z196_4
+        aghi    %r4,-1
+        lr      %r1,%r2
+        srlg    %r5,%r4,8
+        ltgr    %r5,%r5
+        jne     .L_Z196_5
+.L_Z196_3:
+        exrl    %r4,.L_Z196_14
+.L_Z196_4:
+        br      %r14
+.L_Z196_5:
+        cghi    %r5,4096
+        jh      memcpy_mvcle
+.L_Z196_2:
+        pfd     1,768(%r3)
+        pfd     2,768(%r1)
+        mvc     0(256,%r1),0(%r3)
+        aghi    %r5,-1
+        la      %r1,256(%r1)
+        la      %r3,256(%r3)
+        jne     .L_Z196_2
+        j       .L_Z196_3
+.L_Z196_14:
+        mvc     0(1,%r1),0(%r3)
+END(memcpy_z196)
+
+ENTRY(memcpy_z10)
+	.machine "z10"
+        llgfr   %r4,%r4
+        cgije   %r4,0,.L_Z10_4
+        aghi    %r4,-1
+        lr      %r1,%r2
+        srlg    %r5,%r4,8
+        cgijlh  %r5,0,.L_Z10_13
+.L_Z10_3:
+        exrl    %r4,.L_Z10_15
+.L_Z10_4:
+        br      %r14
+.L_Z10_13:
+        cghi    %r5,4096
+        jh      memcpy_mvcle
+.L_Z10_12:
+        pfd     1,768(%r3)
+        pfd     2,768(%r1)
+        mvc     0(256,%r1),0(%r3)
+        la      %r1,256(%r1)
+        la      %r3,256(%r3)
+        brctg   %r5,.L_Z10_12
+        j       .L_Z10_3
+.L_Z10_15:
+        mvc     0(1,%r1),0(%r3)
+END(memcpy_z10)
+
+ENTRY(memcpy_g5)
+	.machine "g5"
+        st      %r13,52(%r15)
+        .cfi_offset 13, -44
+        basr    %r13,0
+.L_G5_16:
+        ltr     %r4,%r4
+        je      .L_G5_4
+        ahi     %r4,-1
+        lr      %r5,%r4
+        srl     %r5,8
+        ltr     %r5,%r5
+        lr      %r1,%r2
+        jne     .L_G5_12
+        ex      %r4,.L_G5_17-.L_G5_16(%r13)
+.L_G5_4:
+        l       %r13,52(%r15)
+        br      %r14
+.L_G5_13:
+        chi	%r5,4096             # > 1 MB to move ?
+        jh	memcpy_mvcle
+.L_G5_12:
+        mvc     0(256,%r1),0(%r3)
+        la      %r1,256(%r1)
+        la      %r3,256(%r3)
+        brct    %r5,.L_G5_12
+        ex      %r4,.L_G5_17-.L_G5_16(%r13)
+        j       .L_G5_4
+.L_G5_17:
+        mvc     0(1,%r1),0(%r3)
+END(memcpy_g5)
+
+ENTRY(memcpy_mvcle)
+       # Using as standalone function will result in unexpected
+       # results since the length field is incremented by 1 in order to
+       # compensate the changes already done in the functions above.
+       # data copies > 1MB are faster with mvcle.
+       ahi     %r4,1               # length + 1
+       lr      %r5,%r4             # source length
+       lr      %r4,%r3             # source address
+       lr      %r3,%r5             # destination length = source length
+.L_MVCLE_1:
+       mvcle   %r2,%r4,0           # thats it, MVCLE is your friend
+       jo      .L_MVCLE_1
+       lr      %r2,%r1             # return destination address
+       br      %r14
+END(memcpy_mvcle)
+
+libc_hidden_builtin_def (memcpy)
Index: glibc/sysdeps/s390/s390-32/multiarch/memset.S
===================================================================
--- /dev/null
+++ glibc/sysdeps/s390/s390-32/multiarch/memset.S
@@ -0,0 +1,110 @@
+/* Set a block of memory to some byte value.  32 bit S/390 version.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Andreas Krebbel (krebbel@linux.vnet.ibm.com)
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+/* INPUT PARAMETERS
+     %r2 = address of memory area
+     %r3 = byte to fill memory with
+     %r4 = number of bytes to fill.  */
+
+	.text
+ENTRY(memset_z196)
+	.machine "z196"
+        llgfr   %r4,%r4
+        ltgr    %r4,%r4
+        je      .L_Z196_4
+        stc     %r3,0(%r2)
+        lr      %r1,%r2
+        cghi    %r4,1
+        je      .L_Z196_4
+        aghi    %r4,-2
+        srlg    %r3,%r4,8
+        ltgr    %r3,%r3
+        jne     .L_Z196_2
+.L_Z196_3:
+        exrl    %r4,.L_Z196_17
+.L_Z196_4:
+        br      %r14
+.L_Z196_2:
+        pfd     2,1024(%r1)
+        mvc     1(256,%r1),0(%r1)
+        aghi    %r3,-1
+        la      %r1,256(%r1)
+        jne     .L_Z196_2
+        j       .L_Z196_3
+.L_Z196_17:
+        mvc     1(1,%r1),0(%r1)
+END(memset_z196)
+
+ENTRY(memset_z10)
+	.machine "z10"
+        llgfr   %r4,%r4
+        cgije   %r4,0,.L_Z10_4
+        stc     %r3,0(%r2)
+        lr      %r1,%r2
+        cgije   %r4,1,.L_Z10_4
+        aghi    %r4,-2
+        srlg    %r3,%r4,8
+        cgijlh  %r3,0,.L_Z10_14
+.L_Z10_3:
+        exrl    %r4,.L_Z10_18
+.L_Z10_4:
+        br      %r14
+.L_Z10_14:
+        pfd     2,1024(%r1)
+        mvc     1(256,%r1),0(%r1)
+        la      %r1,256(%r1)
+        brctg   %r3,.L_Z10_14
+        j       .L_Z10_3
+.L_Z10_18:
+        mvc     1(1,%r1),0(%r1)
+END(memset_z10)
+
+ENTRY(memset_g5)
+	.machine "g5"
+        basr    %r5,0
+.L_G5_19:
+        ltr     %r4,%r4
+        je      .L_G5_4
+        stc     %r3,0(%r2)
+        chi     %r4,1
+        lr      %r1,%r2
+        je      .L_G5_4
+        ahi     %r4,-2
+        lr      %r3,%r4
+        srl     %r3,8
+        ltr     %r3,%r3
+        jne     .L_G5_14
+        ex      %r4,.L_G5_20-.L_G5_19(%r5)
+.L_G5_4:
+        br      %r14
+.L_G5_14:
+        mvc     1(256,%r1),0(%r1)
+        la      %r1,256(%r1)
+        brct    %r3,.L_G5_14
+        ex      %r4,.L_G5_20-.L_G5_19(%r5)
+        j       .L_G5_4
+.L_G5_20:
+        mvc     1(1,%r1),0(%r1)
+END(memset_g5)
+
+libc_hidden_builtin_def (memset)
Index: glibc/sysdeps/s390/s390-32/memcpy.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-32/memcpy.S
+++ /dev/null
@@ -1,58 +0,0 @@
-/* memcpy - copy a block from source to destination.  S/390 version.
-   Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-/* INPUT PARAMETERS
-     %r2 = address of destination memory area
-     %r3 = address of source memory area
-     %r4 = number of bytes to copy.  */
-
-#include "sysdep.h"
-#include "asm-syntax.h"
-
-	.text
-ENTRY(memcpy)
-	ltr     %r4,%r4
-	jz      .L3
-	ahi     %r4,-1              # length - 1
-	lr      %r1,%r2             # copy destination address
-	lr      %r5,%r4
-	srl     %r5,8
-	ltr     %r5,%r5             # < 256 bytes to move ?
-	jz      .L1
-	chi     %r5,255             # > 1MB to move ?
-	jh      .L4
-.L0:	mvc     0(256,%r1),0(%r3)   # move in 256 byte chunks
-	la      %r1,256(%r1)
-	la      %r3,256(%r3)
-	brct    %r5,.L0
-.L1:	bras    %r5,.L2             # setup base pointer for execute
-	mvc     0(1,%r1),0(%r3)     # instruction for execute
-.L2:	ex      %r4,0(%r5)          # execute mvc with length ((%r4)&255)+1
-.L3:	br      %r14
-	# data copies > 1MB are faster with mvcle.
-.L4:	ahi     %r4,1               # length + 1
-	lr      %r5,%r4	            # source length
-	lr	%r4,%r3             # source address
-	lr	%r3,%r5             # destination length = source length
-.L5:	mvcle	%r2,%r4,0           # thats it, MVCLE is your friend
-	jo	.L5
-	lr      %r2,%r1             # return destination address
-	br	%r14
-END(memcpy)
-libc_hidden_builtin_def (memcpy)
Index: glibc/sysdeps/s390/s390-32/memset.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-32/memset.S
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Set a block of memory to some byte value.  For IBM S390
-   Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-/*
- * R2 = address to memory area
- * R3 = byte to fill memory with
- * R4 = number of bytes to fill
- */
-
-#include "sysdep.h"
-#include "asm-syntax.h"
-
-	.text
-ENTRY(memset)
-	ltr     %r4,%r4
-	jz      .L1
-	lr      %r0,%r2             # save source address
-	lr      %r1,%r3             # move pad byte to R1
-	lr      %r3,%r4
-	sr      %r4,%r4             # no source for MVCLE, only a pad byte
-	sr      %r5,%r5
-.L0:    mvcle   %r2,%r4,0(%r1)      # thats it, MVCLE is your friend
-	jo      .L0
-	lr      %r2,%r0             # return value is source address
-.L1:
-	br      %r14
-END(memset)
-libc_hidden_builtin_def (memset)
Index: glibc/sysdeps/s390/s390-64/memcpy.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-64/memcpy.S
+++ /dev/null
@@ -1,57 +0,0 @@
-/* memcpy - copy a block from source to destination.  64 bit S/390 version.
-   Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-/* INPUT PARAMETERS
-     %r2 = address of destination memory area
-     %r3 = address of source memory area
-     %r4 = number of bytes to copy.  */
-
-#include "sysdep.h"
-#include "asm-syntax.h"
-
-	.text
-ENTRY(memcpy)
-	ltgr	%r4,%r4
-	jz	.L3
-	aghi	%r4,-1		    # length - 1
-	lgr	%r1,%r2		    # copy destination address
-	srlg	%r5,%r4,8
-	ltgr    %r5,%r5             # < 256 bytes to mvoe ?
-	jz	.L1
-	chi     %r5,255             # > 1 MB to move ?
-	jh	.L4
-.L0:	mvc	0(256,%r1),0(%r3)   # move in 256 byte chunks
-	la	%r1,256(%r1)
-	la	%r3,256(%r3)
-	brctg	%r5,.L0
-.L1:	bras	%r5,.L2		    # setup base pointer for execute
-	mvc	0(1,%r1),0(%r3)	    # instruction for execute
-.L2:	ex	%r4,0(%r5)	    # execute mvc with length ((%r4)&255)+1
-.L3:	br	%r14
-	# data copies > 1MB are faster with mvcle.
-.L4:	aghi    %r4,1               # length + 1
-	lgr	%r5,%r4	            # source length
-	lgr	%r4,%r3             # source address
-	lgr	%r3,%r5             # destination length = source length
-.L5:	mvcle	%r2,%r4,0           # thats it, MVCLE is your friend
-	jo	.L5
-	lgr     %r2,%r1             # return destination address
-	br	%r14
-END(memcpy)
-libc_hidden_builtin_def (memcpy)
Index: glibc/sysdeps/s390/s390-32/dl-machine.h
===================================================================
--- glibc.orig/sysdeps/s390/s390-32/dl-machine.h
+++ glibc/sysdeps/s390/s390-32/dl-machine.h
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <link.h>
 #include <sysdeps/s390/dl-procinfo.h>
+#include <dl-irel.h>
 
 /* This is an older, now obsolete value.  */
 #define EM_S390_OLD	0xA390
@@ -305,8 +306,21 @@ elf_machine_rela (struct link_map *map, 
       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
       Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
 
+      if (sym != NULL
+	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
+	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
+	  && __builtin_expect (!skip_ifunc, 1))
+	value = elf_ifunc_invoke (value);
+
       switch (r_type)
 	{
+	case R_390_IRELATIVE:
+	  value = map->l_addr + reloc->r_addend;
+	  if (__builtin_expect (!skip_ifunc, 1))
+	    value = elf_ifunc_invoke (value);
+	  *reloc_addr = value;
+	  break;
+
 	case R_390_GLOB_DAT:
 	case R_390_JMP_SLOT:
 	  *reloc_addr = value + reloc->r_addend;
@@ -444,6 +458,13 @@ elf_machine_lazy_rel (struct link_map *m
 	  map->l_mach.plt
 	  + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 8;
     }
+  else if (__builtin_expect (r_type == R_390_IRELATIVE, 1))
+    {
+      Elf32_Addr value = map->l_addr + reloc->r_addend;
+      if (__builtin_expect (!skip_ifunc, 1))
+	value = elf_ifunc_invoke (value);
+      *reloc_addr = value;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]