[PATCH 01/12] linux: Fix vDSO macros build with time64 interfaces

classic Classic list List threaded Threaded
28 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[PATCH 01/12] linux: Fix vDSO macros build with time64 interfaces

Adhemerval Zanella-2
As indicated on libc-help [1] the ec138c67cb commit broke 32-bit
builds when configured with --enable-kernel=5.1 or higher.  The
scenario 10 from [2] might also occur in this configuration and
INLINE_VSYSCALL will try to use the vDSO symbol and
HAVE_CLOCK_GETTIME64_VSYSCALL does not set HAVE_VSYSCALL prior its
usage.

Also, there is no easy way to just enable the code to use one
vDSO sysmbo since the macro INLINE_VSYSCALL is redefined if
HAVE_VSYSCALL is set.

Instead of adding more pre-processor handling and making the code
even more convoluted, this patch removes the requirement of defining
HAVE_VSYSCALL before including sysdep-vdso.h to enable vDSO usage.

The INLINE_VSYSCALL now only tries to call the vDSO symbol through
the function pointer, the fallback code to try the syscall is done
explicitly.  The internal INLINE_VSYSCALL_CALL semantic is also
changed to return a negative errno value in case of an error, it allows
simplify INLINE_VSYSCALL implementation.

The macro is now expect to be called inside the HAVE_*_VSYSCALL and
it does not fallback to call the syscall (this should be done
explicitly).  Also, calling the INLINE_VSYSCALL macro with a vDSO name
not defined by the architecture will trigger a build error.

Internally it is also simplified to expected a negative value with
errno embedded similar on how the Linux syscall work.  It simplifies
error handling.

Both clock_getres and clock_gettime vDSO code for time64_t were
removed since there is no vDSO setup code for the symbol (currently
an architecture can not set HAVE_CLOCK_GETTIME64_VSYSCALL).

Checked on i686-linux-gnu (default and with --enable-kernel=5.1),
x86_64-linux-gnu, aarch64-linux-gnu, and powerpc64le-linux-gnu.
I also checked against a build to mips64-linux-gnu and
sparc64-linux-gnu.

[1] https://sourceware.org/ml/libc-help/2019-12/msg00014.html
---
 .../unix/sysv/linux/aarch64/gettimeofday.c    |  8 +-
 sysdeps/unix/sysv/linux/clock_getres.c        | 43 ++++++----
 sysdeps/unix/sysv/linux/clock_gettime.c       | 45 +++++++----
 sysdeps/unix/sysv/linux/getcpu.c              | 13 +--
 sysdeps/unix/sysv/linux/mips/sysdep.h         | 16 ----
 .../sysv/linux/powerpc/get_timebase_freq.c    |  3 +-
 .../unix/sysv/linux/powerpc/gettimeofday.c    |  8 +-
 .../sysv/linux/powerpc/powerpc32/sysdep.h     | 10 ++-
 .../sysv/linux/powerpc/powerpc64/sysdep.h     | 10 ++-
 sysdeps/unix/sysv/linux/powerpc/time.c        |  9 +--
 sysdeps/unix/sysv/linux/sched_getcpu.c        | 17 ++--
 sysdeps/unix/sysv/linux/sparc/sysdep.h        |  7 --
 sysdeps/unix/sysv/linux/sysdep-vdso.h         | 79 +++++--------------
 sysdeps/unix/sysv/linux/x86/gettimeofday.c    |  8 +-
 sysdeps/unix/sysv/linux/x86/time.c            | 11 +--
 15 files changed, 117 insertions(+), 170 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
index 7e772e05ce..07d38466e2 100644
--- a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
@@ -22,10 +22,6 @@
 
 #include <time.h>
 #include <sysdep.h>
-
-#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 /* Used as a fallback in the ifunc resolver if VDSO is not available
@@ -36,7 +32,9 @@ __gettimeofday_vsyscall (struct timeval *restrict tv, void *restrict tz)
   if (__glibc_unlikely (tz != 0))
     memset (tz, 0, sizeof *tz);
 
-  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+  if (INLINE_VSYSCALL (gettimeofday, 2, tv, tz) == 0)
+    return 0;
+  return INLINE_SYSCALL_CALL (gettimeofday, tv, tz);
 }
 
 #ifdef SHARED
diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c
index 9497f78787..6c12f1d1e9 100644
--- a/sysdeps/unix/sysv/linux/clock_getres.c
+++ b/sysdeps/unix/sysv/linux/clock_getres.c
@@ -20,9 +20,6 @@
 #include <errno.h>
 #include <time.h>
 
-#ifdef HAVE_CLOCK_GETRES_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 #include <shlib-compat.h>
 #include <kernel-features.h>
@@ -31,25 +28,39 @@
 int
 __clock_getres64 (clockid_t clock_id, struct __timespec64 *res)
 {
+  int r = -1;
+
 #ifdef __ASSUME_TIME64_SYSCALLS
-# ifndef __NR_clock_getres_time64
-  return INLINE_VSYSCALL (clock_getres, 2, clock_id, res);
+  /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
+# ifdef __NR_clock_getres_time64
+  r = INLINE_SYSCALL_CALL (clock_getres_time64, clock_id, res);
 # else
-  return INLINE_SYSCALL (clock_getres_time64, 2, clock_id, res);
+#  ifdef HAVE_CLOCK_GETRES_VSYSCALL
+  r = INLINE_VSYSCALL (clock_getres, 2, clock_id, res);
+#  endif
+  if (r == -1)
+    r = INLINE_SYSCALL_CALL (clock_getres, clock_id, res);
 # endif
 #else
+  /* Old 32-bit ABI with possible 64-bit time_t support.  */
 # ifdef __NR_clock_getres_time64
-  int ret = INLINE_SYSCALL (clock_getres_time64, 2, clock_id, res);
-  if (ret == 0 || errno != ENOSYS)
-    return ret;
+  r = INLINE_SYSCALL_CALL (clock_getres_time64, clock_id, res);
 # endif
-  struct timespec ts32;
-  int retval = INLINE_VSYSCALL (clock_getres, 2, clock_id, &ts32);
-  if (! retval && res)
-    *res = valid_timespec_to_timespec64 (ts32);
-
-  return retval;
+  if (r == -1)
+    {
+      /* Fallback code that uses 32-bit support.  */
+      struct timespec ts32;
+# ifdef HAVE_CLOCK_GETRES_VSYSCALL
+      r = INLINE_VSYSCALL (clock_getres, 2, clock_id, &ts32);
+# endif
+      if (r == -1)
+ r = INLINE_SYSCALL_CALL (clock_getres, clock_id, &ts32);
+      if (r == 0)
+ *res = valid_timespec_to_timespec64 (ts32);
+    }
 #endif
+
+  return r;
 }
 
 #if __TIMESIZE != 64
@@ -60,7 +71,7 @@ __clock_getres (clockid_t clock_id, struct timespec *res)
   int retval;
 
   retval = __clock_getres64 (clock_id, &ts64);
-  if (! retval && res)
+  if (retval == 0 && res ! = NULL)
     *res = valid_timespec64_to_timespec (ts64);
 
   return retval;
diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
index 875c4fe905..4ea56c9a4b 100644
--- a/sysdeps/unix/sysv/linux/clock_gettime.c
+++ b/sysdeps/unix/sysv/linux/clock_gettime.c
@@ -21,10 +21,6 @@
 #include <errno.h>
 #include <time.h>
 #include "kernel-posix-cpu-timers.h"
-
-#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 #include <shlib-compat.h>
@@ -33,24 +29,39 @@
 int
 __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
 {
+  int r = -1;
+
 #ifdef __ASSUME_TIME64_SYSCALLS
-# ifndef __NR_clock_gettime64
-#  define __NR_clock_gettime64   __NR_clock_gettime
-#  define __vdso_clock_gettime64 __vdso_clock_gettime
+  /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
+# ifdef __NR_clock_gettime64
+  r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
+# else
+#  ifdef HAVE_CLOCK_GETTIME_VSYSCALL
+  r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
+#  endif
+  if (r == -1)
+    r = INLINE_SYSCALL_CALL (clock_gettime, clock_id, tp);
 # endif
-   return INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
 #else
-# if defined HAVE_CLOCK_GETTIME64_VSYSCALL
-  int ret64 = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
-  if (ret64 == 0 || errno != ENOSYS)
-    return ret64;
+  /* Old 32-bit ABI with possible 64-bit time_t support.  */
+# ifdef __NR_clock_gettime64
+  r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
 # endif
-  struct timespec tp32;
-  int ret = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &tp32);
-  if (ret == 0)
-    *tp = valid_timespec_to_timespec64 (tp32);
-  return ret;
+  if (r == -1)
+    {
+      /* Fallback code that uses 32-bit support.  */
+      struct timespec tp32;
+# ifdef HAVE_CLOCK_GETTIME_VSYSCALL
+      r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &tp32);
+# endif
+      if (r == -1)
+ r = INLINE_SYSCALL_CALL (clock_gettime, clock_id, &tp32);
+      if (r == 0)
+ *tp = valid_timespec_to_timespec64 (tp32);
+    }
 #endif
+
+  return r;
 }
 
 #if __TIMESIZE != 64
diff --git a/sysdeps/unix/sysv/linux/getcpu.c b/sysdeps/unix/sysv/linux/getcpu.c
index fdd27203af..8b26b3e19e 100644
--- a/sysdeps/unix/sysv/linux/getcpu.c
+++ b/sysdeps/unix/sysv/linux/getcpu.c
@@ -18,21 +18,16 @@
 #include <errno.h>
 #include <sched.h>
 #include <sysdep.h>
-
-#ifdef HAVE_GETCPU_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 int
 __getcpu (unsigned int *cpu, unsigned int *node)
 {
-#ifdef __NR_getcpu
-  return INLINE_VSYSCALL (getcpu, 3, cpu, node, NULL);
-#else
-  __set_errno (ENOSYS);
-  return -1;
+#ifdef HAVE_GETCPU_VSYSCALL
+  if (INLINE_VSYSCALL (getcpu, 3, cpu, node, NULL) == 0)
+    return 0;
 #endif
+  return INLINE_SYSCALL_CALL (getcpu, cpu, node, NULL);
 }
 weak_alias (__getcpu, getcpu)
 libc_hidden_def (__getcpu)
diff --git a/sysdeps/unix/sysv/linux/mips/sysdep.h b/sysdeps/unix/sysv/linux/mips/sysdep.h
index 82a3cf9f3d..2470f32d58 100644
--- a/sysdeps/unix/sysv/linux/mips/sysdep.h
+++ b/sysdeps/unix/sysv/linux/mips/sysdep.h
@@ -22,19 +22,3 @@
 /* List of system calls which are supported as vsyscalls.  */
 #define HAVE_CLOCK_GETTIME_VSYSCALL     "__vdso_clock_gettime"
 #define HAVE_GETTIMEOFDAY_VSYSCALL      "__vdso_gettimeofday"
-
-#ifndef __ASSEMBLER__
-
-/* Standard MIPS syscalls have an error flag, and return a positive errno
-   when the error flag is set. Emulate this behaviour for vsyscalls so that
-   the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly.  */
-#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
-  ({ \
-    long _ret = funcptr (args); \
-    err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
-    if (err) \
-      _ret = -_ret; \
-    _ret; \
-  })
-
-#endif /* __ASSEMBLER__  */
diff --git a/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c b/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c
index 29b6624b9a..32b9ab5da5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c
+++ b/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c
@@ -106,7 +106,6 @@ __get_timebase_freq (void)
   if (vdsop == NULL)
     return get_timebase_freq_fallback ();
 
-  INTERNAL_SYSCALL_DECL (err);
-  return INTERNAL_VSYSCALL_CALL_TYPE (vdsop, err, uint64_t, 0);
+  return INTERNAL_VSYSCALL_CALL_TYPE (vdsop, uint64_t, 0);
 }
 weak_alias (__get_timebase_freq, __ppc_get_timebase_freq)
diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
index 18d8f7cb7a..1982b1e025 100644
--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
@@ -17,10 +17,6 @@
 
 #include <time.h>
 #include <sysdep.h>
-
-#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 static int
@@ -29,7 +25,9 @@ __gettimeofday_syscall (struct timeval *restrict tv, void *restrict tz)
   if (__glibc_unlikely (tz != 0))
     memset (tz, 0, sizeof *tz);
 
-  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+  if (INLINE_VSYSCALL (gettimeofday, 2, tv, tz) == 0)
+    return 0;
+  return INLINE_SYSCALL_CALL (gettimeofday, tv, tz);
 }
 
 #ifdef SHARED
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index a3bb552254..3d208dc192 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -41,7 +41,7 @@
    function call, with the exception of LR (which is needed for the
    "sc; bnslr+" sequence) and CR (where only CR0.SO is clobbered to signal
    an error return status).  */
-# define INTERNAL_VSYSCALL_CALL_TYPE(funcptr, err, type, nr, args...)      \
+# define INTERNAL_VSYSCALL_CALL_TYPE(funcptr, type, nr, args...)      \
   ({      \
     register void *r0  __asm__ ("r0");      \
     register long int r3  __asm__ ("r3");      \
@@ -63,13 +63,15 @@
        : "+r" (r0), "+r" (r3), "+r" (r4), "+r" (r5),  "+r" (r6),  "+r" (r7),  \
  "+r" (r8), "+r" (r9), "+r" (r10), "+r" (r11), "+r" (r12)      \
        : : "cr0", "ctr", "lr", "memory");      \
-    err = (long int) r0;      \
+    long int err = (long int) r0;      \
     __asm__ __volatile__ ("" : "=r" (rval) : "r" (r3), "r" (r4));      \
+    if (INTERNAL_SYSCALL_ERROR_P (rval, err))      \
+      rval = -rval;      \
     rval;      \
   })
 
