diff options
author | Roland McGrath <roland@hack.frob.com> | 2012-05-22 16:00:50 -0700 |
---|---|---|
committer | Roland McGrath <roland@hack.frob.com> | 2012-05-24 13:13:46 -0700 |
commit | c14874927b499ddfdbb03745bb32bfc778b8595f (patch) | |
tree | a07ace4f46694be67780cdf4765044f80ac4f729 /sysdeps/unix | |
parent | d6c33fda03457ca8ca87a562fa2681af16ca4ea5 (diff) | |
download | glibc-c14874927b499ddfdbb03745bb32bfc778b8595f.tar.gz glibc-c14874927b499ddfdbb03745bb32bfc778b8595f.tar.xz glibc-c14874927b499ddfdbb03745bb32bfc778b8595f.zip |
syscalls.list support for vDSO IFUNCs, use it for x32 gettimeofday and time.
Diffstat (limited to 'sysdeps/unix')
-rw-r--r-- | sysdeps/unix/make-syscalls.sh | 142 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/dl-vdso.h | 11 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list | 2 |
3 files changed, 107 insertions, 48 deletions
diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh index 48aab629f5..cedce3193c 100644 --- a/sysdeps/unix/make-syscalls.sh +++ b/sysdeps/unix/make-syscalls.sh @@ -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 diff --git a/sysdeps/unix/sysv/linux/dl-vdso.h b/sysdeps/unix/sysv/linux/dl-vdso.h index c30671de72..4149bacdce 100644 --- a/sysdeps/unix/sysv/linux/dl-vdso.h +++ b/sysdeps/unix/sysv/linux/dl-vdso.h @@ -33,6 +33,17 @@ /* 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, diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list index 7edb6fd618..2cc58af2df 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list +++ b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list @@ -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 |