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: Fix two issues with the IFUNC optimized mem* routines


Hi,

the attached patch fixes two problems with the S/390 IFUNC
optimization of the mem* functions:

1. In the current implementation the resolver functions reside in a
different file than the CPU optimized versions.  This requires an
R_390_RELATIVE runtime relocation to be generated when the resolver
returns the function pointers. This caused a bug with GCJ. libgcj
calls memcpy via function pointer (R_390_GLOB_DAT).  This relocation
is resolved at load time of libgcj.  The dynamic linker in that case
called the memcpy resolver inside Glibc *before* glibc has been
relocated causing the resolver to return a bogus value.

This perhaps could also be fixed in the dynamic linker by calling the
ifunc resolvers only in a second pass over all the relocations?!

2. I've seen some problems with the Glibc internal symbols (__GI*) for
the IFUNC optimized routines.  I'll have to look deeper into it but
for now I've chosen to do the same as x86 and make the internal
symbols point to a particular implementation without using IFUNC. This
is unfortunate and should be fixed in the future.

I've tested the attached patch in various combinations and will apply
it in a couple of days to leave some time for comments.

Bye,

-Andreas-

2012-08-29  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	* sysdeps/s390/s390-32/multiarch/ifunc-resolve.c
	(STATIC_FUNC_PTR): New macro.
	(IFUNC_RESOLVE): Use STATIC_FUNC_PTR to obtain pointers to the
	specialized implementations.  Remove creation of the Glibc
	internal variants __GI*.
	* sysdeps/s390/s390-64/multiarch/ifunc-resolve.c: Likewise.
	* sysdeps/s390/s390-32/memcmp.S: Redirect the Glibc internal
	symbol __GI* to the version for the oldest CPU without using
	IFUNC.
	* sysdeps/s390/s390-32/memcpy.S: Likewise.
	* sysdeps/s390/s390-32/memset.S: Likewise.
	* sysdeps/s390/s390-64/memcmp.S: Likewise.
	* sysdeps/s390/s390-64/memcpy.S: Likewise.
	* sysdeps/s390/s390-64/memset.S: Likewise.

---
 sysdeps/s390/s390-32/memcmp.S                  |    2 +
 sysdeps/s390/s390-32/memcpy.S                  |    2 +
 sysdeps/s390/s390-32/memset.S                  |    2 +
 sysdeps/s390/s390-32/multiarch/ifunc-resolve.c |   50 ++++++++++++++++++++-----
 sysdeps/s390/s390-64/memcmp.S                  |    3 +
 sysdeps/s390/s390-64/memcpy.S                  |    2 +
 sysdeps/s390/s390-64/memset.S                  |    2 +
 sysdeps/s390/s390-64/multiarch/ifunc-resolve.c |   26 ++++++-------
 8 files changed, 66 insertions(+), 23 deletions(-)

Index: glibc/sysdeps/s390/s390-32/multiarch/ifunc-resolve.c
===================================================================
--- glibc.orig/sysdeps/s390/s390-32/multiarch/ifunc-resolve.c
+++ glibc/sysdeps/s390/s390-32/multiarch/ifunc-resolve.c
@@ -25,16 +25,46 @@
 
 #ifndef NOT_IN_libc
 