-#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
-  INTERNAL_VSYSCALL_CALL_TYPE(funcptr, err, long int, nr, args)
+#define INTERNAL_VSYSCALL_CALL(funcptr, nr, args...) \
+  INTERNAL_VSYSCALL_CALL_TYPE(funcptr, long int, nr, args)
 
 # undef INLINE_SYSCALL
 # define INLINE_SYSCALL(name, nr, args...) \
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
index 207d9d5709..65f5789c63 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
@@ -51,7 +51,7 @@
    gave back in the non-error (CR0.SO cleared) case, otherwise (CR0.SO set)
    the negation of the return value in the kernel gets reverted.  */
 
-#define INTERNAL_VSYSCALL_CALL_TYPE(funcptr, err, type, nr, args...)    \
+#define INTERNAL_VSYSCALL_CALL_TYPE(funcptr, type, nr, args...)         \
   ({ \
     register void *r0  __asm__ ("r0"); \
     register long int r3  __asm__ ("r3"); \
@@ -70,13 +70,15 @@
        : "+r" (r0), "+r" (r3), "+r" (r4), "+r" (r5),  "+r" (r6),        \
          "+r" (r7), "+r" (r8) \
        : : "r9", "r10", "r11", "r12", "cr0", "ctr", "lr", "memory"); \
-    err = (long int) r0; \
+    long int err = (long int) r0; \
     __asm__ __volatile__ ("" : "=r" (rval) : "r" (r3));        \
+    if (INTERNAL_SYSCALL_ERROR_P (rval, err)) \
+      rval = -rval; \
     rval; \
   })
 
-#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
-  INTERNAL_VSYSCALL_CALL_TYPE(funcptr, err, long int, nr, args)
+#define INTERNAL_VSYSCALL_CALL(funcptr, nr, args...) \
+  INTERNAL_VSYSCALL_CALL_TYPE(funcptr, long int, nr, args)
 
 /* This version is for kernels that implement system calls that
    behave like function calls as far as register saving.  */
diff --git a/sysdeps/unix/sysv/linux/powerpc/time.c b/sysdeps/unix/sysv/linux/powerpc/time.c
index 80a4c73416..2059097c0a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/time.c
+++ b/sysdeps/unix/sysv/linux/powerpc/time.c
@@ -18,16 +18,15 @@
 
 #include <time.h>
 #include <sysdep.h>
-
-#ifdef HAVE_TIME_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 static time_t
 time_vsyscall (time_t *t)
 {
-  return INLINE_VSYSCALL (time, 1, t);
+  time_t ret = INLINE_VSYSCALL (time, 1, t);
+  if (ret != -1)
+    return ret;
+  return INLINE_SYSCALL_CALL (time, t);
 }
 
 #ifdef SHARED
diff --git a/sysdeps/unix/sysv/linux/sched_getcpu.c b/sysdeps/unix/sysv/linux/sched_getcpu.c
index 65dd9fdda7..23a60f1b52 100644
--- a/sysdeps/unix/sysv/linux/sched_getcpu.c
+++ b/sysdeps/unix/sysv/linux/sched_getcpu.c
@@ -18,22 +18,17 @@
 #include <errno.h>
 #include <sched.h>
 #include <sysdep.h>
-
-#ifdef HAVE_GETCPU_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 int
 sched_getcpu (void)
 {
-#ifdef __NR_getcpu
   unsigned int cpu;
-  int r = INLINE_VSYSCALL (getcpu, 3, &cpu, NULL, NULL);
-
-  return r == -1 ? r : cpu;
-#else
-  __set_errno (ENOSYS);
-  return -1;
+  int r = -1;
+#ifdef HAVE_GETCPU_VSYSCALL
+  r = INLINE_VSYSCALL (getcpu, 3, &cpu, NULL, NULL);
 #endif
+  if (r == -1)
+    r = INLINE_SYSCALL_CALL (getcpu, &cpu, NULL, NULL);
+  return r == -1 ? r : cpu;
 }
diff --git a/sysdeps/unix/sysv/linux/sparc/sysdep.h b/sysdeps/unix/sysv/linux/sparc/sysdep.h
index f38144c912..4ae0fca6ee 100644
--- a/sysdeps/unix/sysv/linux/sparc/sysdep.h
+++ b/sysdeps/unix/sysv/linux/sparc/sysdep.h
@@ -34,13 +34,6 @@
 
 #else /* __ASSEMBLER__ */
 
-#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
-  ({ \
-    long _ret = funcptr (args); \
-    err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
-    _ret; \
-  })
-
 # define VDSO_NAME  "LINUX_2.6"
 # define VDSO_HASH  61765110
 
diff --git a/sysdeps/unix/sysv/linux/sysdep-vdso.h b/sysdeps/unix/sysv/linux/sysdep-vdso.h
index cf614fbf8b..04525340a5 100644
--- a/sysdeps/unix/sysv/linux/sysdep-vdso.h
+++ b/sysdeps/unix/sysv/linux/sysdep-vdso.h
@@ -21,69 +21,30 @@
 
 #include <dl-vdso.h>
 
+/* Return the errno value as a negative value in case of an error or 0 or
+   positive value otherwise.  */
 #ifndef INTERNAL_VSYSCALL_CALL
-# define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...)      \
+# define INTERNAL_VSYSCALL_CALL(funcptr, nr, args...)     \
      funcptr (args)
 #endif
 
