]>
Commit | Line | Data |
---|---|---|
bb330e25 AF |
1 | From a5675717e35a02a3eba7e13701c6f9c0d7222e13 Mon Sep 17 00:00:00 2001 |
2 | From: Adhemerval Zanella <azanella@linux.vnet.ibm.com> | |
3 | Date: Fri, 7 Jun 2013 14:50:23 -0500 | |
4 | Subject: [PATCH 2/2] PowerPC: gettimeofday optimization by using IFUNC | |
5 | ||
6 | Backport of ef26eece6331a1f6d959818e37c438cc7ce68e53 from master. | |
7 | --- | |
8 | sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h | 10 ++++ | |
9 | sysdeps/unix/sysv/linux/powerpc/gettimeofday.c | 49 +++++++++++++++------- | |
10 | 2 files changed, 44 insertions(+), 15 deletions(-) | |
11 | ||
12 | commit 76a9b9986141b1a7d9fd290c349d27fcee780c7a | |
13 | Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com> | |
14 | Date: Thu Nov 7 05:34:22 2013 -0600 | |
15 | ||
16 | PowerPC: Fix vDSO missing ODP entries | |
17 | ||
18 | This patch fixes the vDSO symbol used directed in IFUNC resolver where | |
19 | they do not have an associated ODP entry leading to undefined behavior | |
20 | in some cases. It adds an artificial OPD static entry to such cases | |
21 | and set its TOC to non 0 to avoid triggering lazy resolutions. | |
22 | ||
23 | commit d98720e07f67fbeec00f9e1347840404240d3c48 | |
24 | Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com> | |
25 | Date: Mon Jan 20 12:29:51 2014 -0600 | |
26 | ||
27 | PowerPC: Fix gettimeofday ifunc selection | |
28 | ||
29 | The IFUNC selector for gettimeofday runs before _libc_vdso_platform_setup where | |
30 | __vdso_gettimeofday is set. The selector then sets __gettimeofday (the internal | |
31 | version used within GLIBC) to use the system call version instead of the vDSO one. | |
32 | This patch changes the check if vDSO is available to get its value directly | |
33 | instead of rely on __vdso_gettimeofday. | |
34 | ||
35 | This patch changes it by getting the vDSO value directly. | |
36 | ||
37 | It fixes BZ#16431. | |
38 | ||
39 | diff -pruN a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h | |
40 | --- a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h 2014-05-20 14:46:51.026871920 +0530 | |
41 | +++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h 2014-05-20 14:44:39.294877321 +0530 | |
42 | @@ -33,6 +33,36 @@ extern void *__vdso_get_tbfreq; | |
43 | ||
44 | extern void *__vdso_getcpu; | |
45 | ||
46 | +#if defined(__PPC64__) || defined(__powerpc64__) | |
47 | +/* The correct solution is for _dl_vdso_vsym to return the address of the OPD | |
48 | + for the kernel VDSO function. That address would then be stored in the | |
49 | + __vdso_* variables and returned as the result of the IFUNC resolver function. | |
50 | + Yet, the kernel does not contain any OPD entries for the VDSO functions | |
51 | + (incomplete implementation). However, PLT relocations for IFUNCs still expect | |
52 | + the address of an OPD to be returned from the IFUNC resolver function (since | |
53 | + PLT entries on PPC64 are just copies of OPDs). The solution for now is to | |
54 | + create an artificial static OPD for each VDSO function returned by a resolver | |
55 | + function. The TOC value is set to a non-zero value to avoid triggering lazy | |
56 | + symbol resolution via .glink0/.plt0 for a zero TOC (requires thread-safe PLT | |
57 | + sequences) when the dynamic linker isn't prepared for it e.g. RTLD_NOW. None | |
58 | + of the kernel VDSO routines use the TOC or AUX values so any non-zero value | |
59 | + will work. Note that function pointer comparisons will not use this artificial | |
60 | + static OPD since those are resolved via ADDR64 relocations and will point at | |
61 | + the non-IFUNC default OPD for the symbol. Lastly, because the IFUNC relocations | |
62 | + are processed immediately at startup the resolver functions and this code need | |
63 | + not be thread-safe, but if the caller writes to a PLT slot it must do so in a | |
64 | + thread-safe manner with all the required barriers. */ | |
65 | +#define VDSO_IFUNC_RET(value) \ | |
66 | + ({ \ | |
67 | + static Elf64_FuncDesc vdso_opd = { .fd_toc = ~0x0 }; \ | |
68 | + vdso_opd.fd_func = (Elf64_Addr)value; \ | |
69 | + &vdso_opd; \ | |
70 | + }) | |
71 | + | |
72 | +#else | |
73 | +#define VDSO_IFUNC_RET(value) ((void *) (value)) | |
74 | +#endif | |
75 | + | |
76 | #endif | |
77 | ||
78 | #endif /* _LIBC_VDSO_H */ | |
79 | diff -pruN a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c | |
80 | --- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c 2010-05-04 16:57:23.000000000 +0530 | |
81 | +++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c 2014-05-20 14:44:39.298877321 +0530 | |
82 | @@ -16,27 +16,51 @@ | |
83 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
84 | 02111-1307 USA. */ | |
85 | ||
86 | -#include <sysdep.h> | |
87 | -#include <bp-checks.h> | |
88 | -#include <stddef.h> | |
89 | #include <sys/time.h> | |
90 | -#include <time.h> | |
91 | -#include <hp-timing.h> | |
92 | ||
93 | -#undef __gettimeofday | |
94 | -#include <bits/libc-vdso.h> | |
95 | +#ifdef SHARED | |
96 | ||
97 | -/* Get the current time of day and timezone information, | |
98 | - putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled. | |
99 | - Returns 0 on success, -1 on errors. */ | |
100 | - | |
101 | -int | |
102 | -__gettimeofday (tv, tz) | |
103 | - struct timeval *tv; | |
104 | - struct timezone *tz; | |
105 | +# include <dl-vdso.h> | |
106 | +# include <bits/libc-vdso.h> | |
107 | +# include <dl-machine.h> | |
108 | + | |
109 | +void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday"); | |
110 | + | |
111 | +static int | |
112 | +__gettimeofday_syscall (struct timeval *tv, struct timezone *tz) | |
113 | +{ | |
114 | + return INLINE_SYSCALL (gettimeofday, 2, tv, tz); | |
115 | +} | |
116 | + | |
117 | +void * | |
118 | +gettimeofday_ifunc (void) | |
119 | +{ | |
120 | + PREPARE_VERSION (linux2615, "LINUX_2.6.15", 123718565); | |
121 | + | |
122 | + /* If the vDSO is not available we fall back syscall. */ | |
123 | + void *vdso_gettimeofday = _dl_vdso_vsym ("__kernel_gettimeofday", &linux2615); | |
124 | + return (vdso_gettimeofday ? VDSO_IFUNC_RET (vdso_gettimeofday) | |
125 | + : (void*)__gettimeofday_syscall); | |
126 | +} | |
127 | +asm (".type __gettimeofday, %gnu_indirect_function"); | |
128 | + | |
129 | +/* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't | |
130 | + let us do it in C because it doesn't know we're defining __gettimeofday | |
131 | + here in this file. */ | |
132 | +asm (".globl __GI___gettimeofday\n" | |
133 | + "__GI___gettimeofday = __gettimeofday"); | |
134 | + | |
135 | +#else | |
136 | + | |
137 | +# include <sysdep.h> | |
138 | +# include <errno.h> | |
139 | + | |
140 | +int | |
141 | +__gettimeofday (struct timeval *tv, struct timezone *tz) | |
142 | { | |
143 | - return INLINE_VSYSCALL (gettimeofday, 2, CHECK_1 (tv), CHECK_1 (tz)); | |
144 | + return INLINE_SYSCALL (gettimeofday, 2, tv, tz); | |
145 | } | |
146 | ||
147 | +#endif | |
148 | INTDEF (__gettimeofday) | |
149 | weak_alias (__gettimeofday, gettimeofday) |