From patchwork Wed Nov 19 07:52:54 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefani Seibold X-Patchwork-Id: 3801 Received: (qmail 24321 invoked by alias); 19 Nov 2014 07:53:06 -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 24309 invoked by uid 89); 19 Nov 2014 07:53:05 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 X-HELO: www84.your-server.de Message-ID: <1416383574.2214.2.camel@seibold.net> Subject: [PATCH v2] Add x86 32 bit vDSO time function support From: Stefani Seibold To: "GNU C. Library" Cc: Stefani Seibold , Adhemerval Zanella Date: Wed, 19 Nov 2014 08:52:54 +0100 Mime-Version: 1.0 Linux 3.15 adds support for clock_gettime, gettimeofday, and time vDSO (commit id 37c975545ec63320789962bf307f000f08fabd48). This patch adds GLIBC supports to use such symbol when they are available. Along with x86 vDSO support, this patch cleanup x86_64 code by moving all common code to x86 common folder. Only init-first.c is different between implementations, since they differ substantially (x86_64 has getcpu symbol where x86 does not). This is a respin of https://sourceware.org/ml/libc-alpha/2014-04/msg00384.html Checked on x86 and x86_64 with a 3.16-rc2 kernel. --- 2014-11-19 No changes since last version, resend for applying to the glibc master brach 2014-06-27 Adhemerval Zanella Stefani Seibold * sysdeps/unix/sysv/linux/i386/Makefile [sysdep_routines]: Add dl-vdso object. * sysdeps/unix/sysv/linux/i386/gettimeofday.c: New file: add support to vDSO. * sysdeps/unix/sysv/linux/i386/init-first.c: New file: likewise. * sysdeps/unix/sysv/linux/i386/time.c: New file: likewise. * sysdeps/unix/sysv/linux/x86_64/bits/libc-vdso.h: Moved to ... * sysdeps/unix/sysv/linux/x86/bits/libc-vdso.h: ... here. * sysdeps/unix/sysv/linux/x86_64/clock_gettime.c: Move to ... * sysdeps/unix/sysv/linux/x86/clock_gettime.c: ... here. * sysdeps/unix/sysv/linux/x86_64/gettimeofday.c: Move to ... * sysdeps/unix/sysv/linux/x86/gettimeofday.c: ... here. Also added fallback configurable symbol when vDSO is not available. * sysdeps/unix/sysv/linux/x86_64/time.c: Move to ... * sysdeps/unix/sysv/linux/x86/time.c: ... here. Also refactored to be able to redefine fallback symbol when vDSO is not available. * sysdeps/unix/sysv/linux/x86_64/timespec_get.c: Move to ... * sysdeps/unix/sysv/linux/x86/timespec_get.c: ... here. --- diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile index acc3021..3222f46 100644 --- a/sysdeps/unix/sysv/linux/i386/Makefile +++ b/sysdeps/unix/sysv/linux/i386/Makefile @@ -21,3 +21,7 @@ endif ifeq ($(subdir),stdlib) gen-as-const-headers += ucontext_i.sym endif + +ifeq ($(subdir),elf) +sysdep_routines += dl-vdso +endif diff --git a/sysdeps/unix/sysv/linux/i386/gettimeofday.c b/sysdeps/unix/sysv/linux/i386/gettimeofday.c new file mode 100644 index 0000000..c45438c --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/gettimeofday.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2014 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 + +/* If the vDSO is not available we fall back on the syscall. */ +static int +__gettimeofday_syscall (struct timeval *tv, struct timezone *tz) +{ + return INLINE_SYSCALL (gettimeofday, 2, tv, tz); +} +# define GETTIMEOFAY_FALLBACK __gettimeofday_syscall +#endif + +#include diff --git a/sysdeps/unix/sysv/linux/i386/init-first.c b/sysdeps/unix/sysv/linux/i386/init-first.c new file mode 100644 index 0000000..10b0a97 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/init-first.c @@ -0,0 +1,53 @@ +/* Initialization code run first thing by the ELF startup code. Linux/i386. + Copyright (C) 2014 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 +# include +# include +# include +# include + +long int (*__vdso_clock_gettime) (clockid_t, struct timespec *) + __attribute__ ((nocommon)); +strong_alias (__vdso_clock_gettime, __GI___vdso_clock_gettime attribute_hidden) + + +static long int +clock_gettime_syscall (clockid_t id, struct timespec *tp) +{ + INTERNAL_SYSCALL_DECL (err); + return INTERNAL_SYSCALL (clock_gettime, err, 2, id, tp); +} + + +static inline void +_libc_vdso_platform_setup (void) +{ + PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); + + void *p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux26); + if (p == NULL) + p = clock_gettime_syscall; + PTR_MANGLE (p); + __GI___vdso_clock_gettime = p; +} + +# define VDSO_SETUP _libc_vdso_platform_setup +#endif + +#include diff --git a/sysdeps/unix/sysv/linux/i386/time.c b/sysdeps/unix/sysv/linux/i386/time.c new file mode 100644 index 0000000..616ec77 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/time.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2014 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 + +# include +# include + +/* If the vDSO is not available we fall back on the old vsyscall. */ +static time_t +__time_syscall (time_t *t) +{ + INTERNAL_SYSCALL_DECL (err); + return INTERNAL_SYSCALL (time, err, 1, t); +} +# define TIME_FALLBACK (void*)__time_syscall +#endif + +#include diff --git a/sysdeps/unix/sysv/linux/x86/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/x86/bits/libc-vdso.h new file mode 100644 index 0000000..f291924 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/bits/libc-vdso.h @@ -0,0 +1,31 @@ +/* Resolve function pointers to VDSO functions. + Copyright (C) 2005-2014 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 + . */ + +#ifndef _LIBC_VDSO_H +#define _LIBC_VDSO_H + +#include +#include + +#ifdef SHARED + +extern long int (*__vdso_clock_gettime) (clockid_t, struct timespec *); + +#endif + +#endif /* _LIBC_VDSO_H */ diff --git a/sysdeps/unix/sysv/linux/x86/clock_gettime.c b/sysdeps/unix/sysv/linux/x86/clock_gettime.c new file mode 100644 index 0000000..f712110 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/clock_gettime.c @@ -0,0 +1,20 @@ +#include "bits/libc-vdso.h" + +#ifdef SHARED +# define SYSCALL_GETTIME(id, tp) \ + ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \ + long int v_ret; \ + PTR_DEMANGLE (f); \ + v_ret = f (id, tp); \ + if (INTERNAL_SYSCALL_ERROR_P (v_ret, )) { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (v_ret, )); \ + v_ret = -1; \ + } \ + v_ret; }) +# define INTERNAL_GETTIME(id, tp) \ + ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \ + PTR_DEMANGLE (f); \ + f (id, tp); }) +#endif + +#include "../clock_gettime.c" diff --git a/sysdeps/unix/sysv/linux/x86/gettimeofday.c b/sysdeps/unix/sysv/linux/x86/gettimeofday.c new file mode 100644 index 0000000..71f48bb --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/gettimeofday.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2014 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 + +void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday"); + +void * +gettimeofday_ifunc (void) +{ + PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); + + /* If the vDSO is not available we fall back on the old vsyscall. */ + return (_dl_vdso_vsym ("__vdso_gettimeofday", &linux26) + ?: (void *) GETTIMEOFAY_FALLBACK); +} +asm (".type __gettimeofday, %gnu_indirect_function"); + +/* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't + let us do it in C because it doesn't know we're defining __gettimeofday + here in this file. */ +asm (".globl __GI___gettimeofday\n" + "__GI___gettimeofday = __gettimeofday"); + +#else + +# include +# include + +int +__gettimeofday (struct timeval *tv, struct timezone *tz) +{ + return INLINE_SYSCALL (gettimeofday, 2, tv, tz); +} +libc_hidden_def (__gettimeofday) + +#endif +weak_alias (__gettimeofday, gettimeofday) +libc_hidden_weak (gettimeofday) diff --git a/sysdeps/unix/sysv/linux/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c new file mode 100644 index 0000000..183754b --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/time.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2014 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 + +void *time_ifunc (void) __asm__ ("time"); + +void * +time_ifunc (void) +{ + PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); + + return _dl_vdso_vsym ("__vdso_time", &linux26) ?: TIME_FALLBACK; +} +asm (".type time, %gnu_indirect_function"); + +/* This is doing "libc_hidden_def (time)" but the compiler won't let us do + it in C because it doesn't know we're defining __gettimeofday here in + this file. */ +asm (".globl __GI_time\n" + "__GI_time = 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/timespec_get.c b/sysdeps/unix/sysv/linux/x86/timespec_get.c new file mode 100644 index 0000000..cb26068 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/timespec_get.c @@ -0,0 +1,10 @@ +#include "bits/libc-vdso.h" + +#ifdef SHARED +# define INTERNAL_GETTIME(id, tp) \ + ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \ + PTR_DEMANGLE (f); \ + f (id, tp); }) +#endif + +#include "../timespec_get.c" diff --git a/sysdeps/unix/sysv/linux/x86_64/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/x86_64/bits/libc-vdso.h deleted file mode 100644 index f291924..0000000 --- a/sysdeps/unix/sysv/linux/x86_64/bits/libc-vdso.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Resolve function pointers to VDSO functions. - Copyright (C) 2005-2014 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 - . */ - -#ifndef _LIBC_VDSO_H -#define _LIBC_VDSO_H - -#include -#include - -#ifdef SHARED - -extern long int (*__vdso_clock_gettime) (clockid_t, struct timespec *); - -#endif - -#endif /* _LIBC_VDSO_H */ diff --git a/sysdeps/unix/sysv/linux/x86_64/clock_gettime.c b/sysdeps/unix/sysv/linux/x86_64/clock_gettime.c deleted file mode 100644 index f712110..0000000 --- a/sysdeps/unix/sysv/linux/x86_64/clock_gettime.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "bits/libc-vdso.h" - -#ifdef SHARED -# define SYSCALL_GETTIME(id, tp) \ - ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \ - long int v_ret; \ - PTR_DEMANGLE (f); \ - v_ret = f (id, tp); \ - if (INTERNAL_SYSCALL_ERROR_P (v_ret, )) { \ - __set_errno (INTERNAL_SYSCALL_ERRNO (v_ret, )); \ - v_ret = -1; \ - } \ - v_ret; }) -# define INTERNAL_GETTIME(id, tp) \ - ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \ - PTR_DEMANGLE (f); \ - f (id, tp); }) -#endif - -#include "../clock_gettime.c" diff --git a/sysdeps/unix/sysv/linux/x86_64/gettimeofday.c b/sysdeps/unix/sysv/linux/x86_64/gettimeofday.c index 440ca7f..b0fa0e4 100644 --- a/sysdeps/unix/sysv/linux/x86_64/gettimeofday.c +++ b/sysdeps/unix/sysv/linux/x86_64/gettimeofday.c @@ -18,42 +18,9 @@ #include #ifdef SHARED - -# include - +/* If the vDSO is not available we fall back on the old vsyscall. */ # define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000ul - -void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday"); - -void * -gettimeofday_ifunc (void) -{ - PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); - - /* If the vDSO is not available we fall back on the old vsyscall. */ - return (_dl_vdso_vsym ("__vdso_gettimeofday", &linux26) - ?: (void *) VSYSCALL_ADDR_vgettimeofday); -} -asm (".type __gettimeofday, %gnu_indirect_function"); - -/* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't - let us do it in C because it doesn't know we're defining __gettimeofday - here in this file. */ -asm (".globl __GI___gettimeofday\n" - "__GI___gettimeofday = __gettimeofday"); - -#else - -# include -# include - -int -__gettimeofday (struct timeval *tv, struct timezone *tz) -{ - return INLINE_SYSCALL (gettimeofday, 2, tv, tz); -} -libc_hidden_def (__gettimeofday) - +# define GETTIMEOFAY_FALLBACK VSYSCALL_ADDR_vgettimeofday #endif -weak_alias (__gettimeofday, gettimeofday) -libc_hidden_weak (gettimeofday) + +#include diff --git a/sysdeps/unix/sysv/linux/x86_64/time.c b/sysdeps/unix/sysv/linux/x86_64/time.c index 79f1fab..ec1393b 100644 --- a/sysdeps/unix/sysv/linux/x86_64/time.c +++ b/sysdeps/unix/sysv/linux/x86_64/time.c @@ -16,45 +16,9 @@ . */ #ifdef SHARED -/* Redefine time so that the compiler won't complain about the type - mismatch with the IFUNC selector in strong_alias, below. */ -#undef time -#define time __redirect_time -#include - -#include - +/* If the vDSO is not available we fall back on the old vsyscall. */ #define VSYSCALL_ADDR_vtime 0xffffffffff600400 - -/* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle - ifunc symbol properly. */ -extern __typeof (__redirect_time) __libc_time; -void *time_ifunc (void) __asm__ ("__libc_time"); - -void * -time_ifunc (void) -{ - PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); - - /* If the vDSO is not available we fall back on the old vsyscall. */ - return _dl_vdso_vsym ("__vdso_time", &linux26) ?: (void *) VSYSCALL_ADDR_vtime; -} -__asm (".type __libc_time, %gnu_indirect_function"); - -#undef time -strong_alias (__libc_time, time) -libc_hidden_ver (__libc_time, time) - -#else - -# include -# include - -time_t -time (time_t *t) -{ - INTERNAL_SYSCALL_DECL (err); - return INTERNAL_SYSCALL (time, err, 1, t); -} - +#define TIME_FALLBACK (void*)VSYSCALL_ADDR_vtime #endif + +#include diff --git a/sysdeps/unix/sysv/linux/x86_64/timespec_get.c b/sysdeps/unix/sysv/linux/x86_64/timespec_get.c deleted file mode 100644 index cb26068..0000000 --- a/sysdeps/unix/sysv/linux/x86_64/timespec_get.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "bits/libc-vdso.h" - -#ifdef SHARED -# define INTERNAL_GETTIME(id, tp) \ - ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \ - PTR_DEMANGLE (f); \ - f (id, tp); }) -#endif - -#include "../timespec_get.c"