-#ifdef HAVE_VSYSCALL
-
-# include <libc-vdso.h>
-
-# define INLINE_VSYSCALL(name, nr, args...)      \
-  ({      \
-    __label__ out;      \
-    __label__ iserr;      \
-    INTERNAL_SYSCALL_DECL (sc_err);      \
-    long int sc_ret;      \
-      \
-    __typeof (__vdso_##name) vdsop = __vdso_##name;      \
-    PTR_DEMANGLE (vdsop);      \
-    if (vdsop != NULL)      \
-      {      \
- sc_ret = INTERNAL_VSYSCALL_CALL (vdsop, sc_err, nr, ##args);      \
- if (!INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err))      \
-  goto out;      \
- if (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err) != ENOSYS)      \
-  goto iserr;      \
-      }      \
-      \
-    sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, ##args);      \
-    if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err))      \
-      {      \
-      iserr:      \
-        __set_errno (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err));      \
-        sc_ret = -1L;      \
-      }      \
-  out:      \
-    sc_ret;      \
-  })
-
-# define INTERNAL_VSYSCALL(name, err, nr, args...)      \
-  ({      \
-    __label__ out;      \
-    long v_ret;      \
-      \
-    __typeof (__vdso_##name) vdsop = __vdso_##name;      \
-    PTR_DEMANGLE (vdsop);      \
-    if (vdsop != NULL)      \
-      {      \
- v_ret = INTERNAL_VSYSCALL_CALL (vdsop, err, nr, ##args);      \
- if (!INTERNAL_SYSCALL_ERROR_P (v_ret, err)      \
-    || INTERNAL_SYSCALL_ERRNO (v_ret, err) != ENOSYS)      \
-  goto out;      \
-      }      \
-    v_ret = INTERNAL_SYSCALL (name, err, nr, ##args);      \
-  out:      \
-    v_ret;      \
+#include <libc-vdso.h>
+
+#define INLINE_VSYSCALL(name, nr, args...)     \
+  ({     \
+    long int sc_ret = -1;     \
+    __typeof (__vdso_##name) vdsop = __vdso_##name;     \
+    PTR_DEMANGLE (vdsop);     \
+    if (vdsop != NULL)     \
+      {     \
+ sc_ret = INTERNAL_VSYSCALL_CALL (vdsop, nr, ##args);         \
+ if ((unsigned long) sc_ret > -4096UL)     \
+  {     \
+    __set_errno (-sc_ret);     \
+    sc_ret = -1L;     \
+  }     \
+      }     \
+    sc_ret;     \
   })
-#else
-
-# define INLINE_VSYSCALL(name, nr, args...) \
-   INLINE_SYSCALL (name, nr, ##args)
-# define INTERNAL_VSYSCALL(name, err, nr, args...) \
-   INTERNAL_SYSCALL (name, err, nr, ##args)
-
-#endif /* USE_VSYSCALL && defined HAVE_VSYSCALL */
 
 #endif /* SYSDEP_VDSO_LINUX_H  */
diff --git a/sysdeps/unix/sysv/linux/x86/gettimeofday.c b/sysdeps/unix/sysv/linux/x86/gettimeofday.c
index 190127d31e..909575a7e3 100644
--- a/sysdeps/unix/sysv/linux/x86/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/x86/gettimeofday.c
@@ -18,10 +18,6 @@
 
 #include <time.h>
 #include <sysdep.h>
-
-#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 static int
@@ -30,7 +26,9 @@ __gettimeofday_syscall (struct timeval *restrict tv, void *restrict tz)
   if (__glibc_unlikely (tz != 0))
     memset (tz, 0, sizeof *tz);
 
-  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+  if (INLINE_VSYSCALL (gettimeofday, 2, tv, tz) == 0)
+    return 0;
+  return INLINE_SYSCALL_CALL (gettimeofday, tv, tz);
 }
 
 #ifdef SHARED
diff --git a/sysdeps/unix/sysv/linux/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c
index 4a03c46d21..74bae4b07a 100644
--- a/sysdeps/unix/sysv/linux/x86/time.c
+++ b/sysdeps/unix/sysv/linux/x86/time.c
@@ -18,16 +18,17 @@
 
 #include <time.h>
 #include <sysdep.h>
-
-#ifdef HAVE_TIME_VSYSCALL
-# define HAVE_VSYSCALL
-#endif
 #include <sysdep-vdso.h>
 
 static time_t
 time_vsyscall (time_t *t)
 {
-  return INLINE_VSYSCALL (time, 1, t);
+#ifdef HAVE_TIME_VSYSCALL
+  time_t ret = INLINE_VSYSCALL (time, 1, t);
+  if (ret != -1)
+    return ret;
+#endif
+  return INLINE_SYSCALL_CALL (time, t);
 }
 
 #ifdef SHARED
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 02/12] linux: Update x86 vDSO symbols

Adhemerval Zanella-2
Changes from previous version:

  - Assume HAVE_TIME_VSYSCALL on x86 time implementation.

--

Add the missing time and clock_getres vDSO symbol names on x86.
For time, the iFUNC already uses expected name so it affects only
the static build.

The clock_getres is a new implementation added on Linux 5.3
(f66501dc53e72).

Checked on x86-linux-gnu and i686-linux-gnu.
---
 sysdeps/unix/sysv/linux/i386/sysdep.h   | 2 ++
 sysdeps/unix/sysv/linux/x86/time.c      | 2 --
 sysdeps/unix/sysv/linux/x86_64/sysdep.h | 2 ++
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index 7066ddc214..b2e750d490 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 HAVE_CLOCK_GETRES_VSYSCALL     "__vdso_clock_getres"
 
 /* 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/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c
index 74bae4b07a..0aee73826b 100644
--- a/sysdeps/unix/sysv/linux/x86/time.c
+++ b/sysdeps/unix/sysv/linux/x86/time.c
@@ -23,11 +23,9 @@
 static time_t
 time_vsyscall (time_t *t)
 {
-#ifdef HAVE_TIME_VSYSCALL
   time_t ret = INLINE_VSYSCALL (time, 1, t);
   if (ret != -1)
     return ret;
-#endif
   return INLINE_SYSCALL_CALL (time, t);
 }
 
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 475b7d991a..965fd4b851 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -376,7 +376,9 @@
 /* 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 HAVE_GETCPU_VSYSCALL "__vdso_getcpu"
+# define HAVE_CLOCK_GETRES_VSYSCALL     "__vdso_clock_getres"
 
 # define SINGLE_THREAD_BY_GLOBAL 1
 
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 03/12] x86: Make x32 use x86 time implementation

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
This is the only use of auto-generation syscall which uses a vDSO
plus IFUNC and the current x86 generic implementation already covers
the expected semantic.

Checked on x86_64-linux-gnu-x32.
---
 sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
index 786c884232..58ea31d1fd 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
@@ -2,4 +2,3 @@
 
 personality EXTRA personality Ei:i __personality personality
 posix_fadvise64 - fadvise64 Vi:iiii posix_fadvise posix_fadvise64
-time - time:__vdso_time@LINUX_2.6 Ei:P time
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 04/12] linux: Update mips vDSO symbols

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
The clock_getres is a new implementation added on Linux 5.4
(abed3d826f2f).

Checked with a build against mips-linux-gnu and mips64-linux-gnu.
---
 sysdeps/unix/sysv/linux/mips/sysdep.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sysdeps/unix/sysv/linux/mips/sysdep.h b/sysdeps/unix/sysv/linux/mips/sysdep.h
index 2470f32d58..defad8eb62 100644
--- a/sysdeps/unix/sysv/linux/mips/sysdep.h
+++ b/sysdeps/unix/sysv/linux/mips/sysdep.h
@@ -22,3 +22,4 @@
 /* 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_CLOCK_GETRES_VSYSCALL      "__vdso_clock_getres"
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 05/12] Remove vDSO support from make-syscall.sh

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
The auto-generated vDSO call show some issues:

  - It requires sync the auto-generated C file with current glibc
    implementation;
  - It still uses still uses symbol redirections hacks where
    libc-symbols.h provide macros that uses compiler builtins
    (libc_ifunc_redirected for instance);
  - It does not handle all required compiler handling
    (inhibit_stack_protector on iFUNC resolver).
  - It does not have any usage currently.

Checked with a build against all major ABIs.
---
 sysdeps/unix/make-syscalls.sh | 45 +----------------------------------
 1 file changed, 1 insertion(+), 44 deletions(-)

diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh
index fe24bbc78f..c07626677f 100644
--- a/sysdeps/unix/make-syscalls.sh
+++ b/sysdeps/unix/make-syscalls.sh
@@ -149,14 +149,6 @@ emit_weak_aliases()
 echo "$calls" |
 while read file srcfile caller syscall args strong weak; do
 
-  vdso_syscall=
-  case x"$syscall" in
-  *:*@*)
-    vdso_syscall="${syscall#*:}"
-    syscall="${syscall%:*}"
-    ;;
-  esac
-
   case x"$syscall" in
   x-) callnum=_ ;;
   *)
@@ -233,10 +225,9 @@ while read file srcfile caller syscall args strong weak; do
   if test $shared_only = t; then
     # The versioned symbols are only in the shared library.
     echo "shared-only-routines += $file"
-    test -n "$vdso_syscall" || echo "\$(objpfx)${file}.os: \\"
+    echo "\$(objpfx)${file}.os: \\"
   else
     object_suffixes='$(object-suffixes)'
-    test -z "$vdso_syscall" || object_suffixes='$(object-suffixes-noshared)'
     echo "\
 \$(foreach p,\$(sysd-rules-targets),\
 \$(foreach o,${object_suffixes},\$(objpfx)\$(patsubst %,\$p,$file)\$o)): \\"
@@ -268,40 +259,6 @@ while read file srcfile caller syscall args strong weak; do
   echo ' ) | $(compile-syscall) '"\
 \$(foreach p,\$(patsubst %$file,%,\$(basename \$(@F))),\$(\$(p)CPPFLAGS))"
 
-  if test -n "$vdso_syscall"; then
-    # In the shared library, we're going to emit an IFUNC using a vDSO function.
-    # $vdso_syscall looks like "[hidden email]" where "name" is the symbol
-    # name in the vDSO and KERNEL_X.Y is its symbol version.
-    vdso_symbol="${vdso_syscall%@*}"
-    vdso_symver="${vdso_syscall#*@}"
-    vdso_symver=`echo "$vdso_symver" | sed 's/\./_/g'`
-    cat <<EOF
-
-\$(foreach p,\$(sysd-rules-targets),\$(objpfx)\$(patsubst %,\$p,$file).os): \\
- \$(..)sysdeps/unix/make-syscalls.sh
- \$(make-target-directory)
- (echo '#define ${strong} __redirect_${strong}'; \\
- echo '#include <dl-vdso.h>'; \\
- echo '#undef ${strong}'; \\
- echo '#define vdso_ifunc_init()'; \\
- echo '__ifunc (__redirect_${strong}, ${strong},'; \\
- echo '         get_vdso_symbol ("${vdso_symbol}"), void,'; \\
- echo '         vdso_ifunc_init)'; \\
-EOF
-    # This is doing "hidden_def (${strong})", but the compiler
-    # doesn't know that we've defined ${strong} in the same file, so
-    # we can't do it the normal way.
-    cat <<EOF
- echo 'asm (".globl __GI_${strong}");'; \\
- echo 'asm ("__GI_${strong} = ${strong}");'; \\
-EOF
-    emit_weak_aliases
-    cat <<EOF
- ) | \$(compile-stdin.c) \
-\$(foreach p,\$(patsubst %$file,%,\$(basename \$(@F))),\$(\$(p)CPPFLAGS))
-EOF
-  fi
-
   if test $shared_only = t; then
     # The versioned symbols are only in the shared library.
     echo endif
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 06/12] elf: Enable relro for static build

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
Changes from previous version:

  - Added tests for partial and full relro.

--

The code is similar to the one at elf/dl-reloc.c, where it checks for
the l_relro_size from the link_map (obtained from PT_GNU_RELRO header
from program headers) and calls_dl_protected_relro.

Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc64le-linux-gnu,
aarch64-linux-gnu, s390x-linux-gnu, and sparc64-linux-gnu.  I also
check with --enable-static pie on x86_64-linux-gnu, i686-linux-gnu,
and aarch64-linux-gnu which seems the only architectures where
static PIE is actually working (as per 9d7a3741c9e, on
arm-linux-gnueabihf, powerpc64{le}-linux-gnu, and s390x-linux-gnu
I am seeing runtime issues not related to my patch).
---
 elf/Makefile                     | 11 +++++++--
 elf/dl-support.c                 | 18 +++++++++++---
 elf/tst-data-relro-lazy-static.c |  1 +
 elf/tst-data-relro-lazy.c        |  1 +
 elf/tst-data-relro-now-static.c  |  1 +
 elf/tst-data-relro-now.c         |  1 +
 elf/tst-data-relro.c             | 42 ++++++++++++++++++++++++++++++++
 7 files changed, 69 insertions(+), 6 deletions(-)
 create mode 100644 elf/tst-data-relro-lazy-static.c
 create mode 100644 elf/tst-data-relro-lazy.c
 create mode 100644 elf/tst-data-relro-now-static.c
 create mode 100644 elf/tst-data-relro-now.c
 create mode 100644 elf/tst-data-relro.c

diff --git a/elf/Makefile b/elf/Makefile
index b2b3be203f..45b5ad4ea6 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -154,7 +154,8 @@ endif
 tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \
        tst-dl-iter-static \
        tst-tlsalign-static tst-tlsalign-extern-static \
-       tst-linkall-static tst-env-setuid tst-env-setuid-tunables
+       tst-linkall-static tst-env-setuid tst-env-setuid-tunables \
+       tst-data-relro-lazy-static tst-data-relro-now-static
 tests-static-internal := tst-tls1-static tst-tls2-static \
        tst-ptrguard1-static tst-stackguard1-static \
        tst-tls1-static-non-pie tst-libc_dlvsym-static
@@ -205,7 +206,8 @@ tests-internal += loadtest unload unload2 circleload1 \
  neededtest neededtest2 neededtest3 neededtest4 \
  tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
  tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
- tst-create_format1
+ tst-create_format1 \
+ tst-data-relro-now tst-data-relro-lazy
 tests-container += tst-pldd tst-dlopen-tlsmodid-container \
   tst-dlopen-self-container
 test-srcs = tst-pathopt
@@ -1627,3 +1629,8 @@ $(objpfx)tst-dlopenfailmod1.so: \
   $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
 LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
 $(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library)
+
+LDFLAGS-tst-data-relro-lazy += -Wl,-z,relro -Wl,-z,lazy
+LDFLAGS-tst-data-relro-lazy-static += -Wl,-z,relro -Wl,-z,lazy
+LDFLAGS-tst-data-relro-now += -Wl,-z,relro -Wl,-z,now
+LDFLAGS-tst-data-relro-now-static += -Wl,-z,relro -Wl,-z,now
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 5526d5ee6e..b2b1b12f6f 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -367,14 +367,24 @@ _dl_non_dynamic_init (void)
   if (_dl_platform != NULL)
     _dl_platformlen = strlen (_dl_platform);
 
-  /* Scan for a program header telling us the stack is nonexecutable.  */
   if (_dl_phdr != NULL)
-    for (uint_fast16_t i = 0; i < _dl_phnum; ++i)
-      if (_dl_phdr[i].p_type == PT_GNU_STACK)
+    for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph)
+      switch (ph->p_type)
  {
-  _dl_stack_flags = _dl_phdr[i].p_flags;
+ /* Check if the stack is nonexecutable.  */
+ case PT_GNU_STACK:
+  _dl_stack_flags = ph->p_flags;
+  break;
+
+ case PT_GNU_RELRO:
+  _dl_main_map.l_relro_addr = ph->p_vaddr;
+  _dl_main_map.l_relro_size = ph->p_memsz;
   break;
  }
+
+  /* Setup relro on the binary itself.  */
+  if (_dl_main_map.l_relro_size != 0)
+    _dl_protect_relro (&_dl_main_map);
 }
 
 #ifdef DL_SYSINFO_IMPLEMENTATION
diff --git a/elf/tst-data-relro-lazy-static.c b/elf/tst-data-relro-lazy-static.c
new file mode 100644
index 0000000000..364a206506
--- /dev/null
+++ b/elf/tst-data-relro-lazy-static.c
@@ -0,0 +1 @@
+#include <elf/tst-data-relro.c>
diff --git a/elf/tst-data-relro-lazy.c b/elf/tst-data-relro-lazy.c
new file mode 100644
index 0000000000..364a206506
--- /dev/null
+++ b/elf/tst-data-relro-lazy.c
@@ -0,0 +1 @@
+#include <elf/tst-data-relro.c>
diff --git a/elf/tst-data-relro-now-static.c b/elf/tst-data-relro-now-static.c
new file mode 100644
index 0000000000..364a206506
--- /dev/null
+++ b/elf/tst-data-relro-now-static.c
@@ -0,0 +1 @@
+#include <elf/tst-data-relro.c>
diff --git a/elf/tst-data-relro-now.c b/elf/tst-data-relro-now.c
new file mode 100644
index 0000000000..364a206506
--- /dev/null
+++ b/elf/tst-data-relro-now.c
@@ -0,0 +1 @@
+#include <elf/tst-data-relro.c>
diff --git a/elf/tst-data-relro.c b/elf/tst-data-relro.c
new file mode 100644
index 0000000000..bd63b24b3f
--- /dev/null
+++ b/elf/tst-data-relro.c
@@ -0,0 +1,42 @@
+/* Test if variables places on relro section are not writable.
+   Copyright (C) 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <signal.h>
+
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+
+static volatile int val __attribute__ ((section (".data.rel.ro")));
+
+static void
+callback (void *closure)
+{
+  /* It should trigger an invalid write.  */
+  val = 1;
+}
+
+int do_test (void)
+{
+  struct support_capture_subprocess result
+    = support_capture_subprocess (callback, NULL);
+  support_capture_subprocess_check (&result, "tst-relro", -SIGSEGV,
+    sc_allow_stdout);
+  return 0;
+}
+
+#include <support/test-driver.c>
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 07/12] elf: Move vDSO setup to rtld (BZ#24967)

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
Changes from previous version:

 - Simplified the patch by moving the HAVE_VSYSCALL removal refactor
   to its own patch.

--

This patch moves the vDSO setup from libc to loader code, just
after the vDSO link_map setup.  For static case the initialization
is moved to _dl_non_dynamic_init instead.

Instead of using the mangled pointer, the vDSO data is set as
attribute_relro (on _rtld_global_ro for shared or _dl_vdso_* for
static).  It is read-only even with partial relro.

It also fixes BZ#24967 now that the vDSO pointer is setup earlier
than malloc interposition is called.

Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu,
arm-linux-gnueabihf, powerpc64le-linux-gnu, powerpc64-linux-gnu,
powerpc-linux-gnu, s390x-linux-gnu, sparc64-linux-gnu, and
sparcv9-linux-gnu.  I also run some tests on mips.
---
 csu/init-first.c                              |  4 -
 elf/dl-support.c                              |  7 ++
 elf/rtld.c                                    |  7 +-
 malloc/tst-interpose-aux.c                    |  5 ++
 sysdeps/generic/dl-vdso-setup.c               |  1 +
 sysdeps/generic/dl-vdso-setup.h               | 28 ++++++
 sysdeps/generic/dl-vdso.h                     | 30 +++++++
 sysdeps/generic/ldsodefs.h                    |  6 ++
 sysdeps/powerpc/powerpc32/backtrace.c         | 16 ++--
 sysdeps/powerpc/powerpc64/backtrace.c         |  8 +-
 sysdeps/unix/sysv/linux/aarch64/Makefile      |  1 -
 .../unix/sysv/linux/aarch64/gettimeofday.c    |  5 +-
 sysdeps/unix/sysv/linux/arm/Makefile          |  1 -
 sysdeps/unix/sysv/linux/dl-vdso-setup.c       | 81 +++++++++++++++++
 sysdeps/unix/sysv/linux/dl-vdso-setup.h       | 55 ++++++++++++
 sysdeps/unix/sysv/linux/dl-vdso.c             | 48 ----------
 sysdeps/unix/sysv/linux/dl-vdso.h             | 30 ++++---
 sysdeps/unix/sysv/linux/init-first.c          | 90 -------------------
 sysdeps/unix/sysv/linux/libc-vdso.h           | 55 ------------
 sysdeps/unix/sysv/linux/mips/Makefile         |  2 -
 sysdeps/unix/sysv/linux/powerpc/Makefile      |  1 -
 .../sysv/linux/powerpc/get_timebase_freq.c    | 12 ++-
 .../unix/sysv/linux/powerpc/gettimeofday.c    | 15 ++--
 sysdeps/unix/sysv/linux/powerpc/init-first.c  | 50 -----------
 sysdeps/unix/sysv/linux/powerpc/libc-vdso.h   | 10 ---
 sysdeps/unix/sysv/linux/powerpc/time.c        | 17 ++--
 sysdeps/unix/sysv/linux/riscv/Makefile        |  4 -
 sysdeps/unix/sysv/linux/riscv/flush-icache.c  |  2 +-
 sysdeps/unix/sysv/linux/s390/Makefile         |  4 -
 sysdeps/unix/sysv/linux/sparc/Makefile        |  4 -
 sysdeps/unix/sysv/linux/sysdep-vdso.h         | 11 +--
 sysdeps/unix/sysv/linux/x86/Makefile          |  4 -
 sysdeps/unix/sysv/linux/x86/gettimeofday.c    |  5 +-
 sysdeps/unix/sysv/linux/x86/time.c            |  5 +-
 34 files changed, 271 insertions(+), 353 deletions(-)
 create mode 100644 sysdeps/generic/dl-vdso-setup.c
 create mode 100644 sysdeps/generic/dl-vdso-setup.h
 create mode 100644 sysdeps/generic/dl-vdso.h
 create mode 100644 sysdeps/unix/sysv/linux/dl-vdso-setup.c
 create mode 100644 sysdeps/unix/sysv/linux/dl-vdso-setup.h
 delete mode 100644 sysdeps/unix/sysv/linux/dl-vdso.c
 delete mode 100644 sysdeps/unix/sysv/linux/init-first.c
 delete mode 100644 sysdeps/unix/sysv/linux/libc-vdso.h
 delete mode 100644 sysdeps/unix/sysv/linux/powerpc/init-first.c

diff --git a/csu/init-first.c b/csu/init-first.c
index e0f489ee6d..891719a839 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -74,10 +74,6 @@ _init (int argc, char **argv, char **envp)
   _dl_non_dynamic_init ();
 #endif
 
-#ifdef VDSO_SETUP
-  VDSO_SETUP ();
-#endif
-
   __init_misc (argc, argv, envp);
 
   /* Initialize ctype data.  */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index b2b1b12f6f..81d44b0343 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -34,6 +34,8 @@
 #include <unsecvars.h>
 #include <hp-timing.h>
 #include <stackinfo.h>
+#include <dl-vdso.h>
+#include <dl-vdso-setup.h>
 
 extern char *__progname;
 char **_dl_argv = &__progname; /* This is checked for some error messages.  */
@@ -201,6 +203,8 @@ struct link_map *_dl_sysinfo_map;
 # include "get-dynamic-info.h"
 #endif
 #include "setup-vdso.h"
+/* Define the vDSO function pointers.  */
+#include <dl-vdso-setup.c>
 
 /* During the program run we must not modify the global data of
    loaded shared object simultanously in two threads.  Therefore we
@@ -315,6 +319,9 @@ _dl_non_dynamic_init (void)
      so they can influence _dl_init_paths.  */
   setup_vdso (NULL, NULL);
 
+  /* With vDSO setup we can initialize the function pointers.  */
+  setup_vdso_pointers ();
+
   /* Initialize the data structures for the search paths for shared
      objects.  */
   _dl_init_paths (getenv ("LD_LIBRARY_PATH"));
diff --git a/elf/rtld.c b/elf/rtld.c
index dd8fc5e6c6..a06e13c657 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -39,6 +39,8 @@
 #include <dl-osinfo.h>
 #include <dl-procinfo.h>
 #include <dl-prop.h>
+#include <dl-vdso.h>
+#include <dl-vdso-setup.h>
 #include <tls.h>
 #include <stap-probe.h>
 #include <stackinfo.h>
@@ -833,7 +835,7 @@ security_init (void)
   _dl_random = NULL;
 }
 
-#include "setup-vdso.h"
+#include <setup-vdso.h>
 
 /* The library search path.  */
 static const char *library_path attribute_relro;
@@ -1538,6 +1540,9 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
      so they can influence _dl_init_paths.  */
   setup_vdso (main_map, &first_preload);
 
+  /* With vDSO setup we can initialize the function pointers.  */
+  setup_vdso_pointers ();
+
 #ifdef DL_SYSDEP_OSCHECK
   DL_SYSDEP_OSCHECK (_dl_fatal_printf);
 #endif
diff --git a/malloc/tst-interpose-aux.c b/malloc/tst-interpose-aux.c
index bbe321e843..8cbc3e6fea 100644
--- a/malloc/tst-interpose-aux.c
+++ b/malloc/tst-interpose-aux.c
@@ -28,6 +28,7 @@
 #include <sys/mman.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#include <time.h>
 
 #if INTERPOSE_THREADS
 #include <pthread.h>
@@ -96,6 +97,7 @@ struct __attribute__ ((aligned (__alignof__ (max_align_t)))) allocation_header
 {
   size_t allocation_index;
   size_t allocation_size;
+  struct timespec ts;
 };
 
 /* Array of known allocations, to track invalid frees.  */
@@ -166,6 +168,9 @@ malloc_internal (size_t size)
       .allocation_index = index,
       .allocation_size = allocation_size
     };
+  /* BZ#24967: Check if calling a symbol which may use the vDSO does not fail.
+     The CLOCK_REALTIME should be supported on all systems.  */
+  clock_gettime (CLOCK_REALTIME, &allocations[index]->ts);
   return allocations[index] + 1;
 }
 
diff --git a/sysdeps/generic/dl-vdso-setup.c b/sysdeps/generic/dl-vdso-setup.c
new file mode 100644
index 0000000000..6e25b021ab
--- /dev/null
+++ b/sysdeps/generic/dl-vdso-setup.c
@@ -0,0 +1 @@
+/* Empty.  */
diff --git a/sysdeps/generic/dl-vdso-setup.h b/sysdeps/generic/dl-vdso-setup.h
new file mode 100644
index 0000000000..3d79bae317
--- /dev/null
+++ b/sysdeps/generic/dl-vdso-setup.h
@@ -0,0 +1,28 @@
+/* ELF symbol initialization functions for VDSO objects.
+   Copyright (C) 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_VDSO_INIT_H
+#define _DL_VDSO_INIT_H
+
+/* Initialize the VDSO functions pointers.  */
+static inline void __attribute__ ((always_inline))
+setup_vdso_pointers (void)
+{
+}
+
+#endif
diff --git a/sysdeps/generic/dl-vdso.h b/sysdeps/generic/dl-vdso.h
new file mode 100644
index 0000000000..5651f49a1a
--- /dev/null
+++ b/sysdeps/generic/dl-vdso.h
@@ -0,0 +1,30 @@
+/* ELF symbol resolve functions for VDSO objects.
+   Copyright (C) 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_VDSO_H
+#define _DL_VDSO_H 1
+
+/* Function for resolving symbols in the VDSO link map.  Return the
+   address of the vdso symbol NAME. */
+static inline void *
+dl_vdso_vsym (const char *name)
+{
+  return NULL;
+}
+
+#endif
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index fc25a81e1c..8cbd0e87cc 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -608,6 +608,12 @@ struct rtld_global_ro
   /* At startup time we set up the normal DSO data structure for it,
      and this points to it.  */
   EXTERN struct link_map *_dl_sysinfo_map;
+
+# define PROCINFO_DECL
+# ifndef PROCINFO_CLASS
+#  define PROCINFO_CLASS EXTERN
+# endif
+# include <dl-vdso-setup.c>
 #endif
 
   /* Mask for more hardware capabilities that are available on some
diff --git a/sysdeps/powerpc/powerpc32/backtrace.c b/sysdeps/powerpc/powerpc32/backtrace.c
index 2e6a859d9f..f2a57480a5 100644
--- a/sysdeps/powerpc/powerpc32/backtrace.c
+++ b/sysdeps/powerpc/powerpc32/backtrace.c
@@ -51,14 +51,14 @@ struct signal_frame_32 {
   /* We don't care about the rest, since IP value is at 'mctx' field.  */
 };
 
