diff --git a/ChangeLog b/ChangeLog index 7c94fce7d7..983ffe645e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 2012-05-24 Roland McGrath + * 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. diff --git a/Makeconfig b/Makeconfig index 3a09764dfa..b4b2963d00 100644 --- a/Makeconfig +++ b/Makeconfig @@ -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' diff --git a/Makerules b/Makerules index 0fd1b5b3e3..685b1b86c6 100644 --- 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. 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 '; \\ + 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