diff options
-rw-r--r-- | ChangeLog | 61 | ||||
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | fedora/branch.mk | 4 | ||||
-rw-r--r-- | fedora/glibc.spec.in | 32 | ||||
-rw-r--r-- | stdio-common/Makefile | 1 | ||||
-rw-r--r-- | stdio-common/Versions | 1 | ||||
-rw-r--r-- | stdio-common/printf-parse.h | 23 | ||||
-rw-r--r-- | stdio-common/printf-parsemb.c | 123 | ||||
-rw-r--r-- | stdio-common/printf-prs.c | 7 | ||||
-rw-r--r-- | stdio-common/printf.h | 49 | ||||
-rw-r--r-- | stdio-common/reg-modifier.c | 202 | ||||
-rw-r--r-- | stdio-common/reg-printf.c | 46 | ||||
-rw-r--r-- | stdio-common/reg-type.c | 62 | ||||
-rw-r--r-- | stdio-common/vfprintf.c | 108 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/elf/start.S | 4 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc64/elf/start.S | 4 | ||||
-rw-r--r-- | sysdeps/sparc/sparc32/elf/start.S | 4 | ||||
-rw-r--r-- | sysdeps/sparc/sparc64/elf/start.S | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/kernel-features.h | 3 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/preadv.c | 13 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/pwritev.c | 13 | ||||
-rw-r--r-- | sysdeps/x86_64/memchr.S | 3 | ||||
-rw-r--r-- | sysdeps/x86_64/rawmemchr.S | 54 | ||||
-rw-r--r-- | sysdeps/x86_64/strrchr.S | 81 |
24 files changed, 751 insertions, 159 deletions
diff --git a/ChangeLog b/ChangeLog index e3f23e35c1..645a157aae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,64 @@ +2009-04-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/powerpc/powerpc32/elf/start.S: Ensure .data is non-empty. + * sysdeps/powerpc/powerpc64/elf/start.S: Likewise. + * sysdeps/sparc/sparc32/elf/start.S: Likewise. + * sysdeps/sparc/sparc64/elf/start.S: Likewise. + +2009-04-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/kernel-features.h: SH also has + preadv/pwritev. + +2009-04-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86-64/strrchr.S: New file. + +2009-04-10 Ulrich Drepper <drepper@redhat.com> + + * stdio-common/printf.h (struct printf_info): Add user element. + New types printf_arginfo_size_function, printf_va_arg_function. + Declare register_printf_specifier, register_printf_modifier, + register_printf_type. + * stdio-common/printf-parse.h (struct printf_spec): Add size element. + (union printf_arg): Add pa_user element. + Adjust __printf_arginfo_table type. + Add __printf_va_arg_table, __printf_modifier_table, + __handle_registered_modifier_mb, and __handle_registered_modifier_wc + declarations. + * stdio-common/printf-parsemb.c: Recognize registered modifiers. + If registered arginfo call failed try normal specifier. + * stdio-common/printf-prs.c: Pass additional parameter to arginfo + function. + * stdio-common/Makefile (routines): Add reg-modifier and reg-type. + * stdio-common/Versions: Export register_printf_modifier, + register_printf_type, and register_printf_specifier for GLIBC_2.10. + * stdio-common/reg-modifier.c: New file. + * stdio-common/reg-type.c: New file. + * stdio-common/reg-printf.c (__register_printf_specifier): New + function. Mostly the old __register_printf_function function but + uses locking and type of third parameter changed. + (__register_printf_function): Implement using + __register_printf_specifier. + * stdio-common/vfprintf.c (vfprintf): Collect argument sizes in + calls to arginfo functions. Allocate enough memory for user-defined + types. Call new va_arg functions to get user-defined types. + Try installed handlers even for existing format specifiers first. + +2009-04-09 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/rawmemchr.S: New file. + + * stdio-common/vfprintf.c (vfprintf): Slightly more compact code. + Simplified code and possible copy problem fixed. + + * sysdeps/unix/sysv/linux/preadv.c: Avoid prototype for static + function if it is not defined. Add some necessary casts. + * sysdeps/unix/sysv/linux/pwritev.c: Likewise. + + * sysdeps/unix/sysv/linux/kernel-features.h: SPARC and IA64 also + have preadv/pwritev in 2.6.30. + 2009-04-08 Ulrich Drepper <drepper@redhat.com> * malloc/malloc.c (malloc_info): New function. diff --git a/NEWS b/NEWS index 74feed6f3b..d7e52f8982 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU C Library NEWS -- history of user-visible changes. 2009-4-8 +GNU C Library NEWS -- history of user-visible changes. 2009-4-13 Copyright (C) 1992-2008, 2009 Free Software Foundation, Inc. See the end for copying conditions. @@ -37,7 +37,11 @@ Version 2.10 * New locales: nan_TW@latin, ks_IN -* Faster strlen, strchr, strchrnul, and memchr for x86-64. +* Faster strlen, strchr, strchrnul, strrchr, memchr, and rawmemchr for x86-64. + Implemented by Ulrich Drepper. + +* Extended printf hook support. It is possible to use user-defined types + and extend existing format specifiers. Implemented by Ulrich Drepper. diff --git a/fedora/branch.mk b/fedora/branch.mk index 4c3dc344b6..3b62c91029 100644 --- a/fedora/branch.mk +++ b/fedora/branch.mk @@ -3,5 +3,5 @@ glibc-branch := fedora glibc-base := HEAD DIST_BRANCH := devel COLLECTION := dist-f8 -fedora-sync-date := 2009-04-09 14:22 UTC -fedora-sync-tag := fedora-glibc-20090409T1422 +fedora-sync-date := 2009-04-14 21:04 UTC +fedora-sync-tag := fedora-glibc-20090414T2104 diff --git a/fedora/glibc.spec.in b/fedora/glibc.spec.in index db1124fad9..8d22e2f00e 100644 --- a/fedora/glibc.spec.in +++ b/fedora/glibc.spec.in @@ -19,7 +19,7 @@ Summary: The GNU libc libraries Name: glibc Version: @glibcversion@ -Release: 15 +Release: 16 # GPLv2+ is used in a bunch of programs, LGPLv2+ is used for libraries. # Things that are linked directly into dynamically linked programs # and shared libraries (e.g. crt files, lib*_nonshared.a) have an additional @@ -229,31 +229,6 @@ package or when debugging this package. %endif %endif -mkdir -p override_headers/asm -cat > override_headers/asm/unistd.h <<EOF -#ifndef _HACK_ASM_UNISTD_H -#include_next <asm/unistd.h> -%ifarch %{ix86} -#ifndef __NR_preadv -#define __NR_preadv 333 -#define __NR_pwritev 334 -#endif -%endif -%ifarch x86_64 -#ifndef __NR_preadv -#define __NR_preadv 295 -#define __NR_pwritev 296 -#endif -%endif -%ifarch ppc ppc64 -#ifndef __NR_preadv -#define __NR_preadv 320 -#define __NR_pwritev 321 -#endif -%endif -#endif -EOF - # A lot of programs still misuse memcpy when they have to use # memmove. The memcpy implementation below is not tolerant at # all. @@ -342,7 +317,7 @@ mkdir $builddir ; cd $builddir build_CFLAGS="$BuildFlags -g -O3 $*" CC="$GCC" CXX="$GXX" CFLAGS="$build_CFLAGS" ../configure --prefix=%{_prefix} \ --enable-add-ons=nptl$AddOns --without-cvs $EnableKernel \ - --with-headers=`cd ..; pwd`/override_headers:%{_prefix}/include --enable-bind-now \ + --with-headers=%{_prefix}/include --enable-bind-now \ --with-tls --with-__thread --build %{nptl_target_cpu}-redhat-linux \ --host %{nptl_target_cpu}-redhat-linux \ --disable-profile --enable-experimental-malloc --enable-nss-crypt @@ -1034,6 +1009,9 @@ rm -f *.filelist* %endif %changelog +* Tue Apr 14 2009 Jakub Jelinek <jakub@redhat.com> 2.9.90-16 +- update from trunk + * Thu Apr 9 2009 Jakub Jelinek <jakub@redhat.com> 2.9.90-15 - rebuilt with fixed gcc to avoid miscompilation of i586 memmove - reenable experimental malloc again diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 6d0b8ab9e1..9cbf14385c 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -27,6 +27,7 @@ routines := \ ctermid cuserid \ _itoa _itowa itoa-digits itoa-udigits itowa-digits \ vfprintf vprintf printf_fp reg-printf printf-prs printf_fphex \ + reg-modifier reg-type \ printf_size fprintf printf snprintf sprintf asprintf dprintf \ vfwprintf vfscanf vfwscanf \ fscanf scanf sscanf \ diff --git a/stdio-common/Versions b/stdio-common/Versions index af693fff52..3503a84e6b 100644 --- a/stdio-common/Versions +++ b/stdio-common/Versions @@ -55,6 +55,7 @@ libc { } GLIBC_2.10 { psiginfo; + register_printf_modifier; register_printf_type; register_printf_specifier; } GLIBC_PRIVATE { # global variables diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h index f6ad71cd3b..555ad78f33 100644 --- a/stdio-common/printf-parse.h +++ b/stdio-common/printf-parse.h @@ -1,5 +1,5 @@ /* Internal header for parsing printf format strings. - Copyright (C) 1995-1999, 2000, 2002, 2003, 2007 + Copyright (C) 1995-1999, 2000, 2002, 2003, 2007, 2009 Free Software Foundation, Inc. This file is part of th GNU C Library. @@ -42,6 +42,8 @@ struct printf_spec int data_arg_type; /* Type of first argument. */ /* Number of arguments consumed by this format specifier. */ size_t ndata_args; + /* Size of the parameter for PA_USER type. */ + int size; }; @@ -60,6 +62,7 @@ union printf_arg const char *pa_string; const wchar_t *pa_wstring; void *pa_pointer; + void *pa_user; }; @@ -83,8 +86,9 @@ read_int (const UCHAR_T * *pstr) /* These are defined in reg-printf.c. */ -extern printf_arginfo_function **__printf_arginfo_table attribute_hidden; +extern printf_arginfo_size_function **__printf_arginfo_table attribute_hidden; extern printf_function **__printf_function_table attribute_hidden; +extern printf_va_arg_function **__printf_va_arg_table attribute_hidden; /* Find the next spec in FORMAT, or the end of the string. Returns @@ -114,3 +118,18 @@ extern size_t __parse_one_specmb (const unsigned char *format, size_t posn, extern size_t __parse_one_specwc (const unsigned int *format, size_t posn, struct printf_spec *spec, size_t *max_ref_arg) attribute_hidden; + + + +/* This variable is defined in reg-modifier.c. */ +struct printf_modifier_record; +extern struct printf_modifier_record **__printf_modifier_table + attribute_hidden; + +/* Handle registered modifiers. */ +extern int __handle_registered_modifier_mb (const unsigned char **format, + struct printf_info *info) + attribute_hidden; +extern int __handle_registered_modifier_wc (const unsigned int **format, + struct printf_info *info) + attribute_hidden; diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c index da6fd3edb0..efd1eca3a2 100644 --- a/stdio-common/printf-parsemb.c +++ b/stdio-common/printf-parsemb.c @@ -1,5 +1,5 @@ /* Helper functions for parsing printf format strings. - Copyright (C) 1995-2000,2002,2003,2004,2006 Free Software Foundation, Inc. + Copyright (C) 1995-2000,2002-2004,2006,2009 Free Software Foundation, Inc. This file is part of th GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -31,12 +31,14 @@ # define INT_T int # define L_(Str) Str # define ISDIGIT(Ch) isdigit (Ch) +# define HANDLE_REGISTERED_MODIFIER __handle_registered_modifier_mb #else # define CHAR_T wchar_t # define UCHAR_T unsigned int # define INT_T wint_t # define L_(Str) L##Str # define ISDIGIT(Ch) iswdigit (Ch) +# define HANDLE_REGISTERED_MODIFIER __handle_registered_modifier_wc #endif #include "printf-parse.h" @@ -223,72 +225,79 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn, spec->info.is_short = 0; spec->info.is_long = 0; spec->info.is_char = 0; - - switch (*format++) - { - case L_('h'): - /* ints are short ints or chars. */ - if (*format != L_('h')) - spec->info.is_short = 1; - else - { - ++format; - spec->info.is_char = 1; - } - break; - case L_('l'): - /* ints are long ints. */ - spec->info.is_long = 1; - if (*format != L_('l')) + spec->info.user = 0; + + if (__builtin_expect (__printf_modifier_table == NULL, 1) + || __printf_modifier_table[*format] == NULL + || HANDLE_REGISTERED_MODIFIER (&format, &spec->info) != 0) + switch (*format++) + { + case L_('h'): + /* ints are short ints or chars. */ + if (*format != L_('h')) + spec->info.is_short = 1; + else + { + ++format; + spec->info.is_char = 1; + } break; - ++format; - /* FALLTHROUGH */ - case L_('L'): - /* doubles are long doubles, and ints are long long ints. */ - case L_('q'): - /* 4.4 uses this for long long. */ - spec->info.is_long_double = 1; - break; - case L_('z'): - case L_('Z'): - /* ints are size_ts. */ - assert (sizeof (size_t) <= sizeof (unsigned long long int)); + case L_('l'): + /* ints are long ints. */ + spec->info.is_long = 1; + if (*format != L_('l')) + break; + ++format; + /* FALLTHROUGH */ + case L_('L'): + /* doubles are long doubles, and ints are long long ints. */ + case L_('q'): + /* 4.4 uses this for long long. */ + spec->info.is_long_double = 1; + break; + case L_('z'): + case L_('Z'): + /* ints are size_ts. */ + assert (sizeof (size_t) <= sizeof (unsigned long long int)); #if LONG_MAX != LONG_LONG_MAX - spec->info.is_long_double = sizeof (size_t) > sizeof (unsigned long int); + spec->info.is_long_double = (sizeof (size_t) + > sizeof (unsigned long int)); #endif - spec->info.is_long = sizeof (size_t) > sizeof (unsigned int); - break; - case L_('t'): - assert (sizeof (ptrdiff_t) <= sizeof (long long int)); + spec->info.is_long = sizeof (size_t) > sizeof (unsigned int); + break; + case L_('t'): + assert (sizeof (ptrdiff_t) <= sizeof (long long int)); #if LONG_MAX != LONG_LONG_MAX - spec->info.is_long_double = (sizeof (ptrdiff_t) > sizeof (long int)); + spec->info.is_long_double = (sizeof (ptrdiff_t) > sizeof (long int)); #endif - spec->info.is_long = sizeof (ptrdiff_t) > sizeof (int); - break; - case L_('j'): - assert (sizeof (uintmax_t) <= sizeof (unsigned long long int)); + spec->info.is_long = sizeof (ptrdiff_t) > sizeof (int); + break; + case L_('j'): + assert (sizeof (uintmax_t) <= sizeof (unsigned long long int)); #if LONG_MAX != LONG_LONG_MAX - spec->info.is_long_double = (sizeof (uintmax_t) - > sizeof (unsigned long int)); + spec->info.is_long_double = (sizeof (uintmax_t) + > sizeof (unsigned long int)); #endif - spec->info.is_long = sizeof (uintmax_t) > sizeof (unsigned int); - break; - default: - /* Not a recognized modifier. Backup. */ - --format; - break; - } + spec->info.is_long = sizeof (uintmax_t) > sizeof (unsigned int); + break; + default: + /* Not a recognized modifier. Backup. */ + --format; + break; + } /* Get the format specification. */ spec->info.spec = (wchar_t) *format++; - if (__builtin_expect (__printf_function_table != NULL, 0) - && spec->info.spec <= UCHAR_MAX - && __printf_arginfo_table[spec->info.spec] != NULL) - /* We don't try to get the types for all arguments if the format - uses more than one. The normal case is covered though. */ - spec->ndata_args = (*__printf_arginfo_table[spec->info.spec]) - (&spec->info, 1, &spec->data_arg_type); - else + spec->size = -1; + if (__builtin_expect (__printf_function_table == NULL, 1) + || spec->info.spec > UCHAR_MAX + || __printf_arginfo_table[spec->info.spec] == NULL + /* We don't try to get the types for all arguments if the format + uses more than one. The normal case is covered though. If + the call returns -1 we continue with the normal specifiers. */ + || (spec->ndata_args = (*__printf_arginfo_table[spec->info.spec]) + (&spec->info, 1, &spec->data_arg_type, + &spec->size)) < 0) { /* Find the data argument types of a built-in spec. */ spec->ndata_args = 1; diff --git a/stdio-common/printf-prs.c b/stdio-common/printf-prs.c index aabc9ed85a..e8d84b3be0 100644 --- a/stdio-common/printf-prs.c +++ b/stdio-common/printf-prs.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1991, 1992, 1995, 1996, 1999, 2000, 2002, 2003, 2004, 2005, - 2007 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1995, 1996, 1999, 2000, 2002-2005, 2007, 2009 + 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 @@ -97,7 +97,8 @@ parse_printf_format (fmt, n, argtypes) /* We have more than one argument for this format spec. We must call the arginfo function again to determine all the types. */ (void) (*__printf_arginfo_table[spec.info.spec]) - (&spec.info, n - spec.data_arg, &argtypes[spec.data_arg]); + (&spec.info, n - spec.data_arg, &argtypes[spec.data_arg], + &spec.size); break; } } diff --git a/stdio-common/printf.h b/stdio-common/printf.h index 360cdcce1d..a11af02274 100644 --- a/stdio-common/printf.h +++ b/stdio-common/printf.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-1993,1995-1999,2000,2001,2006 +/* Copyright (C) 1991-1993,1995-2001,2006,2009 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -29,6 +29,7 @@ __BEGIN_DECLS #define __need_size_t #define __need_wchar_t #include <stddef.h> +#include <stdarg.h> struct printf_info @@ -48,6 +49,8 @@ struct printf_info unsigned int is_char:1; /* hh flag. */ unsigned int wide:1; /* Nonzero for wide character streams. */ unsigned int i18n:1; /* I flag. */ + unsigned int __pad:4; /* Unused so far. */ + unsigned short int user; /* Bits for user-installed modifiers. */ wchar_t pad; /* Padding character. */ }; @@ -68,18 +71,55 @@ typedef int printf_function (FILE *__stream, /* Type of a printf specifier-arginfo function. INFO gives information about the format specification. - N, ARGTYPES, and return value are as for parse_printf_format. */ + N, ARGTYPES, *SIZE has to contain the size of the parameter for + user-defined types, and return value are as for parse_printf_format + except that -1 should be returned if the handler cannot handle + this case. This allows to partially overwrite the functionality + of existing format specifiers. */ + +typedef int printf_arginfo_size_function (__const struct printf_info *__info, + size_t __n, int *__argtypes, + int *__size); + +/* Old version of 'printf_arginfo_function' without a SIZE parameter. */ typedef int printf_arginfo_function (__const struct printf_info *__info, size_t __n, int *__argtypes); +/* Type of a function to get a value of a user-defined from the + variable argument list. */ +typedef void printf_va_arg_function (void *__mem, va_list *__ap); + /* Register FUNC to be called to format SPEC specifiers; ARGINFO must be specified to determine how many arguments a SPEC conversion requires and what their types are. */ +extern int register_printf_specifier (int __spec, printf_function __func, + printf_arginfo_size_function __arginfo) + __THROW; + + +/* Obsolete interface similar to register_printf_specifier. It can only + handle basic data types because the ARGINFO callback does not return + information on the size of the user-defined type. */ + extern int register_printf_function (int __spec, printf_function __func, - printf_arginfo_function __arginfo); + printf_arginfo_function __arginfo) + __THROW __attribute_deprecated__; + + +/* Register a new modifier character sequence. If the call succeeds + it returns a positive value representing the bit set in the USER + field in 'struct printf_info'. */ + +extern int register_printf_modifier (wchar_t *__str) __wur __THROW; + + +/* Register variable argument handler for user type. The return value + is to be used in ARGINFO functions to signal the use of the + type. */ +extern int register_printf_type (printf_va_arg_function __fct) __wur __THROW; /* Parse FMT, and fill in N elements of ARGTYPES with the @@ -100,7 +140,8 @@ extern size_t parse_printf_format (__const char *__restrict __fmt, size_t __n, /* Codes returned by `parse_printf_format' for basic types. These values cover all the standard format specifications. - Users can add new values after PA_LAST for their own types. */ + Users can reserve new values after PA_LAST for their own types + using 'register_printf_type'. */ enum { /* C type: */ diff --git a/stdio-common/reg-modifier.c b/stdio-common/reg-modifier.c new file mode 100644 index 0000000000..69bb2ef3d5 --- /dev/null +++ b/stdio-common/reg-modifier.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2009 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <limits.h> +#include <printf.h> +#include <wchar.h> +#include <bits/libc-lock.h> + + +struct printf_modifier_record +{ + struct printf_modifier_record *next; + int bit; + wchar_t str[0]; +}; + +struct printf_modifier_record **__printf_modifier_table attribute_hidden; + +__libc_lock_define_initialized (static, lock) + +/* Bits to hand out. */ +static int next_bit; + + +int +__register_printf_modifier (wchar_t *str) +{ + if (str[0] == L'\0') + { + einval: + __set_errno (EINVAL); + return -1; + } + + wchar_t *wc = str; + while (*wc != L'\0') + if (*wc < 0 || *wc > (wchar_t) UCHAR_MAX) + goto einval; + else + ++wc; + + if (next_bit / 8 == sizeof (((struct printf_info *) NULL)->user)) + { + __set_errno (ENOSPC); + return -1; + } + + int result = -1; + __libc_lock_lock (lock); + + if (__printf_modifier_table == NULL) + { + __printf_modifier_table = calloc (UCHAR_MAX, + sizeof (*__printf_modifier_table)); + if (__printf_modifier_table == NULL) + goto out; + } + + /* Create enough room for the string. But we don't need the first + character. */ + struct printf_modifier_record *newp = malloc (sizeof (*newp) + + ((wc - str) + * sizeof (wchar_t))); + if (newp == NULL) + goto out; + + newp->next = __printf_modifier_table[(unsigned char) *str]; + newp->bit = 1 << next_bit++; + __wmemcpy (newp->str, str + 1, wc - str); + + __printf_modifier_table[(unsigned char) *str] = newp; + + result = newp->bit; + + out: + __libc_lock_unlock (lock); + + return result; +} +weak_alias (__register_printf_modifier, register_printf_modifier) + + +#include <stdio.h> +int +attribute_hidden +__handle_registered_modifier_mb (const unsigned char **format, + struct printf_info *info) +{ + struct printf_modifier_record *runp = __printf_modifier_table[**format]; + + int best_bit = 0; + int best_len = 0; + const unsigned char *best_cp = NULL; + + while (runp != NULL) + { + const unsigned char *cp = *format + 1; + wchar_t *fcp = runp->str; + + while (*cp != '\0' && *fcp != L'\0') + if (*cp != *fcp) + break; + else + ++cp, ++fcp; + + if (*fcp == L'\0' && cp - *format > best_len) + { + best_cp = cp; + best_len = cp - *format; + best_bit = runp->bit; + } + + runp = runp->next; + } + + if (best_bit != 0) + { + info->user |= best_bit; + *format = best_cp; + return 0; + } + + return 1; +} + + +int +attribute_hidden +__handle_registered_modifier_wc (const unsigned int **format, + struct printf_info *info) +{ + struct printf_modifier_record *runp = __printf_modifier_table[**format]; + + int best_bit = 0; + int best_len = 0; + const unsigned int *best_cp = NULL; + + while (runp != NULL) + { + const unsigned int *cp = *format + 1; + wchar_t *fcp = runp->str; + + while (*cp != '\0' && *fcp != L'\0') + if (*cp != *fcp) + break; + else + ++cp, ++fcp; + + if (*fcp == L'\0' && cp - *format > best_len) + { + best_cp = cp; + best_len = cp - *format; + best_bit = runp->bit; + } + + runp = runp->next; + } + + if (best_bit != 0) + { + info->user |= best_bit; + *format = best_cp; + return 0; + } + + return 1; +} + + +libc_freeres_fn (free_mem) +{ + if (__printf_modifier_table != NULL) + { + for (int i = 0; i < UCHAR_MAX; ++i) + { + struct printf_modifier_record *runp = __printf_modifier_table[i]; + while (runp != NULL) + { + struct printf_modifier_record *oldp = runp; + runp = runp->next; + free (oldp); + } + } + free (__printf_modifier_table); + } +} diff --git a/stdio-common/reg-printf.c b/stdio-common/reg-printf.c index dbb6234e5f..b5cab679de 100644 --- a/stdio-common/reg-printf.c +++ b/stdio-common/reg-printf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991,1996,1997,2002,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1991,1996,1997,2002-2004,2009 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 @@ -21,21 +21,28 @@ #include <printf.h> #include <stddef.h> #include <stdlib.h> +#include <bits/libc-lock.h> + /* Array of functions indexed by format character. */ -libc_freeres_ptr (printf_arginfo_function **__printf_arginfo_table) +libc_freeres_ptr (printf_arginfo_size_function **__printf_arginfo_table) attribute_hidden; printf_function **__printf_function_table attribute_hidden; +__libc_lock_define_initialized (static, lock) + +int __register_printf_specifier (int, printf_function, + printf_arginfo_size_function); int __register_printf_function (int, printf_function, - printf_arginfo_function) __THROW; + printf_arginfo_function); + /* Register FUNC to be called to format SPEC specifiers. */ int -__register_printf_function (spec, converter, arginfo) +__register_printf_specifier (spec, converter, arginfo) int spec; printf_function converter; - printf_arginfo_function arginfo; + printf_arginfo_size_function arginfo; { if (spec < 0 || spec > (int) UCHAR_MAX) { @@ -43,12 +50,19 @@ __register_printf_function (spec, converter, arginfo) return -1; } + int result = 0; + __libc_lock_lock (lock); + if (__printf_function_table == NULL) { - __printf_arginfo_table = (printf_arginfo_function **) + __printf_arginfo_table = (printf_arginfo_size_function **) calloc (UCHAR_MAX + 1, sizeof (void *) * 2); if (__printf_arginfo_table == NULL) - return -1; + { + result = -1; + goto out; + } + __printf_function_table = (printf_function **) (__printf_arginfo_table + UCHAR_MAX + 1); } @@ -56,6 +70,22 @@ __register_printf_function (spec, converter, arginfo) __printf_function_table[spec] = converter; __printf_arginfo_table[spec] = arginfo; - return 0; + out: + __libc_lock_unlock (lock); + + return result; +} +weak_alias (__register_printf_specifier, register_printf_specifier) + + +/* Register FUNC to be called to format SPEC specifiers. */ +int +__register_printf_function (spec, converter, arginfo) + int spec; + printf_function converter; + printf_arginfo_function arginfo; +{ + return __register_printf_specifier (spec, converter, + (printf_arginfo_size_function*) arginfo); } weak_alias (__register_printf_function, register_printf_function) diff --git a/stdio-common/reg-type.c b/stdio-common/reg-type.c new file mode 100644 index 0000000000..7a96b2893a --- /dev/null +++ b/stdio-common/reg-type.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2009 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <printf.h> +#include <stdlib.h> +#include <bits/libc-lock.h> + + +/* Array of functions indexed by format character. */ +libc_freeres_ptr (printf_va_arg_function **__printf_va_arg_table) + attribute_hidden; + +__libc_lock_define_initialized (static, lock); + +/* Last type allocated. */ +static int pa_next_type = PA_LAST; + + +int +__register_printf_type (printf_va_arg_function fct) +{ + int result = -1; + __libc_lock_lock (lock); + + if (__printf_va_arg_table == NULL) + { + __printf_va_arg_table = (printf_va_arg_function **) + calloc (0x100 - PA_LAST, sizeof (void *)); + if (__printf_va_arg_table == NULL) + goto out; + } + + if (pa_next_type == 0x100) + __set_errno (ENOSPC); + else + { + result = pa_next_type++; + __printf_va_arg_table[result - PA_LAST] = fct; + } + + out: + __libc_lock_unlock (lock); + + return result; +} +weak_alias (__register_printf_type, register_printf_type) diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 5d5bb5e578..38ba8ffdcd 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -1,5 +1,4 @@ -/* Copyright (C) 1991-2002, 2003, 2004, 2005, 2006, 2007, 2008 - Free Software Foundation, Inc. +/* Copyright (C) 1991-2008, 2009 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 @@ -239,7 +238,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) /* This table maps a character into a number representing a class. In each step there is a destination label for each class. */ - static const int jump_table[] = + static const uint8_t jump_table[] = { /* ' ' */ 1, 0, 0, /* '#' */ 4, 0, /* '%' */ 14, 0, /* '\''*/ 6, @@ -1631,6 +1630,7 @@ do_positional: size_t nargs = 0; int *args_type; union printf_arg *args_value = NULL; + int *args_size; /* Positional parameters refer to arguments directly. This could also determine the maximum number of arguments. Track the @@ -1663,24 +1663,10 @@ do_positional: { /* Extend the array of format specifiers. */ struct printf_spec *old = specs; + specs = extend_alloca (specs, nspecs_max, 2 * nspecs_max); - nspecs_max *= 2; - specs = alloca (nspecs_max * sizeof (struct printf_spec)); - - if (specs == &old[nspecs]) - /* Stack grows up, OLD was the last thing allocated; - extend it. */ - nspecs_max += nspecs_max / 2; - else - { - /* Copy the old array's elements to the new space. */ - memcpy (specs, old, nspecs * sizeof (struct printf_spec)); - if (old == &specs[nspecs]) - /* Stack grows down, OLD was just below the new - SPECS. We can use that space when the new space - runs out. */ - nspecs_max += nspecs_max / 2; - } + /* Copy the old array's elements to the new space. */ + memmove (specs, old, nspecs * sizeof (struct printf_spec)); } /* Parse the format specifier. */ @@ -1699,6 +1685,7 @@ do_positional: memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0', nargs * sizeof (int)); args_value = alloca (nargs * sizeof (union printf_arg)); + args_size = alloca (nargs * sizeof (int)); /* XXX Could do sanity check here: If any element in ARGS_TYPE is still zero after this loop, format is invalid. For now we @@ -1719,8 +1706,10 @@ do_positional: { case 0: /* No arguments. */ break; - case 1: /* One argument; we already have the type. */ + case 1: /* One argument; we already have the + type and size. */ args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type; + args_size[specs[cnt].data_arg] = specs[cnt].size; break; default: /* We have more than one argument for this format spec. @@ -1728,7 +1717,8 @@ do_positional: all the types. */ (void) (*__printf_arginfo_table[specs[cnt].info.spec]) (&specs[cnt].info, - specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]); + specs[cnt].ndata_args, &args_type[specs[cnt].data_arg], + &args_size[specs[cnt].data_arg]); break; } } @@ -1743,13 +1733,21 @@ do_positional: args_value[cnt].mem = va_arg (ap_save, type); \ break - T (PA_CHAR, pa_int, int); /* Promoted. */ T (PA_WCHAR, pa_wchar, wint_t); - T (PA_INT|PA_FLAG_SHORT, pa_int, int); /* Promoted. */ + case PA_CHAR: /* Promoted. */ + case PA_INT|PA_FLAG_SHORT: /* Promoted. */ +#if LONG_MAX == INT_MAX + case PA_INT|PA_FLAG_LONG: +#endif T (PA_INT, pa_int, int); - T (PA_INT|PA_FLAG_LONG, pa_long_int, long int); +#if LONG_MAX == LONG_LONG_MAX + case PA_INT|PA_FLAG_LONG: +#endif T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int); - T (PA_FLOAT, pa_double, double); /* Promoted. */ +#if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX +# error "he?" +#endif + case PA_FLOAT: /* Promoted. */ T (PA_DOUBLE, pa_double, double); case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: if (__ldbl_is_dbl) @@ -1760,13 +1758,20 @@ do_positional: else args_value[cnt].pa_long_double = va_arg (ap_save, long double); break; - T (PA_STRING, pa_string, const char *); - T (PA_WSTRING, pa_wstring, const wchar_t *); + case PA_STRING: /* All pointers are the same */ + case PA_WSTRING: /* All pointers are the same */ T (PA_POINTER, pa_pointer, void *); #undef T default: if ((args_type[cnt] & PA_FLAG_PTR) != 0) args_value[cnt].pa_pointer = va_arg (ap_save, void *); + else if (__builtin_expect (__printf_va_arg_table != NULL, 0) + && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL) + { + args_value[cnt].pa_user = alloca (args_size[cnt]); + (*__printf_va_arg_table[args_type[cnt] - PA_LAST]) + (args_value[cnt].pa_user, &ap_save); + } else args_value[cnt].pa_long_double = 0.0; break; @@ -1870,6 +1875,40 @@ do_positional: /* Process format specifiers. */ while (1) { + extern printf_function **__printf_function_table; + int function_done; + + if (spec <= UCHAR_MAX + && __printf_function_table != NULL + && __printf_function_table[(size_t) spec] != NULL) + { + const void **ptr = alloca (specs[nspecs_done].ndata_args + * sizeof (const void *)); + + /* Fill in an array of pointers to the argument values. */ + for (unsigned int i = 0; i < specs[nspecs_done].ndata_args; + ++i) + ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; + + /* Call the function. */ + function_done = __printf_function_table[(size_t) spec] + (s, &specs[nspecs_done].info, ptr); + + if (function_done != -2) + { + /* If an error occurred we don't have information + about # of chars. */ + if (function_done < 0) + { + done = -1; + goto all_done; + } + + done_add (function_done); + break; + } + } + JUMP (spec, step4_jumps); process_arg ((&specs[nspecs_done])); @@ -1877,19 +1916,9 @@ do_positional: LABEL (form_unknown): { - extern printf_function **__printf_function_table; - int function_done; - printf_function *function; unsigned int i; const void **ptr; - function = - (__printf_function_table == NULL ? NULL : - __printf_function_table[specs[nspecs_done].info.spec]); - - if (function == NULL) - function = &printf_unknown; - ptr = alloca (specs[nspecs_done].ndata_args * sizeof (const void *)); @@ -1898,7 +1927,8 @@ do_positional: ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; /* Call the function. */ - function_done = (*function) (s, &specs[nspecs_done].info, ptr); + function_done = printf_unknown (s, &specs[nspecs_done].info, + ptr); /* If an error occurred we don't have information about # of chars. */ diff --git a/sysdeps/powerpc/powerpc32/elf/start.S b/sysdeps/powerpc/powerpc32/elf/start.S index bafd2ae001..a8abdca0c6 100644 --- a/sysdeps/powerpc/powerpc32/elf/start.S +++ b/sysdeps/powerpc/powerpc32/elf/start.S @@ -1,5 +1,6 @@ /* Startup code for programs linked with GNU libc. - Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. + Copyright (C) 1998,1999,2000,2001,2002,2003,2009 + 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 @@ -98,4 +99,5 @@ END(_start) .section ".data" .globl __data_start __data_start: + .long 0 weak_alias (__data_start, data_start) diff --git a/sysdeps/powerpc/powerpc64/elf/start.S b/sysdeps/powerpc/powerpc64/elf/start.S index c9119a2624..e559b87841 100644 --- a/sysdeps/powerpc/powerpc64/elf/start.S +++ b/sysdeps/powerpc/powerpc64/elf/start.S @@ -1,5 +1,6 @@ /* Startup code for programs linked with GNU libc. PowerPC64 version. - Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. + Copyright (C) 1998,1999,2000,2001,2002,2003,2009 + 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 @@ -83,4 +84,5 @@ END(_start) .section ".data" .globl __data_start __data_start: + .long 0 weak_alias (__data_start, data_start) diff --git a/sysdeps/sparc/sparc32/elf/start.S b/sysdeps/sparc/sparc32/elf/start.S index 85adb7322f..7ff4bd68f6 100644 --- a/sysdeps/sparc/sparc32/elf/start.S +++ b/sysdeps/sparc/sparc32/elf/start.S @@ -1,5 +1,6 @@ /* Startup code for elf32-sparc - Copyright (C) 1997, 1998, 2002, 2004, 2007 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 2002, 2004, 2007, 2009 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson <richard@gnu.ai.mit.edu>, 1997. @@ -96,4 +97,5 @@ _start: .data .globl __data_start __data_start: + .long 0 weak_alias (__data_start, data_start) diff --git a/sysdeps/sparc/sparc64/elf/start.S b/sysdeps/sparc/sparc64/elf/start.S index 650d3d3048..406ea0f55e 100644 --- a/sysdeps/sparc/sparc64/elf/start.S +++ b/sysdeps/sparc/sparc64/elf/start.S @@ -1,5 +1,6 @@ /* Startup code for elf64-sparc - Copyright (C) 1997, 1998, 2002, 2004, 2007 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 2002, 2004, 2007, 2009 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson <richard@gnu.ai.mit.edu>, 1997. @@ -97,4 +98,5 @@ _start: .data .globl __data_start __data_start: + .long 0 weak_alias (__data_start, data_start) diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index 5f1ffdb9c5..2fa8524db9 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -532,7 +532,8 @@ /* Support for preadv and pwritev was added in 2.6.30. */ #if __LINUX_KERNEL_VERSION >= 0x02061e \ - && (defined __i386__ || defined __x86_64__ || defined __powerpc__) + && (defined __i386__ || defined __x86_64__ || defined __powerpc__ \ + || defined __ia64__ || defined __sparc__ && defined __sh__) # define __ASSUME_PREADV 1 # define __ASSUME_PWRITEV 1 #endif diff --git a/sysdeps/unix/sysv/linux/preadv.c b/sysdeps/unix/sysv/linux/preadv.c index e2f8238596..0d4a6c3803 100644 --- a/sysdeps/unix/sysv/linux/preadv.c +++ b/sysdeps/unix/sysv/linux/preadv.c @@ -29,6 +29,7 @@ #include <sys/syscall.h> #include <kernel-features.h> + #ifndef PREADV # define PREADV preadv # define PREADV_REPLACEMENT __atomic_preadv_replacement @@ -36,8 +37,10 @@ # define OFF_T off_t #endif +#ifndef __ASSUME_PREADV static ssize_t PREADV_REPLACEMENT (int, __const struct iovec *, int, OFF_T) internal_function; +#endif ssize_t @@ -51,14 +54,16 @@ PREADV (fd, vector, count, offset) ssize_t result; if (SINGLE_THREAD_P) - result = INLINE_SYSCALL (preadv, 5, fd, vector, count, offset >> 32, - offset & 0xffffffff); + result = INLINE_SYSCALL (preadv, 5, fd, vector, count, + (off_t) ((off64_t) offset >> 32), + (off_t) (offset & 0xffffffff)); else { int oldtype = LIBC_CANCEL_ASYNC (); - result = INLINE_SYSCALL (preadv, 5, fd, vector, count, offset >> 32, - offset & 0xffffffff); + result = INLINE_SYSCALL (preadv, 5, fd, vector, count, + (off_t) ((off64_t) offset >> 32), + (off_t) (offset & 0xffffffff)); LIBC_CANCEL_RESET (oldtype); } diff --git a/sysdeps/unix/sysv/linux/pwritev.c b/sysdeps/unix/sysv/linux/pwritev.c index df430ffe46..5c30eae51f 100644 --- a/sysdeps/unix/sysv/linux/pwritev.c +++ b/sysdeps/unix/sysv/linux/pwritev.c @@ -29,6 +29,7 @@ #include <sys/syscall.h> #include <kernel-features.h> + #ifndef PWRITEV # define PWRITEV pwritev # define PWRITEV_REPLACEMENT __atomic_pwritev_replacement @@ -36,8 +37,10 @@ # define OFF_T off_t #endif +#ifndef __ASSUME_PWRITEV static ssize_t PWRITEV_REPLACEMENT (int, __const struct iovec *, int, OFF_T) internal_function; +#endif ssize_t @@ -51,14 +54,16 @@ PWRITEV (fd, vector, count, offset) ssize_t result; if (SINGLE_THREAD_P) - result = INLINE_SYSCALL (pwritev, 5, fd, vector, count, offset >> 32, - offset & 0xffffffff); + result = INLINE_SYSCALL (pwritev, 5, fd, vector, count, + (off_t) ((off64_t) offset >> 32), + (off_t) (offset & 0xffffffff)); else { int oldtype = LIBC_CANCEL_ASYNC (); - result = INLINE_SYSCALL (pwritev, 5, fd, vector, count, offset >> 32, - offset & 0xffffffff); + result = INLINE_SYSCALL (pwritev, 5, fd, vector, count, + (off_t) ((off64_t) offset >> 32), + (off_t) (offset & 0xffffffff)); LIBC_CANCEL_RESET (oldtype); } diff --git a/sysdeps/x86_64/memchr.S b/sysdeps/x86_64/memchr.S index 644362d565..09ba6d4f8d 100644 --- a/sysdeps/x86_64/memchr.S +++ b/sysdeps/x86_64/memchr.S @@ -1,5 +1,4 @@ -/* strlen(str) -- determine the length of the string STR. - Copyright (C) 2009 Free Software Foundation, Inc. +/* Copyright (C) 2009 Free Software Foundation, Inc. Contributed by Ulrich Drepper <drepper@redhat.com>. This file is part of the GNU C Library. diff --git a/sysdeps/x86_64/rawmemchr.S b/sysdeps/x86_64/rawmemchr.S new file mode 100644 index 0000000000..c3bd771635 --- /dev/null +++ b/sysdeps/x86_64/rawmemchr.S @@ -0,0 +1,54 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + + + .text +ENTRY (rawmemchr) + movd %esi, %xmm1 + movq %rdi, %rcx + punpcklbw %xmm1, %xmm1 + andq $~15, %rdi + punpcklbw %xmm1, %xmm1 + orl $0xffffffff, %esi + movdqa (%rdi), %xmm0 + pshufd $0, %xmm1, %xmm1 + subq %rdi, %rcx + pcmpeqb %xmm1, %xmm0 + shl %cl, %esi + pmovmskb %xmm0, %ecx + leaq 16(%rdi), %rdi + andl %esi, %ecx + jnz 1f + +2: movdqa (%rdi), %xmm0 + leaq 16(%rdi), %rdi + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %ecx + testl %ecx, %ecx + jz 2b + +1: bsfl %ecx, %ecx + leaq -16(%rcx,%rdi), %rax + ret +END (rawmemchr) + +strong_alias (rawmemchr, __rawmemchr) +libc_hidden_builtin_def (__rawmemchr) diff --git a/sysdeps/x86_64/strrchr.S b/sysdeps/x86_64/strrchr.S new file mode 100644 index 0000000000..c75b485ca3 --- /dev/null +++ b/sysdeps/x86_64/strrchr.S @@ -0,0 +1,81 @@ +/* strrchr (str, ch) -- Return pointer to last occurrence of CH in STR. + For AMD x86-64. + Copyright (C) 2009 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + + + .text +ENTRY (strrchr) + movd %esi, %xmm1 + movq %rdi, %rcx + punpcklbw %xmm1, %xmm1 + andq $~15, %rdi + pxor %xmm2, %xmm2 + punpcklbw %xmm1, %xmm1 + orl $0xffffffff, %esi + movdqa (%rdi), %xmm0 + pshufd $0, %xmm1, %xmm1 + subq %rdi, %rcx + movdqa %xmm0, %xmm3 + leaq 16(%rdi), %rdi + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm3 + shl %cl, %esi + pmovmskb %xmm0, %edx + pmovmskb %xmm3, %ecx + andl %esi, %edx + andl %esi, %ecx + xorl %eax, %eax + movl %edx, %esi + orl %ecx, %esi + jnz 1f + +2: movdqa (%rdi), %xmm0 + leaq 16(%rdi), %rdi + movdqa %xmm0, %xmm3 + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm3 + pmovmskb %xmm0, %edx + pmovmskb %xmm3, %ecx + movl %edx, %esi + orl %ecx, %esi + jz 2b + +1: bsfl %ecx, %r9d + movl $0xffffffff, %r8d + movl $31, %ecx + jnz 5f + + bsrl %edx, %edx + jz 2b + leaq -16(%rdi,%rdx), %rax + jmp 2b + +5: subl %r9d, %ecx + shrl %cl, %r8d + andl %r8d, %edx + bsrl %edx, %edx + jz 4f + leaq -16(%rdi,%rdx), %rax +4: ret +END (strrchr) + +weak_alias (strrchr, rindex) +libc_hidden_builtin_def (strrchr) |