-static inline int
+static inline bool
 is_sigtramp_address (void *nip)
 {
 #ifdef HAVE_SIGTRAMP_RT32
-  if (nip == VDSO_SYMBOL (sigtramp32))
-    return 1;
+  if (nip == GLRO (dl_vdso_sigtramp_32))
+    return true;
 #endif
-  return 0;
+  return false;
 }
 
 struct rt_signal_frame_32 {
@@ -68,14 +68,14 @@ struct rt_signal_frame_32 {
   /* We don't care about the rest, since IP value is at 'uc' field.  */
 };
 
-static inline int
+static inline bool
 is_sigtramp_address_rt (void * nip)
 {
 #ifdef HAVE_SIGTRAMP_32
-  if (nip == VDSO_SYMBOL (sigtramp_rt32))
-    return 1;
+  if (nip == GLRO (dl_vdso_sigtramp_rt32))
+    return true;
 #endif
-  return 0;
+  return false;
 }
 
 int
diff --git a/sysdeps/powerpc/powerpc64/backtrace.c b/sysdeps/powerpc/powerpc64/backtrace.c
index 234d9c00dc..8ed5bc1585 100644
--- a/sysdeps/powerpc/powerpc64/backtrace.c
+++ b/sysdeps/powerpc/powerpc64/backtrace.c
@@ -54,14 +54,14 @@ struct signal_frame_64 {
   /* We don't care about the rest, since the IP value is at 'uc' field.  */
 };
 
-static inline int
+static inline bool
 is_sigtramp_address (void *nip)
 {
 #ifdef HAVE_SIGTRAMP_RT64
-  if (nip == VDSO_SYMBOL (sigtramp_rt64))
-    return 1;
+  if (nip == GLRO (dl_vdso_sigtramp_rt64))
+    return true;
 #endif
-  return 0;
+  return false;
 }
 
 int
diff --git a/sysdeps/unix/sysv/linux/aarch64/Makefile b/sysdeps/unix/sysv/linux/aarch64/Makefile
index 57bbfeaac6..4bcae85bca 100644
--- a/sysdeps/unix/sysv/linux/aarch64/Makefile
+++ b/sysdeps/unix/sysv/linux/aarch64/Makefile
@@ -5,7 +5,6 @@ shared-only-routines += libc-__read_tp
 endif
 
 ifeq ($(subdir),elf)
-sysdep_routines     += dl-vdso
 sysdep-rtld-routines += __read_tp
 ifeq ($(build-shared),yes)
 # This is needed for DSO loading from static binaries.
diff --git a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
index 07d38466e2..6475840117 100644
--- a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
@@ -38,12 +38,9 @@ __gettimeofday_vsyscall (struct timeval *restrict tv, void *restrict tz)
 }
 
 #ifdef SHARED
