This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] S/390: Fix two issues with the IFUNC optimized mem* routines
- From: "Andreas Krebbel" <andreas at de dot ibm dot com>
- To: libc-alpha at sourceware dot org
- Date: Wed, 29 Aug 2012 12:44:21 +0200
- Subject: [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)