about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/generic/memcpy_chk.c66
-rw-r--r--sysdeps/generic/memmove_chk.c98
-rw-r--r--sysdeps/generic/mempcpy_chk.c67
-rw-r--r--sysdeps/generic/memset_chk.c92
-rw-r--r--sysdeps/generic/readonly-area.c29
-rw-r--r--sysdeps/generic/stpcpy_chk.c45
-rw-r--r--sysdeps/generic/strcat_chk.c58
-rw-r--r--sysdeps/generic/strcpy_chk.c46
-rw-r--r--sysdeps/generic/strncat_chk.c100
-rw-r--r--sysdeps/generic/strncpy_chk.c89
-rw-r--r--sysdeps/i386/i686/memcpy.S9
-rw-r--r--sysdeps/i386/i686/memcpy_chk.S35
-rw-r--r--sysdeps/i386/i686/memmove.S9
-rw-r--r--sysdeps/i386/i686/memmove_chk.S35
-rw-r--r--sysdeps/i386/i686/mempcpy.S7
-rw-r--r--sysdeps/i386/i686/mempcpy_chk.S35
-rw-r--r--sysdeps/i386/i686/memset.S7
-rw-r--r--sysdeps/i386/i686/memset_chk.S35
-rw-r--r--sysdeps/unix/sysv/linux/readonly-area.c90
-rw-r--r--sysdeps/x86_64/memcpy.S6
-rw-r--r--sysdeps/x86_64/memcpy_chk.S34
-rw-r--r--sysdeps/x86_64/mempcpy.S1
-rw-r--r--sysdeps/x86_64/mempcpy_chk.S34
-rw-r--r--sysdeps/x86_64/memset.S8
-rw-r--r--sysdeps/x86_64/memset_chk.S34
-rw-r--r--sysdeps/x86_64/stpcpy_chk.S3
-rw-r--r--sysdeps/x86_64/strcpy_chk.S211
27 files changed, 1280 insertions, 3 deletions
diff --git a/sysdeps/generic/memcpy_chk.c b/sysdeps/generic/memcpy_chk.c
new file mode 100644
index 0000000000..638cd0e4fb
--- /dev/null
+++ b/sysdeps/generic/memcpy_chk.c
@@ -0,0 +1,66 @@
+/* Copy memory to memory until the specified number of bytes
+   has been copied with error checking.  Overlap is NOT handled correctly.
+   Copyright (C) 1991, 1997, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Torbjorn Granlund (tege@sics.se).
+
+   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 <string.h>
+#include <memcopy.h>
+#include <pagecopy.h>
+
+void *
+__memcpy_chk (dstpp, srcpp, len, dstlen)
+     void *dstpp;
+     const void *srcpp;
+     size_t len;
+     size_t dstlen;
+{
+  if (__builtin_expect (dstlen < len, 0))
+    __chk_fail ();
+
+  unsigned long int dstp = (long int) dstpp;
+  unsigned long int srcp = (long int) srcpp;
+
+  /* Copy from the beginning to the end.  */
+
+  /* If there not too few bytes to copy, use word copy.  */
+  if (len >= OP_T_THRES)
+    {
+      /* Copy just a few bytes to make DSTP aligned.  */
+      len -= (-dstp) % OPSIZ;
+      BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
+
+      /* Copy whole pages from SRCP to DSTP by virtual address manipulation,
+	 as much as possible.  */
+
+      PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
+
+      /* Copy from SRCP to DSTP taking advantage of the known alignment of
+	 DSTP.  Number of bytes remaining is put in the third argument,
+	 i.e. in LEN.  This number may vary from machine to machine.  */
+
+      WORD_COPY_FWD (dstp, srcp, len, len);
+
+      /* Fall out and copy the tail.  */
+    }
+
+  /* There are just a few bytes to copy.  Use byte memory operations.  */
+  BYTE_COPY_FWD (dstp, srcp, len);
+
+  return dstpp;
+}
diff --git a/sysdeps/generic/memmove_chk.c b/sysdeps/generic/memmove_chk.c
new file mode 100644
index 0000000000..f3b74d23d9
--- /dev/null
+++ b/sysdeps/generic/memmove_chk.c
@@ -0,0 +1,98 @@
+/* Copy memory to memory until the specified number of bytes
+   has been copied with error checking.  Overlap is handled correctly.
+   Copyright (C) 1991,1995,1996,1997,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Torbjorn Granlund (tege@sics.se).
+
+   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 <string.h>
+#include <memcopy.h>
+#include <pagecopy.h>
+
+void *
+__memmove_chk (dest, src, len, destlen)
+     void *dest;
+     const void *src;
+     size_t len;
+     size_t destlen;
+{
+  if (__builtin_expect (destlen < len, 0))
+    __chk_fail ();
+
+  unsigned long int dstp = (long int) dest;
+  unsigned long int srcp = (long int) src;
+
+  /* This test makes the forward copying code be used whenever possible.
+     Reduces the working set.  */
+  if (dstp - srcp >= len)	/* *Unsigned* compare!  */
+    {
+      /* Copy from the beginning to the end.  */
+
+      /* If there not too few bytes to copy, use word copy.  */
+      if (len >= OP_T_THRES)
+	{
+	  /* Copy just a few bytes to make DSTP aligned.  */
+	  len -= (-dstp) % OPSIZ;
+	  BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
+
+	  /* Copy whole pages from SRCP to DSTP by virtual address
+	     manipulation, as much as possible.  */
+
+	  PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
+
+	  /* Copy from SRCP to DSTP taking advantage of the known
+	     alignment of DSTP.  Number of bytes remaining is put
+	     in the third argument, i.e. in LEN.  This number may
+	     vary from machine to machine.  */
+
+	  WORD_COPY_FWD (dstp, srcp, len, len);
+
+	  /* Fall out and copy the tail.  */
+	}
+
+      /* There are just a few bytes to copy.  Use byte memory operations.  */
+      BYTE_COPY_FWD (dstp, srcp, len);
+    }
+  else
+    {
+      /* Copy from the end to the beginning.  */
+      srcp += len;
+      dstp += len;
+
+      /* If there not too few bytes to copy, use word copy.  */
+      if (len >= OP_T_THRES)
+	{
+	  /* Copy just a few bytes to make DSTP aligned.  */
+	  len -= dstp % OPSIZ;
+	  BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);
+
+	  /* Copy from SRCP to DSTP taking advantage of the known
+	     alignment of DSTP.  Number of bytes remaining is put
+	     in the third argument, i.e. in LEN.  This number may
+	     vary from machine to machine.  */
+
+	  WORD_COPY_BWD (dstp, srcp, len, len);
+
+	  /* Fall out and copy the tail.  */
+	}
+
+      /* There are just a few bytes to copy.  Use byte memory operations.  */
+      BYTE_COPY_BWD (dstp, srcp, len);
+    }
+
+  return dest;
+}
diff --git a/sysdeps/generic/mempcpy_chk.c b/sysdeps/generic/mempcpy_chk.c
new file mode 100644
index 0000000000..5297bbab92
--- /dev/null
+++ b/sysdeps/generic/mempcpy_chk.c
@@ -0,0 +1,67 @@
+/* Copy memory to memory until the specified number of bytes
+   has been copied, return pointer to following byte, with error checking.
+   Overlap is NOT handled correctly.
+   Copyright (C) 1991, 1997, 1998, 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Torbjorn Granlund (tege@sics.se).
+
+   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 <string.h>
+#include <memcopy.h>
+#include <pagecopy.h>
+
+void *
+__mempcpy_chk (dstpp, srcpp, len, dstlen)
+     void *dstpp;
+     const void *srcpp;
+     size_t len;
+     size_t dstlen;
+{
+  if (__builtin_expect (dstlen < len, 0))
+    __chk_fail ();
+
+  unsigned long int dstp = (long int) dstpp;
+  unsigned long int srcp = (long int) srcpp;
+
+  /* Copy from the beginning to the end.  */
+
+  /* If there not too few bytes to copy, use word copy.  */
+  if (len >= OP_T_THRES)
+    {
+      /* Copy just a few bytes to make DSTP aligned.  */
+      len -= (-dstp) % OPSIZ;
+      BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
+
+      /* Copy whole pages from SRCP to DSTP by virtual address manipulation,
+	 as much as possible.  */
+
+      PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
+
+      /* Copy from SRCP to DSTP taking advantage of the known alignment of
+	 DSTP.  Number of bytes remaining is put in the third argument,
+	 i.e. in LEN.  This number may vary from machine to machine.  */
+
+      WORD_COPY_FWD (dstp, srcp, len, len);
+
+      /* Fall out and copy the tail.  */
+    }
+
+  /* There are just a few bytes to copy.  Use byte memory operations.  */
+  BYTE_COPY_FWD (dstp, srcp, len);
+
+  return (void *) dstp;
+}
diff --git a/sysdeps/generic/memset_chk.c b/sysdeps/generic/memset_chk.c
new file mode 100644
index 0000000000..c311914395
--- /dev/null
+++ b/sysdeps/generic/memset_chk.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 1991, 1997, 2003, 2004 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 <string.h>
+#include <memcopy.h>
+
+void *
+__memset_chk (dstpp, c, len, dstlen)
+     void *dstpp;
+     int c;
+     size_t len;
+     size_t dstlen;
+{
+  if (__builtin_expect (dstlen < len, 0))
+    __chk_fail ();
+
+  long int dstp = (long int) dstpp;
+
+  if (len >= 8)
+    {
+      size_t xlen;
+      op_t cccc;
+
+      cccc = (unsigned char) c;
+      cccc |= cccc << 8;
+      cccc |= cccc << 16;
+      if (OPSIZ > 4)
+	/* Do the shift in two steps to avoid warning if long has 32 bits.  */
+	cccc |= (cccc << 16) << 16;
+
+      /* There are at least some bytes to set.
+	 No need to test for LEN == 0 in this alignment loop.  */
+      while (dstp % OPSIZ != 0)
+	{
+	  ((byte *) dstp)[0] = c;
+	  dstp += 1;
+	  len -= 1;
+	}
+
+      /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
+      xlen = len / (OPSIZ * 8);
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  ((op_t *) dstp)[1] = cccc;
+	  ((op_t *) dstp)[2] = cccc;
+	  ((op_t *) dstp)[3] = cccc;
+	  ((op_t *) dstp)[4] = cccc;
+	  ((op_t *) dstp)[5] = cccc;
+	  ((op_t *) dstp)[6] = cccc;
+	  ((op_t *) dstp)[7] = cccc;
+	  dstp += 8 * OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ * 8;
+
+      /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
+      xlen = len / OPSIZ;
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  dstp += OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ;
+    }
+
+  /* Write the last few bytes.  */
+  while (len > 0)
+    {
+      ((byte *) dstp)[0] = c;
+      dstp += 1;
+      len -= 1;
+    }
+
+  return dstpp;
+}
diff --git a/sysdeps/generic/readonly-area.c b/sysdeps/generic/readonly-area.c
new file mode 100644
index 0000000000..df5b96015c
--- /dev/null
+++ b/sysdeps/generic/readonly-area.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 2004 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.  */
+
+/* Return 1 if the whole area PTR .. PTR+SIZE is not writable.
+   Return -1 if it is writable.  */
+
+#include <stdlib.h>
+
+int
+__readonly_str (const void *ptr, size_t size)
+{
+  /* The conservative answer is that all strings are writable.  */
+  return -1;
+}
diff --git a/sysdeps/generic/stpcpy_chk.c b/sysdeps/generic/stpcpy_chk.c
new file mode 100644
index 0000000000..dacda0115a
--- /dev/null
+++ b/sysdeps/generic/stpcpy_chk.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 1992, 1995, 1997, 2002, 2004 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.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST.  */
+char *
+__stpcpy_chk (dest, src, destlen)
+     char *dest;
+     const char *src;
+     size_t destlen;
+{
+  register char *d = dest;
+  register const char *s = src;
+
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+	__chk_fail ();
+      *d++ = *s;
+    }
+  while (*s++ != '\0');
+
+  return d - 1;
+}
diff --git a/sysdeps/generic/strcat_chk.c b/sysdeps/generic/strcat_chk.c
new file mode 100644
index 0000000000..b3fb3470b7
--- /dev/null
+++ b/sysdeps/generic/strcat_chk.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 1991, 1997, 2003, 2004 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 <string.h>
+#include <memcopy.h>
+
+
+/* Append SRC on the end of DEST.  */
+char *
+__strcat_chk (dest, src, destlen)
+     char *dest;
+     const char *src;
+     size_t destlen;
+{
+  char *s1 = dest;
+  const char *s2 = src;
+  reg_char c;
+
+  /* Find the end of the string.  */
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+	__chk_fail ();
+      c = *s1++;
+    }
+  while (c != '\0');
+
+  /* Make S1 point before the next character, so we can increment
+     it while memory is read (wins on pipelined cpus).  */
+  ++destlen;
+  s1 -= 2;
+
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+	__chk_fail ();
+      c = *s2++;
+      *++s1 = c;
+    }
+  while (c != '\0');
+
+  return dest;
+}
diff --git a/sysdeps/generic/strcpy_chk.c b/sysdeps/generic/strcpy_chk.c
new file mode 100644
index 0000000000..5c1ae44cd0
--- /dev/null
+++ b/sysdeps/generic/strcpy_chk.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1991, 1997, 2000, 2003, 2004 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 <stddef.h>
+#include <string.h>
+#include <memcopy.h>
+
+#undef strcpy
+
+/* Copy SRC to DEST with checking of destination buffer overflow.  */
+char *
+__strcpy_chk (dest, src, destlen)
+     char *dest;
+     const char *src;
+     size_t destlen;
+{
+  reg_char c;
+  char *s = (char *) src;
+  const ptrdiff_t off = dest - s - 1;
+
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+	__chk_fail ();
+      c = *s++;
+      s[off] = c;
+    }
+  while (c != '\0');
+
+  return dest;
+}
diff --git a/sysdeps/generic/strncat_chk.c b/sysdeps/generic/strncat_chk.c
new file mode 100644
index 0000000000..953b435a4b
--- /dev/null
+++ b/sysdeps/generic/strncat_chk.c
@@ -0,0 +1,100 @@
+/* Copyright (C) 1991, 1997, 2004 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 <string.h>
+
+#include <memcopy.h>
+
+
+char *
+__strncat_chk (s1, s2, n, s1len)
+     char *s1;
+     const char *s2;
+     size_t n;
+     size_t s1len;
+{
+  reg_char c;
+  char *s = s1;
+
+  /* Find the end of S1.  */
+  do
+    {
+      if (__builtin_expect (s1len-- == 0, 0))
+	__chk_fail ();
+      c = *s1++;
+    }
+  while (c != '\0');
+
+  /* Make S1 point before next character, so we can increment
+     it while memory is read (wins on pipelined cpus).  */
+  ++s1len;
+  s1 -= 2;
+
+  if (n >= 4)
+    {
+      size_t n4 = n >> 2;
+      do
+	{
+	  if (__builtin_expect (s1len-- == 0, 0))
+	    __chk_fail ();
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    return s;
+	  if (__builtin_expect (s1len-- == 0, 0))
+	    __chk_fail ();
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    return s;
+	  if (__builtin_expect (s1len-- == 0, 0))
+	    __chk_fail ();
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    return s;
+	  if (__builtin_expect (s1len-- == 0, 0))
+	    __chk_fail ();
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    return s;
+	} while (--n4 > 0);
+      n &= 3;
+    }
+
+  while (n > 0)
+    {
+      if (__builtin_expect (s1len-- == 0, 0))
+	__chk_fail ();
+      c = *s2++;
+      *++s1 = c;
+      if (c == '\0')
+	return s;
+      n--;
+    }
+
+  if (c != '\0')
+    {
+      if (__builtin_expect (s1len-- == 0, 0))
+	__chk_fail ();
+      *++s1 = '\0';
+    }
+
+  return s;
+}
diff --git a/sysdeps/generic/strncpy_chk.c b/sysdeps/generic/strncpy_chk.c
new file mode 100644
index 0000000000..bdede7738b
--- /dev/null
+++ b/sysdeps/generic/strncpy_chk.c
@@ -0,0 +1,89 @@
+/* Copyright (C) 1991, 1997, 2003, 2004 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 <string.h>
+#include <memcopy.h>
+
+
+char *
+__strncpy_chk (s1, s2, n, s1len)
+     char *s1;
+     const char *s2;
+     size_t n;
+     size_t s1len;
+{
+  reg_char c;
+  char *s = s1;
+
+  if (__builtin_expect (s1len < n, 0))
+    __chk_fail ();
+
+  --s1;
+
+  if (n >= 4)
+    {
+      size_t n4 = n >> 2;
+
+      for (;;)
+	{
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    break;
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    break;
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    break;
+	  c = *s2++;
+	  *++s1 = c;
+	  if (c == '\0')
+	    break;
+	  if (--n4 == 0)
+	    goto last_chars;
+	}
+      n = n - (s1 - s) - 1;
+      if (n == 0)
+	return s;
+      goto zero_fill;
+    }
+
+ last_chars:
+  n &= 3;
+  if (n == 0)
+    return s;
+
+  do
+    {
+      c = *s2++;
+      *++s1 = c;
+      if (--n == 0)
+	return s;
+    }
+  while (c != '\0');
+
+ zero_fill:
+  do
+    *++s1 = '\0';
+  while (--n > 0);
+
+  return s;
+}
diff --git a/sysdeps/i386/i686/memcpy.S b/sysdeps/i386/i686/memcpy.S
index 865967c5c8..00e84ec2e5 100644
--- a/sysdeps/i386/i686/memcpy.S
+++ b/sysdeps/i386/i686/memcpy.S
@@ -1,7 +1,7 @@
 /* Copy memory block and return pointer to beginning of destination block
    For Intel 80x86, x>=6.
    This file is part of the GNU C Library.
-   Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -31,6 +31,13 @@
 #define LEN	SRC+PTR_SIZE
 
 	.text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__memcpy_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	HIDDEN_JUMPTARGET (__chk_fail)
+END (__memcpy_chk)
+#endif
 ENTRY (BP_SYM (memcpy))
 	ENTER
 
diff --git a/sysdeps/i386/i686/memcpy_chk.S b/sysdeps/i386/i686/memcpy_chk.S
new file mode 100644
index 0000000000..561263f9bf
--- /dev/null
+++ b/sysdeps/i386/i686/memcpy_chk.S
@@ -0,0 +1,35 @@
+/* Checking memcpy for x86-64.
+   Copyright (C) 2004 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>
+#include "asm-syntax.h"
+
+#ifndef PIC
+	/* For libc.so this is defined in memcpy.S.
+	   For libc.a, this is a separate source to avoid
+	   memcpy bringing in __chk_fail and all routines
+	   it calls.  */
+        .text
+ENTRY (__memcpy_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	__chk_fail
+	jmp	memcpy
+END (__memcpy_chk)
+#endif
diff --git a/sysdeps/i386/i686/memmove.S b/sysdeps/i386/i686/memmove.S
index 421b4effda..951e139ad4 100644
--- a/sysdeps/i386/i686/memmove.S
+++ b/sysdeps/i386/i686/memmove.S
@@ -1,7 +1,7 @@
 /* Copy memory block and return pointer to beginning of destination block
    For Intel 80x86, x>=6.
    This file is part of the GNU C Library.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 2003.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -31,6 +31,13 @@
 #define LEN	SRC+PTR_SIZE
 
 	.text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__memmove_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	HIDDEN_JUMPTARGET (__chk_fail)
+END (__memmove_chk)
+#endif
 ENTRY (BP_SYM (memmove))
 	ENTER
 
diff --git a/sysdeps/i386/i686/memmove_chk.S b/sysdeps/i386/i686/memmove_chk.S
new file mode 100644
index 0000000000..23382ea8bf
--- /dev/null
+++ b/sysdeps/i386/i686/memmove_chk.S
@@ -0,0 +1,35 @@
+/* Checking memmove for x86-64.
+   Copyright (C) 2004 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>
+#include "asm-syntax.h"
+
+#ifndef PIC
+	/* For libc.so this is defined in memmove.S.
+	   For libc.a, this is a separate source to avoid
+	   memmove bringing in __chk_fail and all routines
+	   it calls.  */
+        .text
+ENTRY (__memmove_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	__chk_fail
+	jmp	memmove
+END (__memmove_chk)
+#endif
diff --git a/sysdeps/i386/i686/mempcpy.S b/sysdeps/i386/i686/mempcpy.S
index 3ea89d4a17..843a35823a 100644
--- a/sysdeps/i386/i686/mempcpy.S
+++ b/sysdeps/i386/i686/mempcpy.S
@@ -31,6 +31,13 @@
 #define LEN	SRC+PTR_SIZE
 
 	.text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__mempcpy_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	HIDDEN_JUMPTARGET (__chk_fail)
+END (__mempcpy_chk)
+#endif
 ENTRY (BP_SYM (__mempcpy))
 	ENTER
 
diff --git a/sysdeps/i386/i686/mempcpy_chk.S b/sysdeps/i386/i686/mempcpy_chk.S
new file mode 100644
index 0000000000..dc9c6095f0
--- /dev/null
+++ b/sysdeps/i386/i686/mempcpy_chk.S
@@ -0,0 +1,35 @@
+/* Checking mempcpy for x86-64.
+   Copyright (C) 2004 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>
+#include "asm-syntax.h"
+
+#ifndef PIC
+	/* For libc.so this is defined in mempcpy.S.
+	   For libc.a, this is a separate source to avoid
+	   mempcpy bringing in __chk_fail and all routines
+	   it calls.  */
+        .text
+ENTRY (__mempcpy_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	__chk_fail
+	jmp	mempcpy
+END (__mempcpy_chk)
+#endif
diff --git a/sysdeps/i386/i686/memset.S b/sysdeps/i386/i686/memset.S
index 4ddcb39731..561188ffec 100644
--- a/sysdeps/i386/i686/memset.S
+++ b/sysdeps/i386/i686/memset.S
@@ -39,6 +39,13 @@
 #endif
 
         .text
+#if defined PIC && !defined NOT_IN_libc && !BZERO_P
+ENTRY (__memset_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	HIDDEN_JUMPTARGET (__chk_fail)
+END (__memset_chk)
+#endif
 ENTRY (BP_SYM (memset))
 	ENTER
 
diff --git a/sysdeps/i386/i686/memset_chk.S b/sysdeps/i386/i686/memset_chk.S
new file mode 100644
index 0000000000..d178654994
--- /dev/null
+++ b/sysdeps/i386/i686/memset_chk.S
@@ -0,0 +1,35 @@
+/* Checking memset for x86-64.
+   Copyright (C) 2004 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>
+#include "asm-syntax.h"
+
+#ifndef PIC
+	/* For libc.so this is defined in memset.S.
+	   For libc.a, this is a separate source to avoid
+	   memset bringing in __chk_fail and all routines
+	   it calls.  */
+        .text
+ENTRY (__memset_chk)
+	movl	12(%esp), %eax
+	cmpl	%eax, 16(%esp)
+	jb	__chk_fail
+	jmp	memset
+END (__memset_chk)
+#endif
diff --git a/sysdeps/unix/sysv/linux/readonly-area.c b/sysdeps/unix/sysv/linux/readonly-area.c
new file mode 100644
index 0000000000..ce5321bcef
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/readonly-area.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 2004 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 <stdint.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libio/libioP.h"
+
+/* Return 1 if the whole area PTR .. PTR+SIZE is not writable.
+   Return -1 if it is writable.  */
+
+int
+__readonly_area (const char *ptr, size_t size)
+{
+  const void *ptr_end = ptr + size;
+
+  FILE *fp = fopen ("/proc/self/maps", "rc");
+  if (fp == NULL)
+    return -1;
+
+  /* We need no locking.  */
+  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  char *line = NULL;
+  size_t linelen = 0;
+
+  while (! feof_unlocked (fp))
+    {
+      if (_IO_getdelim (&line, &linelen, '\n', fp) <= 0)
+	break;
+
+      char *p;
+      uintptr_t from = strtoul (line, &p, 16);
+
+      if (p == line || *p++ != '-')
+	break;
+
+      char *q;
+      uintptr_t to = strtoul (p, &q, 16);
+
+      if (q == p || *q++ != ' ')
+	break;
+
+      if (from < (uintptr_t) ptr_end && to > (uintptr_t) ptr)
+	{
+	  /* Found an entry that at least partially covers the area.  */
+	  if (*q++ != 'r' || *q++ != '-')
+	    break;
+
+	  if (from <= (uintptr_t) ptr && to >= (uintptr_t) ptr_end)
+	    {
+	      size = 0;
+	      break;
+	    }
+	  else if (from <= (uintptr_t) ptr)
+	    size -= to - (uintptr_t) ptr;
+	  else if (to >= (uintptr_t) ptr_end)
+	    size -= (uintptr_t) ptr_end - from;
+	  else
+	    size -= to - from;
+
+	  if (!size)
+	    break;
+	}
+    }
+
+  fclose (fp);
+  free (line);
+
+  /* If the whole area between ptr and ptr_end is covered by read-only
+     VMAs, return 1.  Otherwise return -1.  */
+  return size == 0 ? 1 : -1;
+}
diff --git a/sysdeps/x86_64/memcpy.S b/sysdeps/x86_64/memcpy.S
index de47688241..5f06198b5d 100644
--- a/sysdeps/x86_64/memcpy.S
+++ b/sysdeps/x86_64/memcpy.S
@@ -29,6 +29,12 @@
 #define MEMPCPY_P (defined memcpy)
 
         .text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__memcpy_chk)
+	cmpq	%rdx, %rcx
+	jb	HIDDEN_JUMPTARGET (__chk_fail)
+END (__memcpy_chk)
+#endif
 ENTRY (BP_SYM (memcpy))
 	/* Cutoff for the big loop is a size of 32 bytes since otherwise
 	   the loop will never be entered.  */
diff --git a/sysdeps/x86_64/memcpy_chk.S b/sysdeps/x86_64/memcpy_chk.S
new file mode 100644
index 0000000000..c5251ea2d4
--- /dev/null
+++ b/sysdeps/x86_64/memcpy_chk.S
@@ -0,0 +1,34 @@
+/* Checking memcpy for x86-64.
+   Copyright (C) 2004 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>
+#include "asm-syntax.h"
+
+#ifndef PIC
+	/* For libc.so this is defined in memcpy.S.
+	   For libc.a, this is a separate source to avoid
+	   memcpy bringing in __chk_fail and all routines
+	   it calls.  */
+        .text
+ENTRY (__memcpy_chk)
+	cmpq	%rdx, %rcx
+	jb	__chk_fail
+	jmp	memcpy
+END (__memcpy_chk)
+#endif
diff --git a/sysdeps/x86_64/mempcpy.S b/sysdeps/x86_64/mempcpy.S
index 03aa743fba..4558a1699a 100644
--- a/sysdeps/x86_64/mempcpy.S
+++ b/sysdeps/x86_64/mempcpy.S
@@ -1,4 +1,5 @@
 #define memcpy __mempcpy
+#define __memcpy_chk __mempcpy_chk
 #include <sysdeps/x86_64/memcpy.S>
 
 libc_hidden_def (BP_SYM (__mempcpy))
diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S
new file mode 100644
index 0000000000..c333a4adb3
--- /dev/null
+++ b/sysdeps/x86_64/mempcpy_chk.S
@@ -0,0 +1,34 @@
+/* Checking mempcpy for x86-64.
+   Copyright (C) 2004 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>
+#include "asm-syntax.h"
+
+#ifndef PIC
+	/* For libc.so this is defined in memcpy.S.
+	   For libc.a, this is a separate source to avoid
+	   mempcpy bringing in __chk_fail and all routines
+	   it calls.  */
+        .text
+ENTRY (__mempcpy_chk)
+	cmpq	%rdx, %rcx
+	jb	__chk_fail
+	jmp	mempcpy
+END (__mempcpy_chk)
+#endif
diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S
index 29afa63e7e..6c47f4c863 100644
--- a/sysdeps/x86_64/memset.S
+++ b/sysdeps/x86_64/memset.S
@@ -1,6 +1,6 @@
 /* memset/bzero -- set memory area to CH/0
    Optimized version for x86-64.
-   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>.
 
@@ -32,6 +32,12 @@
 #define LARGE $120000
 
         .text
+#if !BZERO_P && defined PIC && !defined NOT_IN_libc
+ENTRY (__memset_chk)
+	cmpq	%rdx, %rcx
+	jb	HIDDEN_JUMPTARGET (__chk_fail)
+END (__memset_chk)
+#endif
 ENTRY (memset)
 #if BZERO_P
 	mov	%rsi,%rdx	/* Adjust parameter.  */
diff --git a/sysdeps/x86_64/memset_chk.S b/sysdeps/x86_64/memset_chk.S
new file mode 100644
index 0000000000..e62cb58cc0
--- /dev/null
+++ b/sysdeps/x86_64/memset_chk.S
@@ -0,0 +1,34 @@
+/* Checking memset for x86-64.
+   Copyright (C) 2004 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>
+#include "asm-syntax.h"
+
+#ifndef PIC
+	/* For libc.so this is defined in memset.S.
+	   For libc.a, this is a separate source to avoid
+	   memset bringing in __chk_fail and all routines
+	   it calls.  */
+        .text
+ENTRY (__memset_chk)
+	cmpq	%rdx, %rcx
+	jb	__chk_fail
+	jmp	memset
+END (__memset_chk)
+#endif
diff --git a/sysdeps/x86_64/stpcpy_chk.S b/sysdeps/x86_64/stpcpy_chk.S
new file mode 100644
index 0000000000..905e8d7ee3
--- /dev/null
+++ b/sysdeps/x86_64/stpcpy_chk.S
@@ -0,0 +1,3 @@
+#define USE_AS_STPCPY_CHK
+#define STRCPY_CHK __stpcpy_chk
+#include <sysdeps/x86_64/strcpy_chk.S>
diff --git a/sysdeps/x86_64/strcpy_chk.S b/sysdeps/x86_64/strcpy_chk.S
new file mode 100644
index 0000000000..364331553a
--- /dev/null
+++ b/sysdeps/x86_64/strcpy_chk.S
@@ -0,0 +1,211 @@
+/* strcpy/stpcpy checking implementation for x86-64.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@suse.de>, 2002.
+   Adopted into checking version by Jakub Jelinek <jakub@redhat.com>.
+
+   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>
+#include "asm-syntax.h"
+#include "bp-sym.h"
+#include "bp-asm.h"
+
+#ifndef USE_AS_STPCPY_CHK
+# define STRCPY_CHK __strcpy_chk
+#endif
+
+	.text
+ENTRY (STRCPY_CHK)
+	movq	%rsi, %rcx	/* Source register. */
+	andl	$7, %ecx	/* mask alignment bits */
+#ifndef USE_AS_STPCPY_CHK
+	movq	%rdi, %r10	/* Duplicate destination pointer.  */
+#endif
+	jz 5f			/* aligned => start loop */
+
+	cmpq	$8, %rdx	/* Check if only few bytes left in
+				   destination.  */
+	jb	50f
+
+	subq	$8, %rcx	/* We need to align to 8 bytes.  */
+	addq	%rcx, %rdx	/* Subtract count of stored bytes
+				   in the cycle below from destlen.  */
+
+	/* Search the first bytes directly.  */
+0:
+	movb	(%rsi), %al	/* Fetch a byte */
+	testb	%al, %al	/* Is it NUL? */
+	movb	%al, (%rdi)	/* Store it */
+	jz	4f		/* If it was NUL, done! */
+	incq	%rsi
+	incq	%rdi
+	incl	%ecx
+	jnz	0b
+
+5:
+	movq $0xfefefefefefefeff,%r8
+	cmpq	$32, %rdx	/* Are there enough bytes in destination
+				   for the next unrolled round?  */
+	jb	60f		/* If not, avoid the unrolled loop.  */
+
+	/* Now the sources is aligned.  Unfortunatly we cannot force
+	   to have both source and destination aligned, so ignore the
+	   alignment of the destination.  */
+	.p2align 4
+1:
+	/* 1st unroll.  */
+	movq	(%rsi), %rax	/* Read double word (8 bytes).  */
+	addq	$8, %rsi	/* Adjust pointer for next word.  */
+	movq	%rax, %r9	/* Save a copy for NUL finding.  */
+	addq	%r8, %r9	/* add the magic value to the word.  We get
+				   carry bits reported for each byte which
+				   is *not* 0 */
+	jnc	3f		/* highest byte is NUL => return pointer */
+	xorq	%rax, %r9	/* (word+magic)^word */
+	orq	%r8, %r9	/* set all non-carry bits */
+	incq	%r9		/* add 1: if one carry bit was *not* set
+				   the addition will not result in 0.  */
+
+	jnz	3f		/* found NUL => return pointer */
+
+	movq	%rax, (%rdi)	/* Write value to destination.  */
+	addq	$8, %rdi	/* Adjust pointer.  */
+
+	/* 2nd unroll.  */
+	movq	(%rsi), %rax	/* Read double word (8 bytes).  */
+	addq	$8, %rsi	/* Adjust pointer for next word.  */
+	movq	%rax, %r9	/* Save a copy for NUL finding.  */
+	addq	%r8, %r9	/* add the magic value to the word.  We get
+				   carry bits reported for each byte which
+				   is *not* 0 */
+	jnc	3f		/* highest byte is NUL => return pointer */
+	xorq	%rax, %r9	/* (word+magic)^word */
+	orq	%r8, %r9	/* set all non-carry bits */
+	incq	%r9		/* add 1: if one carry bit was *not* set
+				   the addition will not result in 0.  */
+
+	jnz	3f		/* found NUL => return pointer */
+
+	movq	%rax, (%rdi)	/* Write value to destination.  */
+	addq	$8, %rdi	/* Adjust pointer.  */
+
+	/* 3rd unroll.  */
+	movq	(%rsi), %rax	/* Read double word (8 bytes).  */
+	addq	$8, %rsi	/* Adjust pointer for next word.  */
+	movq	%rax, %r9	/* Save a copy for NUL finding.  */
+	addq	%r8, %r9	/* add the magic value to the word.  We get
+				   carry bits reported for each byte which
+				   is *not* 0 */
+	jnc	3f		/* highest byte is NUL => return pointer */
+	xorq	%rax, %r9	/* (word+magic)^word */
+	orq	%r8, %r9	/* set all non-carry bits */
+	incq	%r9		/* add 1: if one carry bit was *not* set
+				   the addition will not result in 0.  */
+
+	jnz	3f		/* found NUL => return pointer */
+
+	movq	%rax, (%rdi)	/* Write value to destination.  */
+	addq	$8, %rdi	/* Adjust pointer.  */
+
+	/* 4th unroll.  */
+	movq	(%rsi), %rax	/* Read double word (8 bytes).  */
+	addq	$8, %rsi	/* Adjust pointer for next word.  */
+	movq	%rax, %r9	/* Save a copy for NUL finding.  */
+	addq	%r8, %r9	/* add the magic value to the word.  We get
+				   carry bits reported for each byte which
+				   is *not* 0 */
+	jnc	3f		/* highest byte is NUL => return pointer */
+	xorq	%rax, %r9	/* (word+magic)^word */
+	orq	%r8, %r9	/* set all non-carry bits */
+	incq	%r9		/* add 1: if one carry bit was *not* set
+				   the addition will not result in 0.  */
+
+	jnz	3f		/* found NUL => return pointer */
+
+	subq	$32, %rdx	/* Adjust destlen.  */
+	movq	%rax, (%rdi)	/* Write value to destination.  */
+	addq	$8, %rdi	/* Adjust pointer.  */
+	cmpq	$32, %rdx	/* Are there enough bytes in destination
+				   for the next unrolled round?  */
+	jae	1b		/* Next iteration.  */
+
+60:
+	cmpq	$8, %rdx	/* Are there enough bytes in destination
+				   for the next unrolled round?  */
+	jb	50f		/* Now, copy and check byte by byte.  */
+
+	movq	(%rsi), %rax	/* Read double word (8 bytes).  */
+	addq	$8, %rsi	/* Adjust pointer for next word.  */
+	movq	%rax, %r9	/* Save a copy for NUL finding.  */
+	addq	%r8, %r9	/* add the magic value to the word.  We get
+				   carry bits reported for each byte which
+				   is *not* 0 */
+	jnc	3f		/* highest byte is NUL => return pointer */
+	xorq	%rax, %r9	/* (word+magic)^word */
+	orq	%r8, %r9	/* set all non-carry bits */
+	incq	%r9		/* add 1: if one carry bit was *not* set
+				   the addition will not result in 0.  */
+
+	jnz	3f		/* found NUL => return pointer */
+
+	subq	$8, %rdx	/* Adjust destlen.  */
+	movq	%rax, (%rdi)	/* Write value to destination.  */
+	addq	$8, %rdi	/* Adjust pointer.  */
+	jmp	60b		/* Next iteration.  */
+
+	/* Do the last few bytes. %rax contains the value to write.
+	   The loop is unrolled twice.  */
+	.p2align 4
+3:
+	/* Note that stpcpy needs to return with the value of the NUL
+	   byte.  */
+	movb	%al, (%rdi)	/* 1st byte.  */
+	testb	%al, %al	/* Is it NUL.  */
+	jz	4f		/* yes, finish.  */
+	incq	%rdi		/* Increment destination.  */
+	movb	%ah, (%rdi)	/* 2nd byte.  */
+	testb	%ah, %ah	/* Is it NUL?.  */
+	jz	4f		/* yes, finish.  */
+	incq	%rdi		/* Increment destination.  */
+	shrq	$16, %rax	/* Shift...  */
+	jmp	3b		/* and look at next two bytes in %rax.  */
+
+51:
+	/* Search the bytes directly, checking for overflows.  */
+	incq	%rsi
+	incq	%rdi
+	decq	%rdx
+	jz	HIDDEN_JUMPTARGET (__chk_fail)
+52:
+	movb	(%rsi), %al	/* Fetch a byte */
+	testb	%al, %al	/* Is it NUL? */
+	movb	%al, (%rdi)	/* Store it */
+	jnz	51b		/* If it was NUL, done! */
+4:
+#ifdef USE_AS_STPCPY_CHK
+	movq	%rdi, %rax	/* Destination is return value.  */
+#else
+	movq	%r10, %rax	/* Source is return value.  */
+#endif
+	retq
+
+50:
+	testq	%rdx, %rdx
+	jnz	52b
+	jmp	HIDDEN_JUMPTARGET (__chk_fail)
+
+END (STRCPY_CHK)