-# include <dl-vdso.h>
-# include <sysdep-vdso.h>
-
 # define INIT_ARCH()
 libc_ifunc (__gettimeofday,
-    (get_vdso_symbol (HAVE_GETTIMEOFDAY_VSYSCALL)
+    (GLRO(dl_vdso_gettimeofday)
     ?: __gettimeofday_vsyscall))
 
 #else
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile
index d7a2f6a8a7..abdf01f00c 100644
--- a/sysdeps/unix/sysv/linux/arm/Makefile
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
@@ -1,5 +1,4 @@
 ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
 sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
 endif
 
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.c b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
new file mode 100644
index 0000000000..1069879f1a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
@@ -0,0 +1,81 @@
+/* Data for vDSO support.  Linux version.
+   Copyright (C) 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
+   <https://www.gnu.org/licenses/>.  */
+
+/* This file is included in three different modes for both static (libc.a)
+   and shared (rtld) modes:
+
+   1. PROCINFO_DECL is defined, meaning we are only interested in
+      declarations.  For static it requires use the extern keywork along with
+      the attribute_relro while for shared it will be embedded in the
+      rtld_global_ro.
+
+   2. PROCINFO_DECL and SHARED are not defined.  Nothing to do, the default
+      zero initializion is suffice.
+
+   3. PROCINFO_DECL is not defined while SHARED is.  Similar to 2., the zero
+      initialization of rtld_global_ro is suffice.  */
+
+#ifndef PROCINFO_CLASS
+# define PROCINFO_CLASS
+#endif
+
+#ifndef SHARED
+# define RELRO attribute_relro
+#else
+# define RELRO
+#endif
+
+#if defined PROCINFO_DECL || !defined SHARED
+# ifdef HAVE_CLOCK_GETTIME_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_clock_gettime) (clockid_t,
+      struct timespec *) RELRO;
+#endif
+# ifdef HAVE_GETTIMEOFDAY_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_gettimeofday) (struct timeval *, void *) RELRO;
+#endif
+# ifdef HAVE_TIME_VSYSCALL
+PROCINFO_CLASS time_t (*_dl_vdso_time) (time_t *) RELRO;
+# endif
+# ifdef HAVE_GETCPU_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_getcpu) (unsigned *, unsigned *, void *) RELRO;
+# endif
+# ifdef HAVE_CLOCK_GETRES_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_clock_getres) (clockid_t,
+     struct timespec *) RELRO;
+# endif
+
+/* PowerPC specific ones.  */
+# ifdef HAVE_GET_TBFREQ
+PROCINFO_CLASS uint64_t (*_dl_vdso_get_tbfreq)(void) RELRO;
+# endif
+/* The sigtramp are used on powerpc backtrace without using
+   INLINE_VSYSCALL, so there is no need to set their type.  */
+# ifdef HAVE_SIGTRAMP_RT64
+PROCINFO_CLASS void *_dl_vdso_sigtramp_rt64 RELRO;
+# endif
+# ifdef HAVE_SIGTRAMP_RT32
+PROCINFO_CLASS void *_dl_vdso_sigtramp_rt32 RELRO;
+# endif
+# ifdef HAVE_SIGTRAMP_32
+PROCINFO_CLASS void *_dl_vdso_sigtramp_32 RELRO;
+# endif
+#endif
+
+#undef RELRO
+#undef PROCINFO_DECL
+#undef PROCINFO_CLASS
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.h b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
new file mode 100644
index 0000000000..f4e76202fc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
@@ -0,0 +1,55 @@
+/* ELF symbol initialization functions for VDSO objects.  Linux version.
+   Copyright (C) 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_VDSO_INIT_H
+#define _DL_VDSO_INIT_H
+
+/* Initialize the VDSO functions pointers.  */
+static inline void __attribute__ ((always_inline))
+setup_vdso_pointers (void)
+{
+#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
+  GLRO(dl_vdso_clock_gettime) = dl_vdso_vsym (HAVE_CLOCK_GETTIME_VSYSCALL);
+#endif
+#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
+  GLRO(dl_vdso_gettimeofday) = dl_vdso_vsym (HAVE_GETTIMEOFDAY_VSYSCALL);
+#endif
+#ifdef HAVE_TIME_VSYSCALL
+  GLRO(dl_vdso_time) = dl_vdso_vsym (HAVE_TIME_VSYSCALL);
+#endif
+#ifdef HAVE_GETCPU_VSYSCALL
+  GLRO(dl_vdso_getcpu) = dl_vdso_vsym (HAVE_GETCPU_VSYSCALL);
+#endif
+#ifdef HAVE_CLOCK_GETRES_VSYSCALL
+  GLRO(dl_vdso_clock_getres) = dl_vdso_vsym (HAVE_CLOCK_GETRES_VSYSCALL);
+#endif
+#ifdef HAVE_GET_TBFREQ
+  GLRO(dl_vdso_get_tbfreq) = dl_vdso_vsym (HAVE_GET_TBFREQ);
+#endif
+#ifdef HAVE_SIGTRAMP_RT64
+  GLRO(dl_vdso_sigtramp_rt64) = dl_vdso_vsym (HAVE_SIGTRAMP_RT64);
+#endif
+#ifdef HAVE_SIGTRAMP_RT32
+  GLRO(dl_vdso_sigtramp_rt32) = dl_vdso_vsym (HAVE_SIGTRAMP_RT32);
+#endif
+#ifdef HAVE_SIGTRAMP_32
+  GLRO(dl_vdso_sigtramp_32) = dl_vdso_vsym (HAVE_SIGTRAMP_32);
+#endif
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/dl-vdso.c b/sysdeps/unix/sysv/linux/dl-vdso.c
deleted file mode 100644
index 5577f2103c..0000000000
--- a/sysdeps/unix/sysv/linux/dl-vdso.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* ELF symbol resolve functions for VDSO objects.
-   Copyright (C) 2005-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
-   <https://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-#include <ldsodefs.h>
-
-
-void *
-_dl_vdso_vsym (const char *name, const struct r_found_version *vers)
-{
-  struct link_map *map = GLRO (dl_sysinfo_map);
-  void *value = NULL;
-
-
-  if (map != NULL)
-    {
-      /* Use a WEAK REF so we don't error out if the symbol is not found.  */
-      ElfW (Sym) wsym;
-      memset (&wsym, 0, sizeof (ElfW (Sym)));
-      wsym.st_info = (unsigned char) ELFW (ST_INFO (STB_WEAK, STT_NOTYPE));
-
-      /* Search the scope of the vdso map.  */
-      const ElfW (Sym) *ref = &wsym;
-      lookup_t result = GLRO (dl_lookup_symbol_x) (name, map, &ref,
-   map->l_local_scope,
-   vers, 0, 0, NULL);
-
-      if (ref != NULL)
- value = DL_SYMBOL_ADDRESS (result, ref);
-    }
-
-  return value;
-}
diff --git a/sysdeps/unix/sysv/linux/dl-vdso.h b/sysdeps/unix/sysv/linux/dl-vdso.h
index 19ffd30c7e..d1e782b81f 100644
--- a/sysdeps/unix/sysv/linux/dl-vdso.h
+++ b/sysdeps/unix/sysv/linux/dl-vdso.h
@@ -22,11 +22,6 @@
 #include <ldsodefs.h>
 #include <dl-hash.h>
 
-/* Functions for resolving symbols in the VDSO link map.  */
-extern void *_dl_vdso_vsym (const char *name,
-    const struct r_found_version *version)
-      attribute_hidden;
-
 /* If the architecture support vDSO it should define which is the expected
    kernel version and hash value through both VDSO_NAME and VDSO_HASH
    (usually defined at architecture sysdep.h).  */
@@ -38,19 +33,26 @@ extern void *_dl_vdso_vsym (const char *name,
 # define VDSO_HASH 0
 #endif
 
+/* Functions for resolving symbols in the VDSO link map.  */
 static inline void *
-get_vdso_symbol (const char *symbol)
+dl_vdso_vsym (const char *name)
 {
+  struct link_map *map = GLRO (dl_sysinfo_map);
+  if (map == NULL)
+    return NULL;
+
+  /* Use a WEAK REF so we don't error out if the symbol is not found.  */
+  ElfW (Sym) wsym = { 0 };
+  wsym.st_info = (unsigned char) ELFW (ST_INFO (STB_WEAK, STT_NOTYPE));
+
   struct r_found_version rfv = { VDSO_NAME, VDSO_HASH, 1, NULL };
-  return _dl_vdso_vsym (symbol, &rfv);
-}
 
-static inline void *
-get_vdso_mangle_symbol (const char *symbol)
-{
-  void *vdsop = get_vdso_symbol (symbol);
-  PTR_MANGLE (vdsop);
-  return vdsop;
+  /* Search the scope of the vdso map.  */
+  const ElfW (Sym) *ref = &wsym;
+  lookup_t result = GLRO (dl_lookup_symbol_x) (name, map, &ref,
+       map->l_local_scope,
+       &rfv, 0, 0, NULL);
+  return ref != NULL ? DL_SYMBOL_ADDRESS (result, ref) : NULL;
 }
 
 #endif /* dl-vdso.h */
diff --git a/sysdeps/unix/sysv/linux/init-first.c b/sysdeps/unix/sysv/linux/init-first.c
deleted file mode 100644
index d005d13322..0000000000
--- a/sysdeps/unix/sysv/linux/init-first.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* vDSO internal symbols.  Linux generic version.
-   Copyright (C) 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 <dl-vdso.h>
-#include <libc-vdso.h>
-
-/* vDSO symbol used on clock_gettime implementation.  */
-#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
-int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *)
-  attribute_hidden;
-#endif
-/* vDSO symbol used on clock_gettime64 implementation.  */
-#ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
-int (*VDSO_SYMBOL(clock_gettime64)) (clockid_t, struct __timespec64 *)
-  attribute_hidden;
-#endif
-/* vDSO symbol used on clock_getres implementation.  */
-#ifdef HAVE_CLOCK_GETRES_VSYSCALL
-int (*VDSO_SYMBOL(clock_getres)) (clockid_t, struct timespec *)
-  attribute_hidden;
-#endif
-/* vDSO symbol used on gettimeofday implementation.  */
-#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
-int (*VDSO_SYMBOL (gettimeofday)) (struct timeval *, void *)
-  attribute_hidden;
-#endif
-/* vDSO symbol used on GNU extension getcpu implementation.  */
-#ifdef HAVE_GETCPU_VSYSCALL
-long int (*VDSO_SYMBOL(getcpu)) (unsigned *, unsigned *, void *)
-   attribute_hidden;
-#endif
-/* vDSO symbol used on time implementation.  */
-#ifdef HAVE_TIME_VSYSCALL
-time_t (*VDSO_SYMBOL(time)) (time_t *) attribute_hidden;
-#endif
-
-static inline void
-__libc_vdso_platform_setup (void)
-{
-#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
-  VDSO_SYMBOL(clock_gettime)
-    = get_vdso_mangle_symbol (HAVE_CLOCK_GETTIME_VSYSCALL);
-#endif
-
-#ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
-  VDSO_SYMBOL(clock_gettime64)
-    = get_vdso_mangle_symbol (HAVE_CLOCK_GETTIME64_VSYSCALL);
-#endif
-
-#ifdef HAVE_CLOCK_GETRES_VSYSCALL
-  VDSO_SYMBOL(clock_getres)
-    = get_vdso_mangle_symbol (HAVE_CLOCK_GETRES_VSYSCALL);
-#endif
-
-#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
-  VDSO_SYMBOL(gettimeofday)
-    = get_vdso_mangle_symbol (HAVE_GETTIMEOFDAY_VSYSCALL);
-#endif
-
-#ifdef HAVE_GETCPU_VSYSCALL
-  VDSO_SYMBOL(getcpu) = get_vdso_mangle_symbol (HAVE_GETCPU_VSYSCALL);
-#endif
-
-#ifdef HAVE_TIME_VSYSCALL
-  VDSO_SYMBOL(time) = get_vdso_mangle_symbol (HAVE_TIME_VSYSCALL);
-#endif
-
-#ifdef VDSO_SETUP_ARCH
-  VDSO_SETUP_ARCH ();
-#endif
-}
-
-#define VDSO_SETUP __libc_vdso_platform_setup
-
-#include <csu/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/libc-vdso.h b/sysdeps/unix/sysv/linux/libc-vdso.h
deleted file mode 100644
index c6d505bab3..0000000000
--- a/sysdeps/unix/sysv/linux/libc-vdso.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2009-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
-   <https://www.gnu.org/licenses/>.  */
-
-#ifndef _LIBC_VDSO_H
-#define _LIBC_VDSO_H
-
-#define VDSO_SYMBOL(__name) __vdso_##__name
-
-/* Adjust the return IFUNC value from a vDSO symbol accordingly required
-   by the ELFv1 ABI.  It is used by the architecture to create an ODP
-   entry since the kernel vDSO does not provide it.  */
-#ifndef VDSO_IFUNC_RET
-# define VDSO_IFUNC_RET(__value) (__value)
-#endif
-
-#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
-extern int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *)
-  attribute_hidden;
-#endif
-#ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
-extern int (*VDSO_SYMBOL(clock_gettime64)) (clockid_t, struct __timespec64 *)
-  attribute_hidden;
-#endif
-#ifdef HAVE_CLOCK_GETRES_VSYSCALL
-extern int (*VDSO_SYMBOL(clock_getres)) (clockid_t, struct timespec *)
-  attribute_hidden;
-#endif
-#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
-extern int (*VDSO_SYMBOL (gettimeofday)) (struct timeval *, void *)
-  attribute_hidden;
-#endif
-#ifdef HAVE_GETCPU_VSYSCALL
-extern long int (*VDSO_SYMBOL(getcpu)) (unsigned *, unsigned *, void *)
-  attribute_hidden;
-#endif
-#ifdef HAVE_TIME_VSYSCALL
-extern time_t (*VDSO_SYMBOL(time)) (time_t *) attribute_hidden;
-#endif
-
-#endif /* _LIBC_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/mips/Makefile b/sysdeps/unix/sysv/linux/mips/Makefile
index 03044e7365..026ba242cf 100644
--- a/sysdeps/unix/sysv/linux/mips/Makefile
+++ b/sysdeps/unix/sysv/linux/mips/Makefile
@@ -60,8 +60,6 @@ ifeq ($(subdir),elf)
 ifeq ($(build-shared),yes)
 # This is needed for DSO loading from static binaries.
 sysdep-dl-routines += dl-static
-
-sysdep_routines += dl-vdso
 endif
 # If the compiler doesn't use GNU.stack note,
 # this test is expected to fail.
diff --git a/sysdeps/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile
index 1596238afa..cc2f804d86 100644
--- a/sysdeps/unix/sysv/linux/powerpc/Makefile
+++ b/sysdeps/unix/sysv/linux/powerpc/Makefile
@@ -13,7 +13,6 @@ gen-as-const-headers += ucontext_i.sym
 endif
 
 ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
 ifeq ($(build-shared),yes)
 # This is needed for DSO loading from static binaries.
 sysdep-dl-routines += dl-static
diff --git a/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c b/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c
index 32b9ab5da5..d4afd488f4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c
+++ b/sysdeps/unix/sysv/linux/powerpc/get_timebase_freq.c
@@ -21,7 +21,7 @@
 
 #include <libc-internal.h>
 #include <not-cancel.h>
-#include <libc-vdso.h>
+#include <sysdep-vdso.h>
 
 static uint64_t
 get_timebase_freq_fallback (void)
@@ -101,11 +101,9 @@ uint64_t
 __get_timebase_freq (void)
 {
   /* The vDSO does not have a fallback mechanism (such calling a syscall).  */
-  __typeof (VDSO_SYMBOL (get_tbfreq)) vdsop = VDSO_SYMBOL (get_tbfreq);
-  PTR_DEMANGLE (vdsop);
-  if (vdsop == NULL)
-    return get_timebase_freq_fallback ();
-
-  return INTERNAL_VSYSCALL_CALL_TYPE (vdsop, uint64_t, 0);
+  uint64_t (*vdsop) (void) = GLRO(dl_vdso_get_tbfreq);
+  if (vdsop != NULL)
+    return INTERNAL_VSYSCALL_CALL_TYPE (vdsop, uint64_t, 0);
+  return get_timebase_freq_fallback ();
 }
 weak_alias (__get_timebase_freq, __ppc_get_timebase_freq)
diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
index 1982b1e025..061fa66746 100644
--- a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c
@@ -18,6 +18,7 @@
 #include <time.h>
 #include <sysdep.h>
 #include <sysdep-vdso.h>
+#include <libc-vdso.h>
 
 static int
 __gettimeofday_syscall (struct timeval *restrict tv, void *restrict tz)
@@ -31,17 +32,11 @@ __gettimeofday_syscall (struct timeval *restrict tv, void *restrict tz)
 }
 
 #ifdef SHARED
-# include <dl-vdso.h>
-# include <libc-vdso.h>
-
-# define INIT_ARCH() \
-  void *vdso_gettimeofday = get_vdso_symbol (HAVE_GETTIMEOFDAY_VSYSCALL)
-
+# define INIT_ARCH()
 /* If the vDSO is not available we fall back syscall.  */
-libc_ifunc (__gettimeofday,
-    vdso_gettimeofday
-    ? VDSO_IFUNC_RET (vdso_gettimeofday)
-    : (void *) __gettimeofday_syscall);
+libc_ifunc (__gettimeofday, GLRO(dl_vdso_gettimeofday)
+    ? VDSO_IFUNC_RET (GLRO(dl_vdso_gettimeofday))
+    : (void *) __gettimeofday_syscall);
 #else
 int
 __gettimeofday (struct timeval *restrict tv, void *restrict tz)
diff --git a/sysdeps/unix/sysv/linux/powerpc/init-first.c b/sysdeps/unix/sysv/linux/powerpc/init-first.c
deleted file mode 100644
index 92a4af83af..0000000000
--- a/sysdeps/unix/sysv/linux/powerpc/init-first.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Initialization code run first thing by the ELF startup code.  Linux/PowerPC.
-   Copyright (C) 2007-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
-   <https://www.gnu.org/licenses/>.  */
-
-#include <dl-vdso.h>
-#include <libc-vdso.h>
-
-unsigned long long (*VDSO_SYMBOL(get_tbfreq)) (void) attribute_hidden;
-#if defined(__PPC64__) || defined(__powerpc64__)
-void *VDSO_SYMBOL(sigtramp_rt64) attribute_hidden;
-#else
-void *VDSO_SYMBOL(sigtramp32) attribute_hidden;
-void *VDSO_SYMBOL(sigtramp_rt32) attribute_hidden;
-#endif
-
-static inline void
-__libc_vdso_platform_setup_arch (void)
-{
-  VDSO_SYMBOL (get_tbfreq) = get_vdso_mangle_symbol (HAVE_GET_TBFREQ);
-
-  /* PPC64 uses only one signal trampoline symbol, while PPC32 will use
-     two depending if SA_SIGINFO is used (__kernel_sigtramp_rt32) or not
-     (__kernel_sigtramp32).
-     There is no need to pointer mangle these symbol because they will
-     used only for pointer comparison.  */
-#if defined(__PPC64__) || defined(__powerpc64__)
-  VDSO_SYMBOL(sigtramp_rt64) =  get_vdso_symbol (HAVE_SIGTRAMP_RT64);
-#else
-  VDSO_SYMBOL(sigtramp32) = get_vdso_symbol (HAVE_SIGTRAMP_32);
-  VDSO_SYMBOL(sigtramp_rt32) = get_vdso_symbol (HAVE_SIGTRAMP_RT32);
-#endif
-}
-
-#define VDSO_SETUP_ARCH __libc_vdso_platform_setup_arch
-
-#include <sysdeps/unix/sysv/linux/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/powerpc/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/libc-vdso.h
index cb7da3b289..adc06d48b0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/libc-vdso.h
+++ b/sysdeps/unix/sysv/linux/powerpc/libc-vdso.h
@@ -54,14 +54,4 @@
 # define VDSO_IFUNC_RET(value)  ((void *) (value))
 #endif
 
-#include_next <libc-vdso.h>
-
-extern unsigned long long (*VDSO_SYMBOL(get_tbfreq)) (void);
-#if defined(__PPC64__) || defined(__powerpc64__)
-extern void *VDSO_SYMBOL(sigtramp_rt64);
-#else
-extern void *VDSO_SYMBOL(sigtramp32);
-extern void *VDSO_SYMBOL(sigtramp_rt32);
-#endif
-
 #endif /* _LIBC_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/powerpc/time.c b/sysdeps/unix/sysv/linux/powerpc/time.c
index 2059097c0a..4f90604e6a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/time.c
+++ b/sysdeps/unix/sysv/linux/powerpc/time.c
@@ -19,6 +19,7 @@
 #include <time.h>
 #include <sysdep.h>
 #include <sysdep-vdso.h>
+#include <libc-vdso.h>
 
 static time_t
 time_vsyscall (time_t *t)
@@ -30,18 +31,12 @@ time_vsyscall (time_t *t)
 }
 
 #ifdef SHARED
-# include <dl-vdso.h>
-# include <libc-vdso.h>
-
-# define INIT_ARCH() \
-  void *vdso_time = get_vdso_symbol (HAVE_TIME_VSYSCALL);
-
+#undef INIT_ARCH
+#define INIT_ARCH()
 /* If the vDSO is not available we fall back to the syscall.  */
-libc_ifunc (time,
-    vdso_time
-    ? VDSO_IFUNC_RET (vdso_time)
-    : (void *) time_vsyscall);
-
+libc_ifunc (time, GLRO(dl_vdso_time)
+  ? VDSO_IFUNC_RET (GLRO(dl_vdso_time))
+  : (void *) time_vsyscall)
 #else
 time_t
 time (time_t *t)
diff --git a/sysdeps/unix/sysv/linux/riscv/Makefile b/sysdeps/unix/sysv/linux/riscv/Makefile
index b7ad31885c..301b082398 100644
--- a/sysdeps/unix/sysv/linux/riscv/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/Makefile
@@ -1,7 +1,3 @@
-ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
-endif
-
 ifeq ($(subdir),misc)
 sysdep_headers += sys/cachectl.h
 sysdep_routines += flush-icache
