From patchwork Thu Sep 5 20:56:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 34401 Received: (qmail 117476 invoked by alias); 5 Sep 2019 20:56:39 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 117411 invoked by uid 89); 5 Sep 2019 20:56:39 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS, T_FILL_THIS_FORM_SHORT autolearn=ham version=3.3.1 spammy= X-HELO: mail-qt1-f194.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=3IOo+BI80Erhf+jc53R3uhJBUadI14E1Pzz1NLp8/W8=; b=Z1IDfjiHgKdMsZWSO0xNw0e2IU5b07VghOXdXCBQLNgUMjIwIEsUIDRaPAbzvshat9 OeDrQaRA/9hKb+kN/5ZW1uIV01FefVzzt384HXAlSL/yN6QGNIOLR7h+BoZjSJrYWlKg rzWItHIRbWaW+P3bycj29++m2uvotAsnCXcmA9BUGkjgUW4ShgjF9Y854mC+S0MDd0kk gLscUuFW+oAVu7FRbjxGCtqPrfn2ia13GI9uf6Ao37LwmzDXgxEY9t6l3Kbf3IvpAGt5 PlZIj+6q0plRH2mpNuR+WvMNg4Whl+XaLQiUrasdGrwRoid8yUjEnZxnj6CRWMVGWVgW ErJw== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 7/8] linux: Consolidate time implementation Date: Thu, 5 Sep 2019 17:56:19 -0300 Message-Id: <20190905205620.4646-7-adhemerval.zanella@linaro.org> In-Reply-To: <20190905205620.4646-1-adhemerval.zanella@linaro.org> References: <20190905205620.4646-1-adhemerval.zanella@linaro.org> Changes from previous version: - Improve comment about hidden_def_redir. - Update due powerpc64 fixes. --- 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 | 11 ++++ 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 | 57 +++++++++++++--- sysdeps/unix/sysv/linux/x86/time.c | 60 ----------------- sysdeps/unix/sysv/linux/x86_64/sysdep.h | 2 + 8 files changed, 65 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 diff --git a/include/libc-symbols.h b/include/libc-symbols.h index b68ec4b7f5..a585a04e63 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -491,6 +491,12 @@ for linking") int foo = INITIAL_FOO_VALUE; libc_hidden_data_weak (foo) + If the internal foo should use a different internal symbol (for instance + if the symbol is exported as an IFUNC, but internal calls should use a + default version) then you may use: + + libc_hidden_def_redir (foo_internal, foo) + If foo is normally just an alias (strong or weak) to some other function, you should use the normal strong_alias first, then add libc_hidden_def or libc_hidden_weak: @@ -548,6 +554,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 +582,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 +613,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 +626,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 +643,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) diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h index e793fdc936..4f79f25989 100644 --- a/sysdeps/unix/sysv/linux/i386/sysdep.h +++ b/sysdeps/unix/sysv/linux/i386/sysdep.h @@ -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 diff --git a/sysdeps/unix/sysv/linux/i386/time.c b/sysdeps/unix/sysv/linux/i386/time.c deleted file mode 100644 index 440e3e6ab4..0000000000 --- a/sysdeps/unix/sysv/linux/i386/time.c +++ /dev/null @@ -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 - . */ - -#ifdef SHARED -# define time __redirect_time -#endif - -#include - -#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 diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/sysdep.h index 357d1b5243..084b6525ca 100644 --- a/sysdeps/unix/sysv/linux/powerpc/sysdep.h +++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.h @@ -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" diff --git a/sysdeps/unix/sysv/linux/powerpc/time.c b/sysdeps/unix/sysv/linux/powerpc/time.c deleted file mode 100644 index f0537a2307..0000000000 --- a/sysdeps/unix/sysv/linux/powerpc/time.c +++ /dev/null @@ -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 - . */ - -#ifdef SHARED -# ifndef __powerpc64__ -# define time __redirect_time -# else -# define __redirect_time time -# endif - -# include -# include -# include -# include -# include - -# 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_IFUNC_RET (vdso_time) - : (void *) time_syscall); -libc_hidden_def (time) - -#else - -#include - -#endif /* !SHARED */ diff --git a/sysdeps/unix/sysv/linux/time.c b/sysdeps/unix/sysv/linux/time.c index 1978f6d817..9176fe6ed7 100644 --- a/sysdeps/unix/sysv/linux/time.c +++ b/sysdeps/unix/sysv/linux/time.c @@ -15,27 +15,68 @@ License along with the GNU C Library; if not, see . */ -#include +/* 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 +#undef time +#include #include +#ifdef HAVE_TIME_VSYSCALL +# define HAVE_VSYSCALL +#endif +#include +#include -#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 +# undef INIT_ARCH +# define INIT_ARCH() \ + void *vdso_time = get_vdso_symbol (HAVE_TIME_VSYSCALL); + +libc_ifunc_redirected (__redirect_time, time, + vdso_time + ? VDSO_IFUNC_RET (vdso_time) + : (void *) time_syscall); +libc_hidden_def_redir (time_syscall, time) +# else +strong_alias (time_syscall, time) +# endif /* SHARED */ #else -# include +time_t +time (time_t *t) +{ + return time_syscall (t); +} +libc_hidden_def_redir (time, time) #endif diff --git a/sysdeps/unix/sysv/linux/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c deleted file mode 100644 index 60e6d1b7c0..0000000000 --- a/sysdeps/unix/sysv/linux/x86/time.c +++ /dev/null @@ -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 - . */ - -#include - -#ifdef SHARED - -#include -#include -#include - -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 - -time_t -time (time_t *t) -{ - INTERNAL_SYSCALL_DECL (err); - return INTERNAL_SYSCALL (time, err, 1, t); -} - -#endif diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h index 4541c0d492..c64fbd1e26 100644 --- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h +++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h @@ -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