summaryrefslogtreecommitdiff
path: root/libc/string
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2004-09-02 14:39:38 +0000
committerManuel Novoa III <mjn3@codepoet.org>2004-09-02 14:39:38 +0000
commitbec90733b9de6e7d75b8bda19b3f0a7117e6b78d (patch)
tree474ca0f3b80b7990ff33e547d42c1e7dc3014e3b /libc/string
parentc4cedfc718426337b0215c256c184d2b4e20cd06 (diff)
Add a couple of mips-specific string funcs.
Port the generic optimized string funcs from glibc, with some tweaks to cut their size a little. The main change is making memmove call memcpy for forward copying to trim redundant code. Make use of both the generic and arch-specific speed-optimized string funcs configurable. Arch-specific take precedence over generic, and generic takes precedence over basic size-optimized uClibc funcs.
Diffstat (limited to 'libc/string')
-rw-r--r--libc/string/Makefile12
-rw-r--r--libc/string/generic/Makefile48
-rw-r--r--libc/string/generic/bp-checks.h129
-rw-r--r--libc/string/generic/memchr.c175
-rw-r--r--libc/string/generic/memcmp.c340
-rw-r--r--libc/string/generic/memcopy.h150
-rw-r--r--libc/string/generic/memcpy.c246
-rw-r--r--libc/string/generic/memmem.c50
-rw-r--r--libc/string/generic/memmove.c278
-rw-r--r--libc/string/generic/mempcpy.c18
-rw-r--r--libc/string/generic/memrchr.c174
-rw-r--r--libc/string/generic/memset.c90
-rw-r--r--libc/string/generic/pagecopy.h75
-rw-r--r--libc/string/generic/rawmemchr.c160
-rw-r--r--libc/string/generic/strcat.c51
-rw-r--r--libc/string/generic/strchr.c190
-rw-r--r--libc/string/generic/strchrnul.c168
-rw-r--r--libc/string/generic/strcmp.c52
-rw-r--r--libc/string/generic/strcpy.c50
-rw-r--r--libc/string/generic/strcspn.c39
-rw-r--r--libc/string/generic/strlen.c152
-rw-r--r--libc/string/generic/strncat.c81
-rw-r--r--libc/string/generic/strncmp.c72
-rw-r--r--libc/string/generic/strncpy.c86
-rw-r--r--libc/string/generic/strnlen.c158
-rw-r--r--libc/string/generic/strrchr.c49
-rw-r--r--libc/string/generic/strsep.c65
-rw-r--r--libc/string/generic/strspn.c46
-rw-r--r--libc/string/generic/strstr.c116
-rw-r--r--libc/string/generic/strtok_r.c69
-rw-r--r--libc/string/mips/Makefile38
-rw-r--r--libc/string/mips/memcpy.S140
-rw-r--r--libc/string/mips/memset.S90
-rw-r--r--libc/string/mips/sysdep.h51
34 files changed, 3706 insertions, 2 deletions
diff --git a/libc/string/Makefile b/libc/string/Makefile
index 37a57cc26..02c86d6aa 100644
--- a/libc/string/Makefile
+++ b/libc/string/Makefile
@@ -20,10 +20,18 @@ TOPDIR=../../
include $(TOPDIR)Rules.mak
DIRS=
+
+ifeq ($(UCLIBC_HAS_STRING_GENERIC_OPT),y)
+DIRS += generic
+endif
+
+ifeq ($(UCLIBC_HAS_STRING_ARCH_OPT),y)
ifeq ($(TARGET_ARCH),$(wildcard $(TARGET_ARCH)))
-DIRS = $(TARGET_ARCH)
+DIRS += $(TARGET_ARCH)
endif
-ALL_SUBDIRS = arm frv i386 sh64 powerpc
+endif
+
+ALL_SUBDIRS = generic arm frv i386 sh64 powerpc mips
MSRC= wstring.c
MOBJ= basename.o bcopy.o bzero.o dirname.o ffs.o memccpy.o memchr.o memcmp.o \
diff --git a/libc/string/generic/Makefile b/libc/string/generic/Makefile
new file mode 100644
index 000000000..3f9af72a3
--- /dev/null
+++ b/libc/string/generic/Makefile
@@ -0,0 +1,48 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org>
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Library General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option) any
+# later version.
+#
+# This program 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 Library General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+TOPDIR=../../../
+include $(TOPDIR)Rules.mak
+
+CSRC= memchr.c memcmp.c memcpy.c memmem.c memmove.c mempcpy.c memrchr.c \
+ memset.c rawmemchr.c strcat.c strchr.c strchrnul.c strcmp.c strcpy.c \
+ strcspn.c strlen.c strncat.c strncmp.c strncpy.c strnlen.c \
+ strrchr.c strsep.c strspn.c strstr.c strtok_r.c
+
+COBJS=$(patsubst %.c,%.o, $(CSRC))
+
+OBJS=$(COBJS)
+
+all: $(OBJS) $(LIBC)
+
+$(LIBC): ar-target
+
+ar-target: $(OBJS)
+ $(AR) $(ARFLAGS) $(LIBC) $(OBJS)
+
+# $(MOBJ): $(MSRC)
+# $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+# $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+$(COBJS): %.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+clean:
+ $(RM) *.[oa] *~ core
+
diff --git a/libc/string/generic/bp-checks.h b/libc/string/generic/bp-checks.h
new file mode 100644
index 000000000..efbb84716
--- /dev/null
+++ b/libc/string/generic/bp-checks.h
@@ -0,0 +1,129 @@
+/* Bounded-pointer checking macros for C.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Greg McGary <greg@mcgary.org>
+
+ 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. */
+
+#ifndef _bp_checks_h_
+#define _bp_checks_h_ 1
+
+#if __BOUNDED_POINTERS__
+
+# define BOUNDS_VIOLATED (__builtin_trap (), 0)
+
+/* Verify that pointer's value >= low. Return pointer value. */
+# define CHECK_BOUNDS_LOW(ARG) \
+ (((__ptrvalue (ARG) < __ptrlow (ARG)) && BOUNDS_VIOLATED), \
+ __ptrvalue (ARG))
+
+/* Verify that pointer's value < high. Return pointer value. */
+# define CHECK_BOUNDS_HIGH(ARG) \
+ (((__ptrvalue (ARG) > __ptrhigh (ARG)) && BOUNDS_VIOLATED), \
+ __ptrvalue (ARG))
+
+# define _CHECK_N(ARG, N, COND) \
+ (((COND) \
+ && (__ptrvalue (ARG) < __ptrlow (ARG) \
+ || __ptrvalue (ARG) + (N) > __ptrhigh (ARG)) \
+ && BOUNDS_VIOLATED), \
+ __ptrvalue (ARG))
+
+extern void *__unbounded __ubp_memchr (const void *__unbounded, int, unsigned);
+
+# define _CHECK_STRING(ARG, COND) \
+ (((COND) \
+ && (__ptrvalue (ARG) < __ptrlow (ARG) \
+ || !__ubp_memchr (__ptrvalue (ARG), '\0', \
+ (__ptrhigh (ARG) - __ptrvalue (ARG)))) \
+ && BOUNDS_VIOLATED), \
+ __ptrvalue (ARG))
+
+/* Check bounds of a pointer seated to an array of N objects. */
+# define CHECK_N(ARG, N) _CHECK_N ((ARG), (N), 1)
+/* Same as CHECK_N, but tolerate ARG == NULL. */
+# define CHECK_N_NULL_OK(ARG, N) _CHECK_N ((ARG), (N), __ptrvalue (ARG))
+
+/* Check bounds of a pointer seated to a single object. */
+# define CHECK_1(ARG) CHECK_N ((ARG), 1)
+/* Same as CHECK_1, but tolerate ARG == NULL. */
+# define CHECK_1_NULL_OK(ARG) CHECK_N_NULL_OK ((ARG), 1)
+
+/* Check for NUL-terminator within string's bounds. */
+# define CHECK_STRING(ARG) _CHECK_STRING ((ARG), 1)
+/* Same as CHECK_STRING, but tolerate ARG == NULL. */
+# define CHECK_STRING_NULL_OK(ARG) _CHECK_STRING ((ARG), __ptrvalue (ARG))
+
+/* Check bounds of signal syscall args with type sigset_t. */
+# define CHECK_SIGSET(SET) CHECK_N ((SET), _NSIG / (8 * sizeof *(SET)))
+/* Same as CHECK_SIGSET, but tolerate SET == NULL. */
+# define CHECK_SIGSET_NULL_OK(SET) CHECK_N_NULL_OK ((SET), _NSIG / (8 * sizeof *(SET)))
+
+# if defined (_IOC_SIZESHIFT) && defined (_IOC_SIZEBITS)
+/* Extract the size of the ioctl data and check its bounds. */
+# define CHECK_IOCTL(ARG, CMD) \
+ CHECK_N ((const char *) (ARG), \
+ (((CMD) >> _IOC_SIZESHIFT) & ((1 << _IOC_SIZEBITS) - 1)))
+# else
+/* We don't know the size of the ioctl data, so the best we can do
+ is check that the first byte is within bounds. */
+# define CHECK_IOCTL(ARG, CMD) CHECK_1 ((const char *) ARG)
+# endif
+
+/* Check bounds of `struct flock *' for the locking fcntl commands. */
+# define CHECK_FCNTL(ARG, CMD) \
+ (((CMD) == F_GETLK || (CMD) == F_SETLK || (CMD) == F_SETLKW) \
+ ? CHECK_1 ((struct flock *) ARG) : (unsigned long) (ARG))
+
+/* Check bounds of an array of mincore residency-status flags that
+ cover a region of NBYTES. Such a vector occupies one byte per page
+ of memory. */
+# define CHECK_N_PAGES(ARG, NBYTES) \
+ ({ int _page_size_ = sysconf (_SC_PAGE_SIZE); \
+ CHECK_N ((const char *) (ARG), \
+ ((NBYTES) + _page_size_ - 1) / _page_size_); })
+
+/* Return a bounded pointer with value PTR that satisfies CHECK_N (PTR, N). */
+# define BOUNDED_N(PTR, N) \
+ ({ __typeof (PTR) __bounded _p_; \
+ __ptrvalue _p_ = __ptrlow _p_ = __ptrvalue (PTR); \
+ __ptrhigh _p_ = __ptrvalue _p_ + (N); \
+ _p_; })
+
+#else /* !__BOUNDED_POINTERS__ */
+
+/* Do nothing if not compiling with -fbounded-pointers. */
+
+# define BOUNDS_VIOLATED
+# define CHECK_BOUNDS_LOW(ARG) (ARG)
+# define CHECK_BOUNDS_HIGH(ARG) (ARG)
+# define CHECK_1(ARG) (ARG)
+# define CHECK_1_NULL_OK(ARG) (ARG)
+# define CHECK_N(ARG, N) (ARG)
+# define CHECK_N_NULL_OK(ARG, N) (ARG)
+# define CHECK_STRING(ARG) (ARG)
+# define CHECK_SIGSET(SET) (SET)
+# define CHECK_SIGSET_NULL_OK(SET) (SET)
+# define CHECK_IOCTL(ARG, CMD) (ARG)
+# define CHECK_FCNTL(ARG, CMD) (ARG)
+# define CHECK_N_PAGES(ARG, NBYTES) (ARG)
+# define BOUNDED_N(PTR, N) (PTR)
+
+#endif /* !__BOUNDED_POINTERS__ */
+
+#define BOUNDED_1(PTR) BOUNDED_N (PTR, 1)
+
+#endif /* _bp_checks_h_ */
diff --git a/libc/string/generic/memchr.c b/libc/string/generic/memchr.c
new file mode 100644
index 000000000..6116b8f92
--- /dev/null
+++ b/libc/string/generic/memchr.c
@@ -0,0 +1,175 @@
+/* Copyright (C) 1991,93,96,97,99,2000,2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
+ with help from Dan Sahlin (dan@sics.se) and
+ commentary by Jim Blandy (jimb@ai.mit.edu);
+ adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
+ and implemented by Roland McGrath (roland@ai.mit.edu).
+
+ 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 <stdlib.h>
+#include <limits.h>
+
+#include "memcopy.h"
+
+#define LONG_MAX_32_BITS 2147483647
+
+#undef memchr
+
+/* Search no more than N bytes of S for C. */
+void * memchr (const void * s, int c_in, size_t n)
+{
+ const unsigned char *char_ptr;
+ const unsigned long int *longword_ptr;
+ unsigned long int longword, magic_bits, charmask;
+ unsigned reg_char c;
+
+ c = (unsigned char) c_in;
+
+ /* Handle the first few characters by reading one character at a time.
+ Do this until CHAR_PTR is aligned on a longword boundary. */
+ for (char_ptr = (const unsigned char *) s;
+ n > 0 && ((unsigned long int) char_ptr
+ & (sizeof (longword) - 1)) != 0;
+ --n, ++char_ptr)
+ if (*char_ptr == c)
+ return (void *) char_ptr;
+
+ /* All these elucidatory comments refer to 4-byte longwords,
+ but the theory applies equally well to 8-byte longwords. */
+
+ longword_ptr = (unsigned long int *) char_ptr;
+
+ /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
+ the "holes." Note that there is a hole just to the left of
+ each byte, with an extra at the end:
+
+ bits: 01111110 11111110 11111110 11111111
+ bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
+
+ The 1-bits make sure that carries propagate to the next 0-bit.
+ The 0-bits provide holes for carries to fall into. */
+
+ if (sizeof (longword) != 4 && sizeof (longword) != 8)
+ abort ();
+
+#if LONG_MAX <= LONG_MAX_32_BITS
+ magic_bits = 0x7efefeff;
+#else
+ magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff;
+#endif
+
+ /* Set up a longword, each of whose bytes is C. */
+ charmask = c | (c << 8);
+ charmask |= charmask << 16;
+#if LONG_MAX > LONG_MAX_32_BITS
+ charmask |= charmask << 32;
+#endif
+
+ /* Instead of the traditional loop which tests each character,
+ we will test a longword at a time. The tricky part is testing
+ if *any of the four* bytes in the longword in question are zero. */
+ while (n >= sizeof (longword))
+ {
+ /* We tentatively exit the loop if adding MAGIC_BITS to
+ LONGWORD fails to change any of the hole bits of LONGWORD.
+
+ 1) Is this safe? Will it catch all the zero bytes?
+ Suppose there is a byte with all zeros. Any carry bits
+ propagating from its left will fall into the hole at its
+ least significant bit and stop. Since there will be no
+ carry from its most significant bit, the LSB of the
+ byte to the left will be unchanged, and the zero will be
+ detected.
+
+ 2) Is this worthwhile? Will it ignore everything except
+ zero bytes? Suppose every byte of LONGWORD has a bit set
+ somewhere. There will be a carry into bit 8. If bit 8
+ is set, this will carry into bit 16. If bit 8 is clear,
+ one of bits 9-15 must be set, so there will be a carry
+ into bit 16. Similarly, there will be a carry into bit
+ 24. If one of bits 24-30 is set, there will be a carry
+ into bit 31, so all of the hole bits will be changed.
+
+ The one misfire occurs when bits 24-30 are clear and bit
+ 31 is set; in this case, the hole at bit 31 is not
+ changed. If we had access to the processor carry flag,
+ we could close this loophole by putting the fourth hole
+ at bit 32!
+
+ So it ignores everything except 128's, when they're aligned
+ properly.
+
+ 3) But wait! Aren't we looking for C, not zero?
+ Good point. So what we do is XOR LONGWORD with a longword,
+ each of whose bytes is C. This turns each byte that is C
+ into a zero. */
+
+ longword = *longword_ptr++ ^ charmask;
+
+ /* Add MAGIC_BITS to LONGWORD. */
+ if ((((longword + magic_bits)
+
+ /* Set those bits that were unchanged by the addition. */
+ ^ ~longword)
+
+ /* Look at only the hole bits. If any of the hole bits
+ are unchanged, most likely one of the bytes was a
+ zero. */
+ & ~magic_bits) != 0)
+ {
+ /* Which of the bytes was C? If none of them were, it was
+ a misfire; continue the search. */
+
+ const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);
+
+ if (cp[0] == c)
+ return (void *) cp;
+ if (cp[1] == c)
+ return (void *) &cp[1];
+ if (cp[2] == c)
+ return (void *) &cp[2];
+ if (cp[3] == c)
+ return (void *) &cp[3];
+#if LONG_MAX > 2147483647
+ if (cp[4] == c)
+ return (void *) &cp[4];
+ if (cp[5] == c)
+ return (void *) &cp[5];
+ if (cp[6] == c)
+ return (void *) &cp[6];
+ if (cp[7] == c)
+ return (void *) &cp[7];
+#endif
+ }
+
+ n -= sizeof (longword);
+ }
+
+ char_ptr = (const unsigned char *) longword_ptr;
+
+ while (n-- > 0)
+ {
+ if (*char_ptr == c)
+ return (void *) char_ptr;
+ else
+ ++char_ptr;
+ }
+
+ return 0;
+}
diff --git a/libc/string/generic/memcmp.c b/libc/string/generic/memcmp.c
new file mode 100644
index 000000000..d9c3a7cab
--- /dev/null
+++ b/libc/string/generic/memcmp.c
@@ -0,0 +1,340 @@
+/* Copyright (C) 1991,1993,1995,1997,1998,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>
+
+#undef memcmp
+
+#include "memcopy.h"
+
+#include <endian.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define WORDS_BIGENDIAN
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
+#else
+# define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
+#endif
+
+/* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */
+
+/* The strategy of this memcmp is:
+
+ 1. Compare bytes until one of the block pointers is aligned.
+
+ 2. Compare using memcmp_common_alignment or
+ memcmp_not_common_alignment, regarding the alignment of the other
+ block after the initial byte operations. The maximum number of
+ full words (of type op_t) are compared in this way.
+
+ 3. Compare the few remaining bytes. */
+
+#ifndef WORDS_BIGENDIAN
+/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
+ A and B are known to be different.
+ This is needed only on little-endian machines. */
+
+static int memcmp_bytes __P((op_t, op_t));
+
+# ifdef __GNUC__
+__inline
+# endif
+static int
+memcmp_bytes (a, b)
+ op_t a, b;
+{
+ long int srcp1 = (long int) &a;
+ long int srcp2 = (long int) &b;
+ op_t a0, b0;
+
+ do
+ {
+ a0 = ((byte *) srcp1)[0];
+ b0 = ((byte *) srcp2)[0];
+ srcp1 += 1;
+ srcp2 += 1;
+ }
+ while (a0 == b0);
+ return a0 - b0;
+}
+#endif
+
+static int memcmp_common_alignment __P((long, long, size_t));
+
+/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
+ objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for
+ memory operations on `op_t's. */
+static int
+memcmp_common_alignment (srcp1, srcp2, len)
+ long int srcp1;
+ long int srcp2;
+ size_t len;
+{
+ op_t a0, a1;
+ op_t b0, b1;
+
+ switch (len % 4)
+ {
+ default: /* Avoid warning about uninitialized local variables. */
+ case 2:
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ srcp1 -= 2 * OPSIZ;
+ srcp2 -= 2 * OPSIZ;
+ len += 2;
+ goto do1;
+ case 3:
+ a1 = ((op_t *) srcp1)[0];
+ b1 = ((op_t *) srcp2)[0];
+ srcp1 -= OPSIZ;
+ srcp2 -= OPSIZ;
+ len += 1;
+ goto do2;
+ case 0:
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ return 0;
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ goto do3;
+ case 1:
+ a1 = ((op_t *) srcp1)[0];
+ b1 = ((op_t *) srcp2)[0];
+ srcp1 += OPSIZ;
+ srcp2 += OPSIZ;
+ len -= 1;
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ goto do0;
+ /* Fall through. */
+ }
+
+ do
+ {
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ if (a1 != b1)
+ return CMP_LT_OR_GT (a1, b1);
+
+ do3:
+ a1 = ((op_t *) srcp1)[1];
+ b1 = ((op_t *) srcp2)[1];
+ if (a0 != b0)
+ return CMP_LT_OR_GT (a0, b0);
+
+ do2:
+ a0 = ((op_t *) srcp1)[2];
+ b0 = ((op_t *) srcp2)[2];
+ if (a1 != b1)
+ return CMP_LT_OR_GT (a1, b1);
+
+ do1:
+ a1 = ((op_t *) srcp1)[3];
+ b1 = ((op_t *) srcp2)[3];
+ if (a0 != b0)
+ return CMP_LT_OR_GT (a0, b0);
+
+ srcp1 += 4 * OPSIZ;
+ srcp2 += 4 * OPSIZ;
+ len -= 4;
+ }
+ while (len != 0);
+
+ /* This is the right position for do0. Please don't move
+ it into the loop. */
+ do0:
+ if (a1 != b1)
+ return CMP_LT_OR_GT (a1, b1);
+ return 0;
+}
+
+static int memcmp_not_common_alignment __P((long, long, size_t));
+
+/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
+ `op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory
+ operations on `op_t', but SRCP1 *should be unaligned*. */
+static int
+memcmp_not_common_alignment (srcp1, srcp2, len)
+ long int srcp1;
+ long int srcp2;
+ size_t len;
+{
+ op_t a0, a1, a2, a3;
+ op_t b0, b1, b2, b3;
+ op_t x;
+ int shl, shr;
+
+ /* Calculate how to shift a word read at the memory operation
+ aligned srcp1 to make it aligned for comparison. */
+
+ shl = 8 * (srcp1 % OPSIZ);
+ shr = 8 * OPSIZ - shl;
+
+ /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
+ it points in the middle of. */
+ srcp1 &= -OPSIZ;
+
+ switch (len % 4)
+ {
+ default: /* Avoid warning about uninitialized local variables. */
+ case 2:
+ a1 = ((op_t *) srcp1)[0];
+ a2 = ((op_t *) srcp1)[1];
+ b2 = ((op_t *) srcp2)[0];
+ srcp1 -= 1 * OPSIZ;
+ srcp2 -= 2 * OPSIZ;
+ len += 2;
+ goto do1;
+ case 3:
+ a0 = ((op_t *) srcp1)[0];
+ a1 = ((op_t *) srcp1)[1];
+ b1 = ((op_t *) srcp2)[0];
+ srcp2 -= 1 * OPSIZ;
+ len += 1;
+ goto do2;
+ case 0:
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ return 0;
+ a3 = ((op_t *) srcp1)[0];
+ a0 = ((op_t *) srcp1)[1];
+ b0 = ((op_t *) srcp2)[0];
+ srcp1 += 1 * OPSIZ;
+ goto do3;
+ case 1:
+ a2 = ((op_t *) srcp1)[0];
+ a3 = ((op_t *) srcp1)[1];
+ b3 = ((op_t *) srcp2)[0];
+ srcp1 += 2 * OPSIZ;
+ srcp2 += 1 * OPSIZ;
+ len -= 1;
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ goto do0;
+ /* Fall through. */
+ }
+
+ do
+ {
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ x = MERGE(a2, shl, a3, shr);
+ if (x != b3)
+ return CMP_LT_OR_GT (x, b3);
+
+ do3:
+ a1 = ((op_t *) srcp1)[1];
+ b1 = ((op_t *) srcp2)[1];
+ x = MERGE(a3, shl, a0, shr);
+ if (x != b0)
+ return CMP_LT_OR_GT (x, b0);
+
+ do2:
+ a2 = ((op_t *) srcp1)[2];
+ b2 = ((op_t *) srcp2)[2];
+ x = MERGE(a0, shl, a1, shr);
+ if (x != b1)
+ return CMP_LT_OR_GT (x, b1);
+
+ do1:
+ a3 = ((op_t *) srcp1)[3];
+ b3 = ((op_t *) srcp2)[3];
+ x = MERGE(a1, shl, a2, shr);
+ if (x != b2)
+ return CMP_LT_OR_GT (x, b2);
+
+ srcp1 += 4 * OPSIZ;
+ srcp2 += 4 * OPSIZ;
+ len -= 4;
+ }
+ while (len != 0);
+
+ /* This is the right position for do0. Please don't move
+ it into the loop. */
+ do0:
+ x = MERGE(a2, shl, a3, shr);
+ if (x != b3)
+ return CMP_LT_OR_GT (x, b3);
+ return 0;
+}
+
+int
+memcmp (s1, s2, len)
+ const __ptr_t s1;
+ const __ptr_t s2;
+ size_t len;
+{
+ op_t a0;
+ op_t b0;
+ long int srcp1 = (long int) s1;
+ long int srcp2 = (long int) s2;
+ op_t res;
+
+ if (len >= OP_T_THRES)
+ {
+ /* There are at least some bytes to compare. No need to test
+ for LEN == 0 in this alignment loop. */
+ while (srcp2 % OPSIZ != 0)
+ {
+ a0 = ((byte *) srcp1)[0];
+ b0 = ((byte *) srcp2)[0];
+ srcp1 += 1;
+ srcp2 += 1;
+ res = a0 - b0;
+ if (res != 0)
+ return res;
+ len -= 1;
+ }
+
+ /* SRCP2 is now aligned for memory operations on `op_t'.
+ SRCP1 alignment determines if we can do a simple,
+ aligned compare or need to shuffle bits. */
+
+ if (srcp1 % OPSIZ == 0)
+ res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
+ else
+ res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
+ if (res != 0)
+ return res;
+
+ /* Number of bytes remaining in the interval [0..OPSIZ-1]. */
+ srcp1 += len & -OPSIZ;
+ srcp2 += len & -OPSIZ;
+ len %= OPSIZ;
+ }
+
+ /* There are just a few bytes to compare. Use byte memory operations. */
+ while (len != 0)
+ {
+ a0 = ((byte *) srcp1)[0];
+ b0 = ((byte *) srcp2)[0];
+ srcp1 += 1;
+ srcp2 += 1;
+ res = a0 - b0;
+ if (res != 0)
+ return res;
+ len -= 1;
+ }
+
+ return 0;
+}
+#ifdef weak_alias
+# undef bcmp
+weak_alias (memcmp, bcmp)
+#endif
diff --git a/libc/string/generic/memcopy.h b/libc/string/generic/memcopy.h
new file mode 100644
index 000000000..df1ba9a97
--- /dev/null
+++ b/libc/string/generic/memcopy.h
@@ -0,0 +1,150 @@
+/* memcopy.h -- definitions for memory copy functions. Generic C version.
+ Copyright (C) 1991, 1992, 1993, 1997 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. */
+
+/* The strategy of the memory functions is:
+
+ 1. Copy bytes until the destination pointer is aligned.
+
+ 2. Copy words in unrolled loops. If the source and destination
+ are not aligned in the same way, use word memory operations,
+ but shift and merge two read words before writing.
+
+ 3. Copy the few remaining bytes.
+
+ This is fast on processors that have at least 10 registers for
+ allocation by GCC, and that can access memory at reg+const in one
+ instruction.
+
+ I made an "exhaustive" test of this memmove when I wrote it,
+ exhaustive in the sense that I tried all alignment and length
+ combinations, with and without overlap. */
+
+#include <sys/cdefs.h>
+#include <endian.h>
+
+/* The macros defined in this file are:
+
+ BYTE_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_to_copy)
+
+ BYTE_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_to_copy)
+
+ WORD_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_remaining, nbytes_to_copy)
+
+ WORD_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_remaining, nbytes_to_copy)
+
+ MERGE(old_word, sh_1, new_word, sh_2)
+ [I fail to understand. I feel stupid. --roland]
+*/
+
+/* Type to use for aligned memory operations.
+ This should normally be the biggest type supported by a single load
+ and store. */
+#define op_t unsigned long int
+#define OPSIZ (sizeof(op_t))
+
+/* Type to use for unaligned operations. */
+typedef unsigned char byte;
+