diff --git a/sysdeps/unix/sysv/linux/riscv/flush-icache.c b/sysdeps/unix/sysv/linux/riscv/flush-icache.c
index c5bd60d9c2..e967e40deb 100644
--- a/sysdeps/unix/sysv/linux/riscv/flush-icache.c
+++ b/sysdeps/unix/sysv/linux/riscv/flush-icache.c
@@ -38,7 +38,7 @@ __riscv_flush_icache_syscall (void *start, void *end, unsigned long int flags)
 static func_type
 __lookup_riscv_flush_icache (void)
 {
-  func_type func = get_vdso_symbol ("__vdso_flush_icache");
+  func_type func = dl_vdso_vsym ("__vdso_flush_icache");
 
   /* If there is no vDSO entry then call the system call directly.  All Linux
      versions provide the vDSO entry, but QEMU's user-mode emulation doesn't
diff --git a/sysdeps/unix/sysv/linux/s390/Makefile b/sysdeps/unix/sysv/linux/s390/Makefile
index 77f38523b5..d9db1b5422 100644
--- a/sysdeps/unix/sysv/linux/s390/Makefile
+++ b/sysdeps/unix/sysv/linux/s390/Makefile
@@ -11,10 +11,6 @@ ifeq ($(subdir),stdlib)
 gen-as-const-headers += ucontext_i.sym
 endif
 
-ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
-endif
-
 ifeq ($(subdir),nptl)
 libpthread-sysdep_routines += elision-lock elision-unlock elision-timed \
       elision-trylock
diff --git a/sysdeps/unix/sysv/linux/sparc/Makefile b/sysdeps/unix/sysv/linux/sparc/Makefile
index fb3ee5b8a1..b0d182a439 100644
--- a/sysdeps/unix/sysv/linux/sparc/Makefile
+++ b/sysdeps/unix/sysv/linux/sparc/Makefile
@@ -7,10 +7,6 @@ librt-routines += rt-sysdep
 librt-shared-only-routines += rt-sysdep
 endif
 
-ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
-endif
-
 ifeq ($(subdir),sysvipc)
 sysdep_routines += getshmlba
 endif
diff --git a/sysdeps/unix/sysv/linux/sysdep-vdso.h b/sysdeps/unix/sysv/linux/sysdep-vdso.h
index 04525340a5..76c46bea8a 100644
--- a/sysdeps/unix/sysv/linux/sysdep-vdso.h
+++ b/sysdeps/unix/sysv/linux/sysdep-vdso.h
@@ -19,22 +19,19 @@
 #ifndef SYSDEP_VDSO_LINUX_H
 # define SYSDEP_VDSO_LINUX_H
 
-#include <dl-vdso.h>
+#include <ldsodefs.h>
 
 /* Return the errno value as a negative value in case of an error or 0 or
    positive value otherwise.  */
 #ifndef INTERNAL_VSYSCALL_CALL
-# define INTERNAL_VSYSCALL_CALL(funcptr, nr, args...)     \
-     funcptr (args)
+# define INTERNAL_VSYSCALL_CALL(funcptr, nr, args...)         \
+  funcptr (args)
 #endif
 
-#include <libc-vdso.h>
-
 #define INLINE_VSYSCALL(name, nr, args...)     \
   ({     \
     long int sc_ret = -1;     \
-    __typeof (__vdso_##name) vdsop = __vdso_##name;     \
-    PTR_DEMANGLE (vdsop);     \
+    __typeof (GLRO(dl_vdso_##name)) vdsop = GLRO(dl_vdso_##name);     \
     if (vdsop != NULL)     \
       {     \
  sc_ret = INTERNAL_VSYSCALL_CALL (vdsop, nr, ##args);         \
diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile
index 02ca36c6d2..b23b532590 100644
--- a/sysdeps/unix/sysv/linux/x86/Makefile
+++ b/sysdeps/unix/sysv/linux/x86/Makefile
@@ -20,10 +20,6 @@ CFLAGS-elision-timed.c += -mrtm
 CFLAGS-elision-trylock.c += -mrtm
 endif
 
-ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso
-endif
-
 ifeq ($(subdir),setjmp)
 tests += tst-saved_mask-1
 endif
diff --git a/sysdeps/unix/sysv/linux/x86/gettimeofday.c b/sysdeps/unix/sysv/linux/x86/gettimeofday.c
index 909575a7e3..f7579ac924 100644
--- a/sysdeps/unix/sysv/linux/x86/gettimeofday.c
+++ b/sysdeps/unix/sysv/linux/x86/gettimeofday.c
@@ -32,13 +32,10 @@ __gettimeofday_syscall (struct timeval *restrict tv, void *restrict tz)
 }
 
 #ifdef SHARED
-# include <dl-vdso.h>
-# include <libc-vdso.h>
-
 # define INIT_ARCH()
 /* If the vDSO is not available we fall back to syscall.  */
 libc_ifunc (__gettimeofday,
-    (get_vdso_symbol (HAVE_GETTIMEOFDAY_VSYSCALL)
+    (GLRO(dl_vdso_gettimeofday)
     ?: __gettimeofday_syscall));
 
 #else
diff --git a/sysdeps/unix/sysv/linux/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c
index 0aee73826b..c65f2d5d54 100644
--- a/sysdeps/unix/sysv/linux/x86/time.c
+++ b/sysdeps/unix/sysv/linux/x86/time.c
@@ -30,13 +30,10 @@ time_vsyscall (time_t *t)
 }
 
 #ifdef SHARED
-# include <dl-vdso.h>
-# include <libc-vdso.h>
-
 #undef INIT_ARCH
 #define INIT_ARCH()
 /* If the vDSO is not available we fall back on the syscall.  */
-libc_ifunc (time, (get_vdso_symbol ("__vdso_time") ?: time_vsyscall))
+libc_ifunc (time, (GLRO(dl_vdso_time) ?: time_vsyscall))
 #else
 time_t
 time (time_t *t)
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 08/12] Add support for clock_gettime64 vDSO

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
No architecture currently defines the vDSO symbol.
---
 sysdeps/unix/sysv/linux/clock_gettime.c | 12 ++++++++++--
 sysdeps/unix/sysv/linux/dl-vdso-setup.c |  4 ++++
 sysdeps/unix/sysv/linux/dl-vdso-setup.h |  3 +++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
index 4ea56c9a4b..43e378aa83 100644
--- a/sysdeps/unix/sysv/linux/clock_gettime.c
+++ b/sysdeps/unix/sysv/linux/clock_gettime.c
@@ -34,7 +34,11 @@ __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
 #ifdef __ASSUME_TIME64_SYSCALLS
   /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
 # ifdef __NR_clock_gettime64
-  r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
+#  ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
+  r = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
+#  endif
+  if (r == -1)
+    r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
 # else
 #  ifdef HAVE_CLOCK_GETTIME_VSYSCALL
   r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
@@ -45,7 +49,11 @@ __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
 #else
   /* Old 32-bit ABI with possible 64-bit time_t support.  */
 # ifdef __NR_clock_gettime64
-  r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
+#  ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
+  r = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
+#  endif
+  if (r == -1)
+    r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
 # endif
   if (r == -1)
     {
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.c b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
index 1069879f1a..d19a4af6c1 100644
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.c
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
@@ -45,6 +45,10 @@
 PROCINFO_CLASS int (*_dl_vdso_clock_gettime) (clockid_t,
       struct timespec *) RELRO;
 #endif
+# ifdef HAVE_CLOCK_GETTIME_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_clock_gettime64) (clockid_t,
+ struct __timespec64 *) RELRO;
+#endif
 # ifdef HAVE_GETTIMEOFDAY_VSYSCALL
 PROCINFO_CLASS int (*_dl_vdso_gettimeofday) (struct timeval *, void *) RELRO;
 #endif
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.h b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
index f4e76202fc..8a89e100c8 100644
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.h
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
@@ -26,6 +26,9 @@ setup_vdso_pointers (void)
 #ifdef HAVE_CLOCK_GETTIME_VSYSCALL
   GLRO(dl_vdso_clock_gettime) = dl_vdso_vsym (HAVE_CLOCK_GETTIME_VSYSCALL);
 #endif
+#ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
+  GLRO(dl_vdso_clock_gettime64) = dl_vdso_vsym (HAVE_CLOCK_GETTIME64_VSYSCALL);
+#endif
 #ifdef HAVE_GETTIMEOFDAY_VSYSCALL
   GLRO(dl_vdso_gettimeofday) = dl_vdso_vsym (HAVE_GETTIMEOFDAY_VSYSCALL);
 #endif
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 09/12] Enable vDSO clock_gettime64 for i386

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
It was added on Linux 5.3 (commit 22ca962288c0a).

Checked on i686-linux-gnu with 5.3.0 kernel.
---
 sysdeps/unix/sysv/linux/i386/sysdep.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index b2e750d490..5156587d95 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
@@ -314,6 +314,7 @@ struct libc_do_syscall_args
 
 /* List of system calls which are supported as vsyscalls.  */
 # define HAVE_CLOCK_GETTIME_VSYSCALL    "__vdso_clock_gettime"
+# define HAVE_CLOCK_GETTIME64_VSYSCALL  "__vdso_clock_gettime64"
 # define HAVE_GETTIMEOFDAY_VSYSCALL     "__vdso_gettimeofday"
 # define HAVE_TIME_VSYSCALL             "__vdso_time"
 # define HAVE_CLOCK_GETRES_VSYSCALL     "__vdso_clock_getres"
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 10/12] Enable vDSO clock_gettime64 for arm

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
It was added on Linux 5.5 (commit 74d06efb9c2f9).
---
 sysdeps/unix/sysv/linux/arm/sysdep.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sysdeps/unix/sysv/linux/arm/sysdep.h b/sysdeps/unix/sysv/linux/arm/sysdep.h
index e9e022e037..b5ef17d1a8 100644
--- a/sysdeps/unix/sysv/linux/arm/sysdep.h
+++ b/sysdeps/unix/sysv/linux/arm/sysdep.h
@@ -393,6 +393,7 @@ __local_syscall_error: \
 
 /* List of system calls which are supported as vsyscalls.  */
 #define HAVE_CLOCK_GETTIME_VSYSCALL "__vdso_clock_gettime"
+#define HAVE_CLOCK_GETTIME64_VSYSCALL "__vdso_clock_gettime64"
 #define HAVE_GETTIMEOFDAY_VSYSCALL "__vdso_gettimeofday"
 
 #define LOAD_ARGS_0()
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 11/12] Enable vDSO clock_gettime64 for mips

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
It was added on Linux 5.4 (commit 1f66c45db3302).
---
 sysdeps/unix/sysv/linux/mips/sysdep.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sysdeps/unix/sysv/linux/mips/sysdep.h b/sysdeps/unix/sysv/linux/mips/sysdep.h
index defad8eb62..1705a64157 100644
--- a/sysdeps/unix/sysv/linux/mips/sysdep.h
+++ b/sysdeps/unix/sysv/linux/mips/sysdep.h
@@ -16,10 +16,15 @@
    License along with the GNU C Library.  If not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sgidefs.h>
+
 #define VDSO_NAME  "LINUX_2.6"
 #define VDSO_HASH  61765110
 
 /* List of system calls which are supported as vsyscalls.  */
 #define HAVE_CLOCK_GETTIME_VSYSCALL     "__vdso_clock_gettime"
+#if _MIPS_SIM != _ABI64
+#define HAVE_CLOCK_GETTIME64_VSYSCALL   "__vdso_clock_gettime64"
+#endif
 #define HAVE_GETTIMEOFDAY_VSYSCALL      "__vdso_gettimeofday"
 #define HAVE_CLOCK_GETRES_VSYSCALL      "__vdso_clock_getres"
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

[PATCH 12/12] Add support for clock_getres64 vDSO

Adhemerval Zanella-2
In reply to this post by Adhemerval Zanella-2
No architecture currently defines the vDSO symbol.
---
 sysdeps/unix/sysv/linux/clock_getres.c  | 12 ++++++++++--
 sysdeps/unix/sysv/linux/dl-vdso-setup.c |  4 ++++
 sysdeps/unix/sysv/linux/dl-vdso-setup.h |  3 +++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c
index 6c12f1d1e9..39481afe22 100644
--- a/sysdeps/unix/sysv/linux/clock_getres.c
+++ b/sysdeps/unix/sysv/linux/clock_getres.c
@@ -33,7 +33,11 @@ __clock_getres64 (clockid_t clock_id, struct __timespec64 *res)
 #ifdef __ASSUME_TIME64_SYSCALLS
   /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
 # ifdef __NR_clock_getres_time64
-  r = INLINE_SYSCALL_CALL (clock_getres_time64, clock_id, res);
+#  ifdef HAVE_CLOCK_GETRES64_VSYSCALL
+  r = INLINE_VSYSCALL (clock_getres64, 2, clock_id, tp)
+#  endif
+  if (r == -1)
+    r = INLINE_SYSCALL_CALL (clock_getres_time64, clock_id, res);
 # else
 #  ifdef HAVE_CLOCK_GETRES_VSYSCALL
   r = INLINE_VSYSCALL (clock_getres, 2, clock_id, res);
@@ -44,7 +48,11 @@ __clock_getres64 (clockid_t clock_id, struct __timespec64 *res)
 #else
   /* Old 32-bit ABI with possible 64-bit time_t support.  */
 # ifdef __NR_clock_getres_time64
-  r = INLINE_SYSCALL_CALL (clock_getres_time64, clock_id, res);
+#  ifdef HAVE_CLOCK_GETRES64_VSYSCALL
+  r = INLINE_VSYSCALL (clock_getres64, 2, clock_id, tp)
+#  endif
+  if (r == -1)
+    r = INLINE_SYSCALL_CALL (clock_getres_time64, clock_id, res);
 # endif
   if (r == -1)
     {
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.c b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
index d19a4af6c1..620348e2c7 100644
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.c
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
@@ -62,6 +62,10 @@ PROCINFO_CLASS int (*_dl_vdso_getcpu) (unsigned *, unsigned *, void *) RELRO;
 PROCINFO_CLASS int (*_dl_vdso_clock_getres) (clockid_t,
      struct timespec *) RELRO;
 # endif
+# ifdef HAVE_CLOCK_GETRES64_VSYSCALL
+PROCINFO_CLASS int (*_dl_vdso_clock_getres64) (clockid_t,
+       struct __timespec64 *) RELRO;
+# endif
 
 /* PowerPC specific ones.  */
 # ifdef HAVE_GET_TBFREQ
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.h b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
index 8a89e100c8..005acf15f7 100644
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.h
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
@@ -41,6 +41,9 @@ setup_vdso_pointers (void)
 #ifdef HAVE_CLOCK_GETRES_VSYSCALL
   GLRO(dl_vdso_clock_getres) = dl_vdso_vsym (HAVE_CLOCK_GETRES_VSYSCALL);
 #endif
+#ifdef HAVE_CLOCK_GETRES64_VSYSCALL
+  GLRO(dl_vdso_clock_getres64) = dl_vdso_vsym (HAVE_CLOCK_GETRES64_VSYSCALL);
+#endif
 #ifdef HAVE_GET_TBFREQ
   GLRO(dl_vdso_get_tbfreq) = dl_vdso_vsym (HAVE_GET_TBFREQ);
 #endif
--
2.17.1

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 01/12] linux: Fix vDSO macros build with time64 interfaces

Florian Weimer-5
In reply to this post by Adhemerval Zanella-2
* Adhemerval Zanella:

> diff --git a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
> index 7e772e05ce..07d38466e2 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
> +++ b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
> @@ -22,10 +22,6 @@
>  
>  #include <time.h>
>  #include <sysdep.h>
> -
> -#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
> -# define HAVE_VSYSCALL
> -#endif
>  #include <sysdep-vdso.h>
>  
>  /* Used as a fallback in the ifunc resolver if VDSO is not available
> @@ -36,7 +32,9 @@ __gettimeofday_vsyscall (struct timeval *restrict tv, void *restrict tz)
>    if (__glibc_unlikely (tz != 0))
>      memset (tz, 0, sizeof *tz);
>  
> -  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
> +  if (INLINE_VSYSCALL (gettimeofday, 2, tv, tz) == 0)
> +    return 0;
> +  return INLINE_SYSCALL_CALL (gettimeofday, tv, tz);
>  }

Given that this is the fallback function why do we try INLINE_VSYSCALL
first?

(The static case would need adjusting, of course.)

> diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
> index 875c4fe905..4ea56c9a4b 100644
> --- a/sysdeps/unix/sysv/linux/clock_gettime.c
> +++ b/sysdeps/unix/sysv/linux/clock_gettime.c
> @@ -21,10 +21,6 @@
>  #include <errno.h>
>  #include <time.h>
>  #include "kernel-posix-cpu-timers.h"
> -
> -#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
> -# define HAVE_VSYSCALL
> -#endif
>  #include <sysdep-vdso.h>
>  
>  #include <shlib-compat.h>
> @@ -33,24 +29,39 @@
>  int
>  __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
>  {
> +  int r = -1;
> +
>  #ifdef __ASSUME_TIME64_SYSCALLS
> +  /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
> +# ifdef __NR_clock_gettime64
> +  r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
> +# else
> +#  ifdef HAVE_CLOCK_GETTIME_VSYSCALL
> +  r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
> +#  endif
> +  if (r == -1)
> +    r = INLINE_SYSCALL_CALL (clock_gettime, clock_id, tp);

Why do you check __NR_clock_gettime64 first?  Won't this make the vDSO
unused?

Thanks,
Florian

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 01/12] linux: Fix vDSO macros build with time64 interfaces

Adhemerval Zanella-2


On 13/12/2019 08:51, Florian Weimer wrote:

> * Adhemerval Zanella:
>
>> diff --git a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>> index 7e772e05ce..07d38466e2 100644
>> --- a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>> +++ b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>> @@ -22,10 +22,6 @@
>>  
>>  #include <time.h>
>>  #include <sysdep.h>
>> -
>> -#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
>> -# define HAVE_VSYSCALL
>> -#endif
>>  #include <sysdep-vdso.h>
>>  
>>  /* Used as a fallback in the ifunc resolver if VDSO is not available
>> @@ -36,7 +32,9 @@ __gettimeofday_vsyscall (struct timeval *restrict tv, void *restrict tz)
>>    if (__glibc_unlikely (tz != 0))
>>      memset (tz, 0, sizeof *tz);
>>  
>> -  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
>> +  if (INLINE_VSYSCALL (gettimeofday, 2, tv, tz) == 0)
>> +    return 0;
>> +  return INLINE_SYSCALL_CALL (gettimeofday, tv, tz);
>>  }
>
> Given that this is the fallback function why do we try INLINE_VSYSCALL
> first?
>
> (The static case would need adjusting, of course.)

Because it will be used on static build and the fallback case will be
unlikely. But I can add static only case that uses vDSO plus syscall and
change the shared fallback case that just issues the syscall.

My idea is to eventually consolidate the aarch64/powerpc64/x86_64
gettimeofday implementation, since they are essentially the same.

>
>> diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
>> index 875c4fe905..4ea56c9a4b 100644
>> --- a/sysdeps/unix/sysv/linux/clock_gettime.c
>> +++ b/sysdeps/unix/sysv/linux/clock_gettime.c
>> @@ -21,10 +21,6 @@
>>  #include <errno.h>
>>  #include <time.h>
>>  #include "kernel-posix-cpu-timers.h"
>> -
>> -#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
>> -# define HAVE_VSYSCALL
>> -#endif
>>  #include <sysdep-vdso.h>
>>  
>>  #include <shlib-compat.h>
>> @@ -33,24 +29,39 @@
>>  int
>>  __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
>>  {
>> +  int r = -1;
>> +
>>  #ifdef __ASSUME_TIME64_SYSCALLS
>> +  /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
>> +# ifdef __NR_clock_gettime64
>> +  r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
>> +# else
>> +#  ifdef HAVE_CLOCK_GETTIME_VSYSCALL
>> +  r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
>> +#  endif
>> +  if (r == -1)
>> +    r = INLINE_SYSCALL_CALL (clock_gettime, clock_id, tp);
>
> Why do you check __NR_clock_gettime64 first?  Won't this make the vDSO
> unused?

The vDSO support for clock_gettime64 was added later in this set. I
explicit removed because even if an architecture sets
HAVE_CLOCK_GETTIME64_VSYSCALL, it won't build.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 06/12] elf: Enable relro for static build

Florian Weimer-5
In reply to this post by Adhemerval Zanella-2
* Adhemerval Zanella:

> +static volatile int val __attribute__ ((section (".data.rel.ro")));

I would prefer something that needs an actual run-time relocation
because I doubt that all targets use .data.rel.ro.

> +int do_test (void)
> +{
> +  struct support_capture_subprocess result
> +    = support_capture_subprocess (callback, NULL);
> +  support_capture_subprocess_check (&result, "tst-relro", -SIGSEGV,
> +    sc_allow_stdout);
> +  return 0;
> +}

My test <https://sourceware.org/ml/libc-alpha/2019-10/msg00130.html>
used a new support/ helper for that.

Thanks,
Florian

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 07/12] elf: Move vDSO setup to rtld (BZ#24967)

Florian Weimer-5
In reply to this post by Adhemerval Zanella-2
* Adhemerval Zanella:

> diff --git a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
> index 07d38466e2..6475840117 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
> +++ b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
> @@ -38,12 +38,9 @@ __gettimeofday_vsyscall (struct timeval *restrict tv, void *restrict tz)
>  }
>  
>  #ifdef SHARED
> -# include <dl-vdso.h>
> -# include <sysdep-vdso.h>
> -
>  # define INIT_ARCH()
>  libc_ifunc (__gettimeofday,
> -    (get_vdso_symbol (HAVE_GETTIMEOFDAY_VSYSCALL)
> +    (GLRO(dl_vdso_gettimeofday)
>      ?: __gettimeofday_vsyscall))

This IFUNC resolver is still not valid because _rtld_global_ro has a
relocation dependency.

What we should do instead is to patch the vDSO function pointers (and
pretty much all shared variables, including the page size) into
libc.so.6 right after loading it (before relocation).  I had hoped to
post a patch for this, but the prerequisite

  <https://sourceware.org/ml/libc-alpha/2019-11/msg00977.html>

has not been reviewed.  It provides _dl_lookup_direct, which we could
use to get access to this global variables structure very efficiently.

Thanks,
Florian

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 06/12] elf: Enable relro for static build

Adhemerval Zanella-2
In reply to this post by Florian Weimer-5


On 13/12/2019 09:08, Florian Weimer wrote:

> * Adhemerval Zanella:
>
>> +static volatile int val __attribute__ ((section (".data.rel.ro")));
>
> I would prefer something that needs an actual run-time relocation
> because I doubt that all targets use .data.rel.ro.
>
>> +int do_test (void)
>> +{
>> +  struct support_capture_subprocess result
>> +    = support_capture_subprocess (callback, NULL);
>> +  support_capture_subprocess_check (&result, "tst-relro", -SIGSEGV,
>> +    sc_allow_stdout);
>> +  return 0;
>> +}
>
> My test <https://sourceware.org/ml/libc-alpha/2019-10/msg00130.html>
> used a new support/ helper for that.

Alright, we can use these tests instead. I can update my patch to remove
them.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 07/12] elf: Move vDSO setup to rtld (BZ#24967)

Adhemerval Zanella-2
In reply to this post by Florian Weimer-5


On 13/12/2019 09:12, Florian Weimer wrote:

> * Adhemerval Zanella:
>
>> diff --git a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>> index 07d38466e2..6475840117 100644
>> --- a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>> +++ b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>> @@ -38,12 +38,9 @@ __gettimeofday_vsyscall (struct timeval *restrict tv, void *restrict tz)
>>  }
>>  
>>  #ifdef SHARED
>> -# include <dl-vdso.h>
>> -# include <sysdep-vdso.h>
>> -
>>  # define INIT_ARCH()
>>  libc_ifunc (__gettimeofday,
>> -    (get_vdso_symbol (HAVE_GETTIMEOFDAY_VSYSCALL)
>> +    (GLRO(dl_vdso_gettimeofday)
>>      ?: __gettimeofday_vsyscall))
>
> This IFUNC resolver is still not valid because _rtld_global_ro has a
> relocation dependency.

Afaik with current ld guaranties, .rel{a}.dyn will be sort prior ifunc
so _rtld_global_ro should be reallocated prior the ifunc itself.

>
> What we should do instead is to patch the vDSO function pointers (and
> pretty much all shared variables, including the page size) into
> libc.so.6 right after loading it (before relocation).  I had hoped to
> post a patch for this, but the prerequisite
>
>   <https://sourceware.org/ml/libc-alpha/2019-11/msg00977.html>
>
> has not been reviewed.  It provides _dl_lookup_direct, which we could
> use to get access to this global variables structure very efficiently.

We can go on this way (which is a rather complex solution with might add
even more pitfalls). However another much simple possibility is to make
gettimeoday and time use normal function that calls the vDSO directly.  
On x86_64 haswell (i7-4790K) I see just 7% increase of latency to by
using INLINE_VSYSCALL with my patch, which I think it quite acceptable.


Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 07/12] elf: Move vDSO setup to rtld (BZ#24967)

Florian Weimer-5
* Adhemerval Zanella:

>> This IFUNC resolver is still not valid because _rtld_global_ro has a
>> relocation dependency.
>
> Afaik with current ld guaranties, .rel{a}.dyn will be sort prior ifunc
> so _rtld_global_ro should be reallocated prior the ifunc itself.

But that's intra-DSO.  It does not necessarily affect cross-DSO
relocation ordering.  In theory, the DT_NEEDED ordering should make this
work, except for the static dlopen case, where you get a
default-initialized _rtld_global_ro from the inactive (inner) loader.
The latter is why some architectures use _dl_var_init for essential
non-loader data, and why getauxval is currently broken for something
that is dlopen'ed from a statically linked program (bug 20802).

>> What we should do instead is to patch the vDSO function pointers (and
>> pretty much all shared variables, including the page size) into
>> libc.so.6 right after loading it (before relocation).  I had hoped to
>> post a patch for this, but the prerequisite
>>
>>   <https://sourceware.org/ml/libc-alpha/2019-11/msg00977.html>
>>
>> has not been reviewed.  It provides _dl_lookup_direct, which we could
>> use to get access to this global variables structure very efficiently.
>
> We can go on this way (which is a rather complex solution with might add
> even more pitfalls). However another much simple possibility is to make
> gettimeoday and time use normal function that calls the vDSO directly.  
> On x86_64 haswell (i7-4790K) I see just 7% increase of latency to by
> using INLINE_VSYSCALL with my patch, which I think it quite acceptable.

It's not more complex overall because we already need _dl_var_init on
some architectures.  This new mechanism would replace that and do away
with undo-RELRO/_dl_var_init/reapply-RELRO sequence.

Thanks,
Florian

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 01/12] linux: Fix vDSO macros build with time64 interfaces

Florian Weimer-5
In reply to this post by Adhemerval Zanella-2
* Adhemerval Zanella:

> On 13/12/2019 08:51, Florian Weimer wrote:
>> * Adhemerval Zanella:
>>
>>> diff --git a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>>> index 7e772e05ce..07d38466e2 100644
>>> --- a/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>>> +++ b/sysdeps/unix/sysv/linux/aarch64/gettimeofday.c
>>> @@ -22,10 +22,6 @@
>>>  
>>>  #include <time.h>
>>>  #include <sysdep.h>
>>> -
>>> -#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
>>> -# define HAVE_VSYSCALL
>>> -#endif
>>>  #include <sysdep-vdso.h>
>>>  
>>>  /* Used as a fallback in the ifunc resolver if VDSO is not available
>>> @@ -36,7 +32,9 @@ __gettimeofday_vsyscall (struct timeval *restrict tv, void *restrict tz)
>>>    if (__glibc_unlikely (tz != 0))
>>>      memset (tz, 0, sizeof *tz);
>>>  
>>> -  return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
>>> +  if (INLINE_VSYSCALL (gettimeofday, 2, tv, tz) == 0)
>>> +    return 0;
>>> +  return INLINE_SYSCALL_CALL (gettimeofday, tv, tz);
>>>  }
>>
>> Given that this is the fallback function why do we try INLINE_VSYSCALL
>> first?
>>
>> (The static case would need adjusting, of course.)
>
> Because it will be used on static build and the fallback case will be
> unlikely. But I can add static only case that uses vDSO plus syscall and
> change the shared fallback case that just issues the syscall.

I think that would make more sense, yes.

>>> diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
>>> index 875c4fe905..4ea56c9a4b 100644
>>> --- a/sysdeps/unix/sysv/linux/clock_gettime.c
>>> +++ b/sysdeps/unix/sysv/linux/clock_gettime.c
>>> @@ -21,10 +21,6 @@
>>>  #include <errno.h>
>>>  #include <time.h>
>>>  #include "kernel-posix-cpu-timers.h"
>>> -
>>> -#ifdef HAVE_CLOCK_GETTIME_VSYSCALL
>>> -# define HAVE_VSYSCALL
>>> -#endif
>>>  #include <sysdep-vdso.h>
>>>  
>>>  #include <shlib-compat.h>
>>> @@ -33,24 +29,39 @@
>>>  int
>>>  __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
>>>  {
>>> +  int r = -1;
>>> +
>>>  #ifdef __ASSUME_TIME64_SYSCALLS
>>> +  /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
>>> +# ifdef __NR_clock_gettime64
>>> +  r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
>>> +# else
>>> +#  ifdef HAVE_CLOCK_GETTIME_VSYSCALL
>>> +  r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
>>> +#  endif
>>> +  if (r == -1)
>>> +    r = INLINE_SYSCALL_CALL (clock_gettime, clock_id, tp);
>>
>> Why do you check __NR_clock_gettime64 first?  Won't this make the vDSO
>> unused?
>
> The vDSO support for clock_gettime64 was added later in this set. I
> explicit removed because even if an architecture sets
> HAVE_CLOCK_GETTIME64_VSYSCALL, it won't build.

Ah, I see it now:

  /* Get current value of CLOCK and store it in TP.  */
  int
  __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
  {
    int r = -1;
 
  #ifdef __ASSUME_TIME64_SYSCALLS
    /* 64 bit ABIs or Newer 32-bit ABIs that only support 64-bit time_t.  */
  # ifdef __NR_clock_gettime64
  #  ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
    r = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
  #  endif
    if (r == -1)
      r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
  # else
  #  ifdef HAVE_CLOCK_GETTIME_VSYSCALL
    r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp);
  #  endif
    if (r == -1)
      r = INLINE_SYSCALL_CALL (clock_gettime, clock_id, tp);
  # endif
  #else
    /* Old 32-bit ABI with possible 64-bit time_t support.  */
  # ifdef __NR_clock_gettime64
  #  ifdef HAVE_CLOCK_GETTIME64_VSYSCALL
    r = INLINE_VSYSCALL (clock_gettime64, 2, clock_id, tp);
  #  endif
    if (r == -1)
      r = INLINE_SYSCALL_CALL (clock_gettime64, clock_id, tp);
  # endif
    if (r == -1)
      {
        /* Fallback code that uses 32-bit support.  */
        struct timespec tp32;
  # ifdef HAVE_CLOCK_GETTIME_VSYSCALL
        r = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &tp32);
  # endif
        if (r == -1)
  r = INLINE_SYSCALL_CALL (clock_gettime, clock_id, &tp32);
        if (r == 0)
  *tp = valid_timespec_to_timespec64 (tp32);
      }
  #endif
 
    return r;
  }

This looks quite ugly to me.

If I read it correctly, it still does not cover for 32-bit the case of
an old kernel without clock_gettime64 support.  Here, INLINE_VSYSCALL
for clock_gettimeofday64 will fail (without a context switch), then
INLINE_SYSCALL_CALL will fail, *with* a context switch, and only then,
and only then the INLINE_VSYSCALL call for clock_gettimeofday will
suceed.

Since this is used to implement clock_gettime:

  #if __TIMESIZE != 64
  int
  __clock_gettime (clockid_t clock_id, struct timespec *tp)
  {
    int ret;
    struct __timespec64 tp64;
 
    ret = __clock_gettime64 (clock_id, &tp64);
 
    if (ret == 0)
      {
        if (! in_time_t_range (tp64.tv_sec))
          {
            __set_errno (EOVERFLOW);
            return -1;
          }
 
        *tp = valid_timespec64_to_timespec (tp64);
      }
 
    return ret;
  }
  #endif

it will impact quite a lot of installations.  We know that
clock_gettimeofday performance is critical to many users, eveon i386.

The main question is whether it is worth supporting clock_gettime64
without vDSO support.  If it is not, at startup, the loader should
select a function pointer for the clock_gettime64 implementation used by
the clock_gettime64 wrapper:

  (a) kernel-provided clock_gettime64 from the vDSO
  (b) glibc clock_gettime64 implementation on top of clock_gettime vDSO
  (c) glibc clock_gettime64 implementation on top of clock_gettime syscall

Checking the presence of vDSO symbols is reasonably efficient because
it's just a hash table lookup (especially if _dl_lookup_direct is used).
We would have two indirect calls for the legacy vDSO case, but getting
rid of that would mean to use an IFUNC for clock_gettime and
clock_gettime64, driving up complexity again.

Unfortunately, writing (b) and (c) may not be easy on architectures
where INTERNAL_VSYSCALL_CALL uses a non-standard calling convention with
inline assembly, due to lack of proper GCC support for it.

If we need to support systems without clock_gettime64 in the vDSO, we
have a problem because that requires system call probing, which is
probably not something that we want to do at startup.

Thanks,
Florian

12