+/* Macro to obtain a pointer to the specialized functions.  The
+   functions are defined in a different module but still need to be
+   handled like static functions in order to avoid R_390_RELATIVE
+   relocs generated for them.  So far it is racy if the body of an
+   IFUNC resolver needs a relocation and the resolver is called via
+   function pointer from another shared object.  */
+#ifdef PIC
+#define STATIC_FUNC_PTR(FUNC)					\
+  ({ void *ptr;							\
+    unsigned long litbase;					\
+    unsigned long got;						\
+    asm ("        basr    %[LITBASE],0"                "\n\t"	\
+	 "0:      l       %[GOT],2f-0b(%[LITBASE])"    "\n\t"	\
+         "        la      %[GOT],0(%[GOT],%[LITBASE])" "\n\t"	\
+	 "        l       %[PTR],1f-0b(%[LITBASE])"    "\n\t"	\
+	 "        la      %[PTR],0(%[PTR],%[GOT])"     "\n\t"	\
+         "        j       3f"                          "\n\t"   \
+	 "1:      .long   " #FUNC "@GOTOFF"            "\n\t"	\
+         "2:      .long   _GLOBAL_OFFSET_TABLE_-0b"    "\n\t"	\
+         "3:"                                          "\n"	\
+	 : [PTR] "=a" (ptr), [LITBASE] "=a" (litbase),		\
+	   [GOT] "=a" (got): :);				\
+    ptr; })
+#else
+#define STATIC_FUNC_PTR(FUNC)					\
+  ({ void *ptr;							\
+    unsigned long litbase;					\
+    asm ("        basr    %[LITBASE],0"              "\n\t"	\
+	 "0:      l       %[PTR],1f-0b(%[LITBASE])"  "\n\t"	\
+         "        j       2f"                        "\n\t"	\
+	 "1:      .long   " #FUNC                    "\n\t"	\
+         "2:"                                        "\n"	\
+	 : [PTR] "=d" (ptr), [LITBASE] "=a" (litbase) : :);	\
+    ptr; })
+#endif
+
 #define IFUNC_RESOLVE(FUNC)						\
   asm (".globl " #FUNC "\n\t"						\
        ".type  " #FUNC ",@gnu_indirect_function\n\t"			\
-       ".set   " #FUNC ",resolve_" #FUNC "\n\t"				\
-       ".globl __GI_" #FUNC "\n\t"					\
-       ".set   __GI_" #FUNC "," #FUNC "\n");				\
-									\
-  extern void *FUNC##_z10;						\
-  extern void *FUNC##_z196;						\
-  extern void *FUNC##_g5;						\
+       ".set   " #FUNC ",resolve_" #FUNC "\n");				\
 									\
   void *resolve_##FUNC (unsigned long int dl_hwcap)			\
   {									\
@@ -50,11 +80,11 @@
 		     : : "cc");						\
 									\
 	if ((stfle_bits & (1ULL << (63 - STFLE_BITS_Z196))) != 0)	\
-	  return &FUNC##_z196;						\
+	  return STATIC_FUNC_PTR (FUNC##_z196);				\
 	else if ((stfle_bits & (1ULL << (63 - STFLE_BITS_Z10))) != 0)	\
-	  return &FUNC##_z10;						\
+	  return STATIC_FUNC_PTR (FUNC##_z10);				\
       }									\
-    return &FUNC##_g5;							\
+    return STATIC_FUNC_PTR (FUNC##_g5);					\
   }
 
 IFUNC_RESOLVE(memset)
Index: glibc/sysdeps/s390/s390-64/multiarch/ifunc-resolve.c
===================================================================
--- glibc.orig/sysdeps/s390/s390-64/multiarch/ifunc-resolve.c
+++ glibc/sysdeps/s390/s390-64/multiarch/ifunc-resolve.c
@@ -25,16 +25,19 @@
 
 #ifndef NOT_IN_libc
 
+/* Macro to obtain a pointer to the specialized functions.  The
+   functions are defined in a different module but still need to be
+   handled like static functions in order to avoid R_390_RELATIVE
+   relocs generated for them.  So far it is racy if the body of an
+   IFUNC resolver needs a relocation and the resolver is called via
+   function pointer from another shared object.  */
+#define STATIC_FUNC_PTR(FUNC)						\
+  ({ void *ptr; asm ("larl   %0," #FUNC "\n" : "=d" (ptr) : :); ptr; })
+
 #define IFUNC_RESOLVE(FUNC)						\
   asm (".globl " #FUNC "\n\t"						\
        ".type  " #FUNC ",@gnu_indirect_function\n\t"			\
-       ".set   " #FUNC ",resolve_" #FUNC "\n\t"				\
-       ".globl __GI_" #FUNC "\n\t"					\
-       ".set   __GI_" #FUNC "," #FUNC "\n");				\
-									\
-  extern void *FUNC##_z10;						\
-  extern void *FUNC##_z196;						\
-  extern void *FUNC##_z900;						\
+       ".set   " #FUNC ",resolve_" #FUNC "\n");				\
 									\
   void *resolve_##FUNC (unsigned long int dl_hwcap)			\
   {									\
@@ -52,14 +55,11 @@
 		     : : "cc");						\
 									\
 	if ((stfle_bits & (1UL << (63 - STFLE_BITS_Z196))) != 0)	\
-	  return &FUNC##_z196;						\
+	  return STATIC_FUNC_PTR (FUNC##_z196);				\
 	else if ((stfle_bits & (1UL << (63 - STFLE_BITS_Z10))) != 0)	\
-	  return &FUNC##_z10;						\
-	else								\
-	  return &FUNC##_z900;						\
+	  return STATIC_FUNC_PTR (FUNC##_z10);				\
       }									\
-    else								\
-      return &FUNC##_z900;						\
+    return STATIC_FUNC_PTR (FUNC##_z900);				\
   }
 
 IFUNC_RESOLVE(memset)
Index: glibc/sysdeps/s390/s390-64/memcmp.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-64/memcmp.S
+++ glibc/sysdeps/s390/s390-64/memcmp.S
@@ -57,6 +57,9 @@ ENTRY(memcmp)
         clc     0(1,%r3),0(%r2)
 #ifdef USE_MULTIARCH
 END(memcmp_z900)
+	.globl	__GI_memcmp
+	.set	__GI_memcmp, memcmp_z900
+weak_alias (memcmp_z900, bcmp)
 #else
 END(memcmp)
 libc_hidden_builtin_def (memcmp)
Index: glibc/sysdeps/s390/s390-64/memcpy.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-64/memcpy.S
+++ glibc/sysdeps/s390/s390-64/memcpy.S
@@ -60,6 +60,8 @@ ENTRY(memcpy)
 
 #ifdef USE_MULTIARCH
 END(memcpy_z900)
+	.globl	__GI_memcpy
+	.set	__GI_memcpy, memcpy_z900
 #else
 END(memcpy)
 libc_hidden_builtin_def (memcpy)
Index: glibc/sysdeps/s390/s390-64/memset.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-64/memset.S
+++ glibc/sysdeps/s390/s390-64/memset.S
@@ -58,6 +58,8 @@ ENTRY(memset)
         mvc     1(1,%r1),0(%r1)
 #ifdef USE_MULTIARCH
 END(memset_z900)
+	.globl	__GI_memset
+	.set	__GI_memset, memset_z900
 #else
 END(memset)
 libc_hidden_builtin_def (memset)
Index: glibc/sysdeps/s390/s390-32/memcmp.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-32/memcmp.S
+++ glibc/sysdeps/s390/s390-32/memcmp.S
@@ -59,6 +59,8 @@ ENTRY(memcmp)
         clc     0(1,%r3),0(%r2)
 #ifdef USE_MULTIARCH
 END(memcmp_g5)
+	.globl	__GI_memcmp
+	.set	__GI_memcmp, memcmp_g5
 #else
 END(memcmp)
 libc_hidden_builtin_def (memcmp)
Index: glibc/sysdeps/s390/s390-32/memcpy.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-32/memcpy.S
+++ glibc/sysdeps/s390/s390-32/memcpy.S
@@ -61,6 +61,8 @@ ENTRY(memcpy)
         mvc     0(1,%r1),0(%r3)
 #ifdef USE_MULTIARCH
 END(memcpy_g5)
+	.globl	__GI_memcpy
+	.set	__GI_memcpy, memcpy_g5
 #else
 END(memcpy)
 libc_hidden_builtin_def (memcpy)
Index: glibc/sysdeps/s390/s390-32/memset.S
===================================================================
--- glibc.orig/sysdeps/s390/s390-32/memset.S
+++ glibc/sysdeps/s390/s390-32/memset.S
@@ -59,6 +59,8 @@ ENTRY(memset)
         mvc     1(1,%r1),0(%r1)
 #ifdef USE_MULTIARCH
 END(memset_g5)
+	.globl	__GI_memset
+	.set	__GI_memset, memset_g5
 #else
 END(memset)
 libc_hidden_builtin_def (memset)


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