syscalls.list support for vDSO IFUNCs, use it for x32 gettimeofday and time.
authorRoland McGrath <roland@hack.frob.com>
Tue, 22 May 2012 23:00:50 +0000 (16:00 -0700)
committerRoland McGrath <roland@hack.frob.com>
Thu, 24 May 2012 20:13:46 +0000 (13:13 -0700)
ChangeLog
Makeconfig
Makerules
sysdeps/unix/make-syscalls.sh
sysdeps/unix/sysv/linux/dl-vdso.h
sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list

index 7c94fce..983ffe6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2012-05-24  Roland McGrath  <roland@hack.frob.com>
 
+       * sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list: New file.
+
+       * sysdeps/unix/make-syscalls.sh: Support "syscall:vdso_name@VDSOVER"
+       in the third column, to generate for the shared library an IFUNC
+       that uses _dl_vdso_vsym.
+       * Makerules (COMPILE.c, compile-stdin.c): New variables.
+       * Makeconfig (object-suffixes-noshared): New variable.
+
+       * sysdeps/unix/sysv/linux/dl-vdso.h (PREPARE_VERSION_KNOWN): New macro.
+       (VDSO_NAME_LINUX_2_6, VDSO_HASH_LINUX_2_6): New macros.
+       (VDSO_NAME_LINUX_2_6_15, VDSO_HASH_LINUX_2_6_15): New macros.
+       (VDSO_NAME_LINUX_2_6_29, VDSO_HASH_LINUX_2_6_29): New macros.
+
        [BZ #14132]
        * include/sys/time.h (__gettimeofday): Remove macro.
        (__gettimeofday, gettimeofday): Add libc_hidden_proto.
index 3a09764..b4b2963 100644 (file)
@@ -720,6 +720,10 @@ CFLAGS-.op = -pg
 libtype.op = lib%_p.a
 endif
 
+# Convenience variable for when we want to treat shared-library cases
+# differently from the rest.
+object-suffixes-noshared := $(filter-out .os,$(object-suffixes))
+
 bppfx = BP-
 ifeq (yes,$(build-bounded))
 # Under --enable-bounded, we build the library with `-fbounded-pointers -g'
index 0fd1b5b..685b1b8 100644 (file)
--- a/Makerules
+++ b/Makerules
@@ -366,6 +366,7 @@ compile.c = $(CC) $< -c $(CFLAGS) $(CPPFLAGS)
 compile.cc = $(CXX) $< -c $(CXXFLAGS) $(CPPFLAGS)
 compile.S = $(CC) $< -c $(CPPFLAGS) $(S-CPPFLAGS) \
                  $(ASFLAGS) $(ASFLAGS-$(suffix $@))
+COMPILE.c = $(CC) -c $(CFLAGS) $(CPPFLAGS)
 COMPILE.S = $(CC) -c $(CPPFLAGS) $(S-CPPFLAGS) \
                  $(ASFLAGS) $(ASFLAGS-$(suffix $@))
 
@@ -374,6 +375,9 @@ COMPILE.S = $(CC) -c $(CPPFLAGS) $(S-CPPFLAGS) \
 # together.  You can't compile the C library with such a compiler.
 OUTPUT_OPTION = -o $@
 
+# This is the end of the pipeline for compiling generated C code.
+compile-stdin.c = $(COMPILE.c) -o $@ -x c - $(compile-mkdep-flags)
+
 # We need the $(CFLAGS) to be in there to have the right predefines during
 # the dependency run for C sources.  But having it for assembly sources can
 # get the wrong predefines.
index 48aab62..cedce31 100644 (file)
@@ -64,10 +64,67 @@ done`
 # Any calls left?
 test -n "$calls" || exit 0
 
+# This uses variables $weak and $strong.
+emit_weak_aliases()
+{
+  # A shortcoming in the current gas is that it will only allow one
+  # version-alias per symbol.  So we create new strong aliases as needed.
+  vcount=""
+
+  for name in $weak; do
+    case $name in
+      *@@*)
+       base=`echo $name | sed 's/@@.*//'`
+       ver=`echo $name | sed 's/.*@@//'`
+       if test -z "$vcount" ; then
+         source=$strong
+         vcount=1
+       else
+         source="${strong}_${vcount}"
+         vcount=`expr $vcount + 1`
+         echo "         echo 'strong_alias ($strong, $source)'; \\"
+       fi
+       echo "   echo 'default_symbol_version($source, $base, $ver)'; \\"
+       ;;
+      *@*)
+       base=`echo $name | sed 's/@.*//'`
+       ver=`echo $name | sed 's/.*@//'`
+       if test -z "$vcount" ; then
+         source=$strong
+         vcount=1
+       else
+         source="${strong}_${vcount}"
+         vcount=`expr $vcount + 1`
+         echo "         echo 'strong_alias ($strong, $source)'; \\"
+       fi
+       echo "   echo 'symbol_version ($source, $base, $ver)'; \\"
+       ;;
+      !*)
+       name=`echo $name | sed 's/.//'`
+       echo "   echo 'strong_alias ($strong, $name)'; \\"
+       echo "   echo 'libc_hidden_def ($name)'; \\"
+       ;;
+      *)
+       echo "   echo 'weak_alias ($strong, $name)'; \\"
+       echo "   echo 'libc_hidden_weak ($name)'; \\"
+       ;;
+    esac
+  done
+}
+
+
 # Emit rules to compile the syscalls remaining in $calls.
 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=_ ;;
   *)
@@ -144,13 +201,14 @@ while read file srcfile caller syscall args strong weak; do
   # Emit a compilation rule for this syscall.
   if test $shared_only = t; then
     # The versioned symbols are only in the shared library.
-    echo "\
-shared-only-routines += $file
-\$(objpfx)${file}.os: \\"
+    echo "shared-only-routines += $file"
+    test -n "$vdso_syscall" || 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)): \\"
+\$(foreach o,${object_suffixes},\$(objpfx)\$(patsubst %,\$p,$file)\$o)): \\"
   fi
 
   echo "               \$(..)sysdeps/unix/make-syscalls.sh"
@@ -178,55 +236,43 @@ shared-only-routines += $file
   esac
 
   # Append any weak aliases or versions defined for this syscall function.
-
-  # A shortcoming in the current gas is that it will only allow one
-  # version-alias per symbol.  So we create new strong aliases as needed.
-  vcount=""
-
-  for name in $weak; do
-    case $name in
-      *@@*)
-       base=`echo $name | sed 's/@@.*//'`
-       ver=`echo $name | sed 's/.*@@//'`
-       if test -z "$vcount" ; then
-         source=$strong
-         vcount=1
-       else
-         source="${strong}_${vcount}"
-         vcount=`expr $vcount + 1`
-         echo "         echo 'strong_alias ($strong, $source)'; \\"
-       fi
-       echo "   echo 'default_symbol_version($source, $base, $ver)'; \\"
-       ;;
-      *@*)
-       base=`echo $name | sed 's/@.*//'`
-       ver=`echo $name | sed 's/.*@//'`
-       if test -z "$vcount" ; then
-         source=$strong
-         vcount=1
-       else
-         source="${strong}_${vcount}"
-         vcount=`expr $vcount + 1`
-         echo "         echo 'strong_alias ($strong, $source)'; \\"
-       fi
-       echo "   echo 'symbol_version ($source, $base, $ver)'; \\"
-       ;;
-      !*)
-       name=`echo $name | sed 's/.//'`
-       echo "   echo 'strong_alias ($strong, $name)'; \\"
-       echo "   echo 'libc_hidden_def ($name)'; \\"
-       ;;
-      *)
-       echo "   echo 'weak_alias ($strong, $name)'; \\"
-       echo "   echo 'libc_hidden_weak ($name)'; \\"
-       ;;
-    esac
-  done
+  emit_weak_aliases
 
   # And finally, pipe this all into the compiler.
   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 "name@KERNEL_X.Y" 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="${vdso_symver//./_}"
+    echo "\
+\$(foreach p,\$(sysd-rules-targets),\$(objpfx)\$(patsubst %,\$p,$file).os): \\
+               \$(..)sysdeps/unix/make-syscalls.sh\
+       \$(make-target-directory)
+       (echo '#include <dl-vdso.h>'; \\
+        echo 'extern void *${strong}_ifunc (void) __asm (\"${strong}\");'; \\
+        echo 'void *'; \\
+        echo '${strong}_ifunc (void)'; \\
+        echo '{'; \\
+        echo '  PREPARE_VERSION_KNOWN (symver, ${vdso_symver});'; \\
+        echo '  return _dl_vdso_vsym (\"${vdso_symbol}\", &symver);'; \\
+        echo '}'; \\
+        echo 'asm (\".type ${strong}, %gnu_indirect_function\");'; \\"
+    # This is doing "libc_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.
+    echo "\
+        echo 'asm (\".globl __GI_${strong}\\n\"'; \\
+        echo '     \"__GI_${strong} = ${strong}\");'; \\"
+    emit_weak_aliases
+    echo '     ) | $(compile-stdin.c) '"\
+\$(foreach p,\$(patsubst %$file,%,\$(basename \$(@F))),\$(\$(p)CPPFLAGS))"
+  fi
+
   if test $shared_only = t; then
     # The versioned symbols are only in the shared library.
     echo endif
index c30671d..4149bac 100644 (file)
   /* We don't have a specific file where the symbol can be found.  */        \
   var.filename = NULL
 
+/* Use this for the known version sets defined below, where we
+   record their precomputed hash values only once, in this file.  */
+#define PREPARE_VERSION_KNOWN(var, vname) \
+  PREPARE_VERSION (var, VDSO_NAME_##vname, VDSO_HASH_##vname)
+
+#define VDSO_NAME_LINUX_2_6    "LINUX_2.6"
+#define VDSO_HASH_LINUX_2_6    61765110
+#define VDSO_NAME_LINUX_2_6_15 "LINUX_2.6.15"
+#define VDSO_HASH_LINUX_2_6_15 123718565
+#define VDSO_NAME_LINUX_2_6_29 "LINUX_2.6.29"
+#define VDSO_HASH_LINUX_2_6_29 123718585
 
 /* Functions for resolving symbols in the VDSO link map.  */
 extern void *_dl_vdso_vsym (const char *name,
index 7edb6fd..2cc58af 100644 (file)
@@ -1,6 +1,8 @@
 # File name    Caller  Syscall name    # args  Strong name     Weak names
 
 fallocate      -       fallocate       Ci:iiii fallocate       fallocate64
+gettimeofday   -       gettimeofday:__vdso_gettimeofday@LINUX_2.6      i:pP    __gettimeofday  gettimeofday
 posix_fadvise  -       fadvise64       Vi:iiii posix_fadvise   posix_fadvise64
 preadv         -       preadv          Ci:ipii preadv          preadv64
 pwritev                -       pwritev         Ci:ipii pwritev         pwritev64
+time           -       time:__vdso_time@LINUX_2.6                      Ei:P    time