[11/12] linux: Consolidate time implementation
Commit Message
The time syscall has currently 3 possible implementations:
1. Wire-up __NR_time with a vDSO implementation (currently only x86 and
powerpc).
2. Wire-up __NR_time (hppa, i686, m68k, microblaze, mips, powerpc,
powerpc64, s390, sh4, sparcv9, x86_64).
3. Using internal gettimeofday (aarch64, alpha, arm, mips64, mips64-n32,
nios2, s390x, sparc64).
This patch consolidates all implementation on Linux generic
sysdeps/unix/sysv/linux/time.c. To simplify the code, some changes are
made:
* The wire-up with vDSO implementation route external calls directly
to vDSO through IFUNC. To enable it the architecture need to
explicit define USE_TIME_VSYSCALL_IFUNC.
* Also, powerpc and x86 tries to route internal time usages to
IFUNC mechanism, which is problematic since powerpc32 and i686 does
not really support it. Instead, all internal calls are routed to
a default internal symbol which in turn calls INTERNAL_VSYSCALL.
* Static linking also uses the fallback mechanism which calls
INTERNAL_VSYSCALL, so vDSO is used for this case as well.
The generic implementation issues a syscall as default, calls the
vDSO if the architecture defines HAVE_TIME_VSYSCALL, and route the external
calls to iFUNC if the architecture also defines USE_TIME_VSYSCALL_IFUNC.
Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc-linux-gnu,
powerpc64-linux-gnu, powerpc64le-linux-gnu, and aarch64-linux-gnu.
* include/libc-symbols.h (hidden_def_redir): New macro.
* sysdeps/unix/sysv/linux/i386/sysdep.h (HAVE_TIME_VSYSCALL,
USE_TIME_VSYSCALL_IFUNC): Define.
* sysdeps/unix/sysv/linux/x86_64/sysdep.h (HAVE_TIME_VSYSCALL,
USE_TIME_VSYSCALL_IFUNC): Likewise.
* sysdeps/unix/sysv/linux/powerpc/sysdep.h (USE_TIME_VSYSCALL_IFUNC):
Likewise.
* sysdeps/unix/sysv/linux/i386/time.c: Remove file.
* sysdeps/unix/sysv/linux/x86/time.c: Likewise.
* sysdeps/unix/sysv/linux/powerpc/time.c: Likewise.
* sysdeps/unix/sysv/linux/time.c (time): Handle all possible Linux
implementations (wire-up syscall, vDSO implementation, iFUNC).
(time_syscall): New function.
---
include/libc-symbols.h | 5 ++
sysdeps/unix/sysv/linux/i386/sysdep.h | 2 +
sysdeps/unix/sysv/linux/i386/time.c | 34 ----------
sysdeps/unix/sysv/linux/powerpc/sysdep.h | 1 +
sysdeps/unix/sysv/linux/powerpc/time.c | 83 ------------------------
sysdeps/unix/sysv/linux/time.c | 53 ++++++++++++---
sysdeps/unix/sysv/linux/x86/time.c | 60 -----------------
sysdeps/unix/sysv/linux/x86_64/sysdep.h | 2 +
8 files changed, 55 insertions(+), 185 deletions(-)
delete mode 100644 sysdeps/unix/sysv/linux/i386/time.c
delete mode 100644 sysdeps/unix/sysv/linux/powerpc/time.c
delete mode 100644 sysdeps/unix/sysv/linux/x86/time.c
Comments
* Adhemerval Zanella:
> * include/libc-symbols.h (hidden_def_redir): New macro.
This macro should have documentation in the large common block above it.
Its purpose isn't obvious to me.
> +#if HAVE_IFUNC && defined USE_TIME_VSYSCALL_IFUNC
> +/* Route externals calls direct to vDSO and static and internal calls to
> + fallback implementation (which also might call the vDSO). */
> +# ifdef SHARED
> +# define INIT_ARCH()
> +libc_ifunc_redirected (__redirect_time, time,
> + get_vdso_symbol (HAVE_TIME_VSYSCALL)
> + ?: time_syscall);
> +libc_hidden_def_redir (time_syscall, time)
> +# else
> +strong_alias (time_syscall, time)
> +# endif /* SHARED */
Does this really work on x86-64? I don't think it's possible to call
IFUNCs through hidden aliases.
Thanks,
Florian
On 25/06/2019 15:24, Florian Weimer wrote:
> * Adhemerval Zanella:
>
>> * include/libc-symbols.h (hidden_def_redir): New macro.
>
> This macro should have documentation in the large common block above it.
> Its purpose isn't obvious to me.
>
>> +#if HAVE_IFUNC && defined USE_TIME_VSYSCALL_IFUNC
>> +/* Route externals calls direct to vDSO and static and internal calls to
>> + fallback implementation (which also might call the vDSO). */
>> +# ifdef SHARED
>> +# define INIT_ARCH()
>> +libc_ifunc_redirected (__redirect_time, time,
>> + get_vdso_symbol (HAVE_TIME_VSYSCALL)
>> + ?: time_syscall);
>> +libc_hidden_def_redir (time_syscall, time)
>> +# else
>> +strong_alias (time_syscall, time)
>> +# endif /* SHARED */
>
> Does this really work on x86-64? I don't think it's possible to call
> IFUNCs through hidden aliases.
The idea is to not call an IFUNC in the static case nor on internal
hidden case for shared case. Only external calls are routes through
iFUNC.
* Adhemerval Zanella:
> On 25/06/2019 15:24, Florian Weimer wrote:
>> * Adhemerval Zanella:
>>
>>> * include/libc-symbols.h (hidden_def_redir): New macro.
>>
>> This macro should have documentation in the large common block above it.
>> Its purpose isn't obvious to me.
>>
>>> +#if HAVE_IFUNC && defined USE_TIME_VSYSCALL_IFUNC
>>> +/* Route externals calls direct to vDSO and static and internal calls to
>>> + fallback implementation (which also might call the vDSO). */
>>> +# ifdef SHARED
>>> +# define INIT_ARCH()
>>> +libc_ifunc_redirected (__redirect_time, time,
>>> + get_vdso_symbol (HAVE_TIME_VSYSCALL)
>>> + ?: time_syscall);
>>> +libc_hidden_def_redir (time_syscall, time)
>>> +# else
>>> +strong_alias (time_syscall, time)
>>> +# endif /* SHARED */
>>
>> Does this really work on x86-64? I don't think it's possible to call
>> IFUNCs through hidden aliases.
>
> The idea is to not call an IFUNC in the static case nor on internal
> hidden case for shared case. Only external calls are routes through
> iFUNC.
I see. I will try to review the change with this in mind.
Thanks,
Florian
Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
> The time syscall has currently 3 possible implementations:
>
> 1. Wire-up __NR_time with a vDSO implementation (currently only x86 and
> powerpc).
> 2. Wire-up __NR_time (hppa, i686, m68k, microblaze, mips, powerpc,
> powerpc64, s390, sh4, sparcv9, x86_64).
> 3. Using internal gettimeofday (aarch64, alpha, arm, mips64, mips64-n32,
> nios2, s390x, sparc64).
>
> This patch consolidates all implementation on Linux generic
> sysdeps/unix/sysv/linux/time.c. To simplify the code, some changes are
> made:
>
> * The wire-up with vDSO implementation route external calls directly
> to vDSO through IFUNC. To enable it the architecture need to
> explicit define USE_TIME_VSYSCALL_IFUNC.
>
> * Also, powerpc and x86 tries to route internal time usages to
> IFUNC mechanism, which is problematic since powerpc32 and i686 does
> not really support it. Instead, all internal calls are routed to
> a default internal symbol which in turn calls INTERNAL_VSYSCALL.
>
> * Static linking also uses the fallback mechanism which calls
> INTERNAL_VSYSCALL, so vDSO is used for this case as well.
>
> The generic implementation issues a syscall as default, calls the
> vDSO if the architecture defines HAVE_TIME_VSYSCALL, and route the external
> calls to iFUNC if the architecture also defines USE_TIME_VSYSCALL_IFUNC.
>
> Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc-linux-gnu,
> powerpc64-linux-gnu, powerpc64le-linux-gnu, and aarch64-linux-gnu.
This patch is causing segmentation faults in powerpc64, e.g.
$ ./testrun.sh ./io/test-utime
Segmentation fault
> diff --git a/sysdeps/unix/sysv/linux/time.c b/sysdeps/unix/sysv/linux/time.c
> index 1978f6d817..93e036fe16 100644
> --- a/sysdeps/unix/sysv/linux/time.c
> +++ b/sysdeps/unix/sysv/linux/time.c
> ...
> +#if HAVE_IFUNC && defined USE_TIME_VSYSCALL_IFUNC
> +/* Route externals calls direct to vDSO and static and internal calls to
> + fallback implementation (which also might call the vDSO). */
> +# ifdef SHARED
> +# define INIT_ARCH()
> +libc_ifunc_redirected (__redirect_time, time,
> + get_vdso_symbol (HAVE_TIME_VSYSCALL)
> + ?: time_syscall);
Missing VDSO_IFUNC_RET ?
On 28/06/2019 19:45, Tulio Magno Quites Machado Filho wrote:
> Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
>
>> The time syscall has currently 3 possible implementations:
>>
>> 1. Wire-up __NR_time with a vDSO implementation (currently only x86 and
>> powerpc).
>> 2. Wire-up __NR_time (hppa, i686, m68k, microblaze, mips, powerpc,
>> powerpc64, s390, sh4, sparcv9, x86_64).
>> 3. Using internal gettimeofday (aarch64, alpha, arm, mips64, mips64-n32,
>> nios2, s390x, sparc64).
>>
>> This patch consolidates all implementation on Linux generic
>> sysdeps/unix/sysv/linux/time.c. To simplify the code, some changes are
>> made:
>>
>> * The wire-up with vDSO implementation route external calls directly
>> to vDSO through IFUNC. To enable it the architecture need to
>> explicit define USE_TIME_VSYSCALL_IFUNC.
>>
>> * Also, powerpc and x86 tries to route internal time usages to
>> IFUNC mechanism, which is problematic since powerpc32 and i686 does
>> not really support it. Instead, all internal calls are routed to
>> a default internal symbol which in turn calls INTERNAL_VSYSCALL.
>>
>> * Static linking also uses the fallback mechanism which calls
>> INTERNAL_VSYSCALL, so vDSO is used for this case as well.
>>
>> The generic implementation issues a syscall as default, calls the
>> vDSO if the architecture defines HAVE_TIME_VSYSCALL, and route the external
>> calls to iFUNC if the architecture also defines USE_TIME_VSYSCALL_IFUNC.
>>
>> Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc-linux-gnu,
>> powerpc64-linux-gnu, powerpc64le-linux-gnu, and aarch64-linux-gnu.
>
> This patch is causing segmentation faults in powerpc64, e.g.
> $ ./testrun.sh ./io/test-utime
> Segmentation fault
>
Indeed when I had to refactor the 'powerpc: Refactor vsyscall internal macros'
I forgot to update both the gettimeofday and time one, which required some
changes as well. I will send an updated version.
>> diff --git a/sysdeps/unix/sysv/linux/time.c b/sysdeps/unix/sysv/linux/time.c
>> index 1978f6d817..93e036fe16 100644
>> --- a/sysdeps/unix/sysv/linux/time.c
>> +++ b/sysdeps/unix/sysv/linux/time.c
>> ...
>> +#if HAVE_IFUNC && defined USE_TIME_VSYSCALL_IFUNC
>> +/* Route externals calls direct to vDSO and static and internal calls to
>> + fallback implementation (which also might call the vDSO). */
>> +# ifdef SHARED
>> +# define INIT_ARCH()
>> +libc_ifunc_redirected (__redirect_time, time,
>> + get_vdso_symbol (HAVE_TIME_VSYSCALL)
>> + ?: time_syscall);
>
> Missing VDSO_IFUNC_RET ?
>
@@ -548,6 +548,7 @@ for linking")
# define hidden_ver(local, name) __hidden_ver1(local, __GI_##name, name);
# define hidden_data_ver(local, name) hidden_ver(local, name)
# define hidden_def(name) __hidden_ver1(__GI_##name, name, name);
+# define hidden_def_redir(redir, name) __hidden_ver1(redir, __GI_##name, redir);
# define hidden_data_def(name) hidden_def(name)
# define hidden_tls_def(name) \
__hidden_ver2 (__thread, __GI_##name, name, name);
@@ -575,6 +576,7 @@ for linking")
hidden_proto doesn't make sense for assembly but the equivalent
is to call via the HIDDEN_JUMPTARGET macro instead of JUMPTARGET. */
# define hidden_def(name) strong_alias (name, __GI_##name)
+# define hidden_def_redir(redir, name) strong_alias(redir, __GI_##name);
# define hidden_weak(name) hidden_def (name)
# define hidden_ver(local, name) strong_alias (local, __GI_##name)
# define hidden_data_def(name) strong_data_alias (name, __GI_##name)
@@ -605,6 +607,7 @@ for linking")
# endif /* Not __ASSEMBLER__ */
# define hidden_weak(name)
# define hidden_def(name)
+# define hidden_def_redir(redir, name)
# define hidden_ver(local, name)
# define hidden_data_weak(name)
# define hidden_data_def(name)
@@ -617,6 +620,7 @@ for linking")
# define libc_hidden_proto(name, attrs...) hidden_proto (name, ##attrs)
# define libc_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs)
# define libc_hidden_def(name) hidden_def (name)
+# define libc_hidden_def_redir(redir, name) hidden_def_redir (redir, name)
# define libc_hidden_weak(name) hidden_weak (name)
# ifdef LINK_OBSOLETE_RPC
/* libc_hidden_nolink_sunrpc should only get used in sunrpc code. */
@@ -633,6 +637,7 @@ for linking")
# define libc_hidden_proto(name, attrs...)
# define libc_hidden_tls_proto(name, attrs...)
# define libc_hidden_def(name)
+# define libc_hidden_def_redir(redir, name)
# define libc_hidden_weak(name)
# define libc_hidden_ver(local, name)
# define libc_hidden_data_def(name)
@@ -315,6 +315,8 @@ struct libc_do_syscall_args
/* List of system calls which are supported as vsyscalls. */
# define HAVE_CLOCK_GETTIME_VSYSCALL "__vdso_clock_gettime"
# define HAVE_GETTIMEOFDAY_VSYSCALL "__vdso_gettimeofday"
+# define HAVE_TIME_VSYSCALL "__vdso_time"
+# define USE_TIME_VSYSCALL_IFUNC 1
/* Define a macro which expands inline into the wrapper code for a system
call. This use is for internal calls that do not need to handle errors
deleted file mode 100644
@@ -1,34 +0,0 @@
-/* time -- Get number of seconds since Epoch. Linux/i386 version.
- Copyright (C) 2015-2019 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/>. */
-
-#ifdef SHARED
-# define time __redirect_time
-#endif
-
-#include <time.h>
-
-#ifdef SHARED
-# undef time
-# define time_type __redirect_time
-
-# undef libc_hidden_def
-# define libc_hidden_def(name) \
- __hidden_ver1 (__time_syscall, __GI_time, __time_syscall);
-#endif
-
-#include <sysdeps/unix/sysv/linux/x86/time.c>
@@ -24,6 +24,7 @@
#define HAVE_CLOCK_GETTIME_VSYSCALL "__kernel_clock_gettime"
#define HAVE_GETCPU_VSYSCALL "__kernel_getcpu"
#define HAVE_TIME_VSYSCALL "__kernel_time"
+#define USE_TIME_VSYSCALL_IFUNC 1
#define HAVE_GETTIMEOFDAY_VSYSCALL "__kernel_gettimeofday"
#define HAVE_GET_TBFREQ "__kernel_get_tbfreq"
deleted file mode 100644
@@ -1,83 +0,0 @@
-/* time system call for Linux/PowerPC.
- Copyright (C) 2013-2019 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/>. */
-
-#ifdef SHARED
-# ifndef __powerpc64__
-# define time __redirect_time
-# else
-# define __redirect_time time
-# endif
-
-# include <time.h>
-# include <sysdep.h>
-# include <dl-vdso.h>
-# include <libc-vdso.h>
-# include <dl-machine.h>
-
-# ifndef __powerpc64__
-# undef time
-
-time_t
-__time_vsyscall (time_t *t)
-{
- return INLINE_VSYSCALL (time, 1, t);
-}
-
-/* __GI_time is defined as hidden and for ppc32 it enables the
- compiler make a local call (symbol@local) for internal GLIBC usage. It
- means the PLT won't be used and the ifunc resolver will be called directly.
- For ppc64 a call to a function in another translation unit might use a
- different toc pointer thus disallowing direct branchess and making internal
- ifuncs calls safe. */
-# undef libc_hidden_def
-# define libc_hidden_def(name) \
- __hidden_ver1 (__time_vsyscall, __GI_time, __time_vsyscall);
-
-# endif /* !__powerpc64__ */
-
-static time_t
-time_syscall (time_t *t)
-{
- struct timeval tv;
- time_t result;
-
- if (INLINE_VSYSCALL (gettimeofday, 2, &tv, NULL) < 0)
- result = (time_t) -1;
- else
- result = (time_t) tv.tv_sec;
-
- if (t != NULL)
- *t = result;
- return result;
-}
-
-# define INIT_ARCH() \
- void *vdso_time = get_vdso_symbol (HAVE_TIME_VSYSCALL);
-
-/* If the vDSO is not available we fall back to the syscall. */
-libc_ifunc_hidden (__redirect_time, time,
- vdso_time
- ? vdso_time
- : (void *) time_syscall);
-libc_hidden_def (time)
-
-#else
-
-#include <sysdeps/posix/time.c>
-
-#endif /* !SHARED */
@@ -15,27 +15,64 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <stddef.h>
+/* Currently we have 3 possible time implementations, which is also selected
+ in the order:
+
+ 1. Wire-up __NR_time with a vDSO implementation (currently only x86 and
+ powerpc).
+ 2. Only wire-up __NR_time (usually old kABIs).
+ 3. Using internal gettimeofday (which may call a vDSO as well). */
+
+#define time __redirect_time
#include <time.h>
+#undef time
+#include <sys/time.h>
#include <sysdep.h>
+#ifdef HAVE_TIME_VSYSCALL
+# define HAVE_VSYSCALL
+#endif
+#include <sysdep-vdso.h>
+#include <libc-vdso.h>
-#ifdef __NR_time
-
-time_t
-time (time_t *t)
+static time_t
+time_syscall (time_t *t)
{
+ time_t res;
+#ifdef __NR_time
INTERNAL_SYSCALL_DECL (err);
- time_t res = INTERNAL_SYSCALL (time, err, 1, NULL);
+ res = INTERNAL_VSYSCALL (time, err, 1, NULL);
/* There cannot be any error. */
+#else
+ struct timeval tv;
+ /* gettimeofday does not fail with valid 'tv' and null timezone. */
+ __gettimeofday (&tv, NULL);
+ res = tv.tv_sec;
+#endif
if (t != NULL)
*t = res;
return res;
}
-libc_hidden_def (time)
+#if HAVE_IFUNC && defined USE_TIME_VSYSCALL_IFUNC
+/* Route externals calls direct to vDSO and static and internal calls to
+ fallback implementation (which also might call the vDSO). */
+# ifdef SHARED
+# define INIT_ARCH()
+libc_ifunc_redirected (__redirect_time, time,
+ get_vdso_symbol (HAVE_TIME_VSYSCALL)
+ ?: time_syscall);
+libc_hidden_def_redir (time_syscall, time)
+# else
+strong_alias (time_syscall, time)
+# endif /* SHARED */
#else
-# include <sysdeps/posix/time.c>
+time_t
+time (time_t *t)
+{
+ return time_syscall (t);
+}
+libc_hidden_def_redir (time, time)
#endif
deleted file mode 100644
@@ -1,60 +0,0 @@
-/* time -- Get number of seconds since Epoch. Linux/x86 version.
- Copyright (C) 2015-2019 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/>. */
-
-#include <time.h>
-
-#ifdef SHARED
-
-#include <dl-vdso.h>
-#include <errno.h>
-#include <sysdep-vdso.h>
-
-static time_t
-__time_syscall (time_t *t)
-{
- INTERNAL_SYSCALL_DECL (err);
- return INTERNAL_SYSCALL (time, err, 1, t);
-}
-
-# ifndef time_type
-/* The i386 time.c includes this file with a defined time_type macro.
- For x86_64 we have to define it to time as the internal symbol is the
- ifunc'ed one. */
-# define time_type time
-# endif
-
-#undef INIT_ARCH
-#define INIT_ARCH()
-
-/* If the vDSO is not available we fall back on the syscall. */
-libc_ifunc_hidden (time_type, time,
- (get_vdso_symbol ("__vdso_time") ?: __time_syscall))
-libc_hidden_def (time)
-
-#else
-
-# include <sysdep.h>
-
-time_t
-time (time_t *t)
-{
- INTERNAL_SYSCALL_DECL (err);
- return INTERNAL_SYSCALL (time, err, 1, t);
-}
-
-#endif
@@ -376,6 +376,8 @@
/* List of system calls which are supported as vsyscalls. */
# define HAVE_CLOCK_GETTIME_VSYSCALL "__vdso_clock_gettime"
# define HAVE_GETTIMEOFDAY_VSYSCALL "__vdso_gettimeofday"
+# define HAVE_TIME_VSYSCALL "__vdso_time"
+# define USE_TIME_VSYSCALL_IFUNC 1
# define HAVE_GETCPU_VSYSCALL "__vdso_getcpu"
# define SINGLE_THREAD_BY_GLOBAL 1