summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog61
-rw-r--r--NEWS8
-rw-r--r--fedora/branch.mk4
-rw-r--r--fedora/glibc.spec.in32
-rw-r--r--stdio-common/Makefile1
-rw-r--r--stdio-common/Versions1
-rw-r--r--stdio-common/printf-parse.h23
-rw-r--r--stdio-common/printf-parsemb.c123
-rw-r--r--stdio-common/printf-prs.c7
-rw-r--r--stdio-common/printf.h49
-rw-r--r--stdio-common/reg-modifier.c202
-rw-r--r--stdio-common/reg-printf.c46
-rw-r--r--stdio-common/reg-type.c62
-rw-r--r--stdio-common/vfprintf.c108
-rw-r--r--sysdeps/powerpc/powerpc32/elf/start.S4
-rw-r--r--sysdeps/powerpc/powerpc64/elf/start.S4
-rw-r--r--sysdeps/sparc/sparc32/elf/start.S4
-rw-r--r--sysdeps/sparc/sparc64/elf/start.S4
-rw-r--r--sysdeps/unix/sysv/linux/kernel-features.h3
-rw-r--r--sysdeps/unix/sysv/linux/preadv.c13
-rw-r--r--sysdeps/unix/sysv/linux/pwritev.c13
-rw-r--r--sysdeps/x86_64/memchr.S3
-rw-r--r--sysdeps/x86_64/rawmemchr.S54
-rw-r--r--sysdeps/x86_64/strrchr.S81
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)