xref: /netbsd-src/common/lib/libc/string/bcopy.c (revision 23e81d3280fb561f21bc9bbc61f626819e130d83)
1*23e81d32Smartin /*	$NetBSD: bcopy.c,v 1.13 2018/02/12 11:14:15 martin Exp $	*/
237c9f0a6Schristos 
337c9f0a6Schristos /*-
437c9f0a6Schristos  * Copyright (c) 1990, 1993
537c9f0a6Schristos  *	The Regents of the University of California.  All rights reserved.
637c9f0a6Schristos  *
737c9f0a6Schristos  * This code is derived from software contributed to Berkeley by
837c9f0a6Schristos  * Chris Torek.
937c9f0a6Schristos  *
1037c9f0a6Schristos  * Redistribution and use in source and binary forms, with or without
1137c9f0a6Schristos  * modification, are permitted provided that the following conditions
1237c9f0a6Schristos  * are met:
1337c9f0a6Schristos  * 1. Redistributions of source code must retain the above copyright
1437c9f0a6Schristos  *    notice, this list of conditions and the following disclaimer.
1537c9f0a6Schristos  * 2. Redistributions in binary form must reproduce the above copyright
1637c9f0a6Schristos  *    notice, this list of conditions and the following disclaimer in the
1737c9f0a6Schristos  *    documentation and/or other materials provided with the distribution.
1837c9f0a6Schristos  * 3. Neither the name of the University nor the names of its contributors
1937c9f0a6Schristos  *    may be used to endorse or promote products derived from this software
2037c9f0a6Schristos  *    without specific prior written permission.
2137c9f0a6Schristos  *
2237c9f0a6Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2337c9f0a6Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2437c9f0a6Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2537c9f0a6Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2637c9f0a6Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2737c9f0a6Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2837c9f0a6Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2937c9f0a6Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3037c9f0a6Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3137c9f0a6Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3237c9f0a6Schristos  * SUCH DAMAGE.
3337c9f0a6Schristos  */
3437c9f0a6Schristos 
3537c9f0a6Schristos #include <sys/cdefs.h>
3637c9f0a6Schristos #if defined(LIBC_SCCS) && !defined(lint)
3737c9f0a6Schristos #if 0
3837c9f0a6Schristos static char sccsid[] = "@(#)bcopy.c	8.1 (Berkeley) 6/4/93";
3937c9f0a6Schristos #else
40*23e81d32Smartin __RCSID("$NetBSD: bcopy.c,v 1.13 2018/02/12 11:14:15 martin Exp $");
4137c9f0a6Schristos #endif
4237c9f0a6Schristos #endif /* LIBC_SCCS and not lint */
4337c9f0a6Schristos 
4437c9f0a6Schristos #if !defined(_KERNEL) && !defined(_STANDALONE)
4537c9f0a6Schristos #include <assert.h>
4637c9f0a6Schristos #include <string.h>
4737c9f0a6Schristos #else
4837c9f0a6Schristos #include <lib/libkern/libkern.h>
49d0b9e6c9Stsutsui #if !defined(MEMCOPY) && defined(_STANDALONE)
50d0b9e6c9Stsutsui #include <lib/libsa/stand.h>
51d0b9e6c9Stsutsui #endif
5237c9f0a6Schristos #endif
5337c9f0a6Schristos 
54e3dae427Sjoerg #if defined(_FORTIFY_SOURCE) || defined(_STANDALONE) || defined(_KERNEL)
55a8565cf9Schristos #undef bcopy
56a8565cf9Schristos #undef memcpy
57a8565cf9Schristos #undef memmove
58a8565cf9Schristos #endif
59a8565cf9Schristos 
609e32ad04Schristos #ifndef __OPTIMIZE_SIZE__
6137c9f0a6Schristos /*
6237c9f0a6Schristos  * sizeof(word) MUST BE A POWER OF TWO
6337c9f0a6Schristos  * SO THAT wmask BELOW IS ALL ONES
6437c9f0a6Schristos  */
6537c9f0a6Schristos typedef	long word;		/* "word" used for optimal copy speed */
6637c9f0a6Schristos 
6737c9f0a6Schristos #define	wsize	sizeof(word)
6837c9f0a6Schristos #define	wmask	(wsize - 1)
6937c9f0a6Schristos 
7037c9f0a6Schristos /*
7137c9f0a6Schristos  * Copy a block of memory, handling overlap.
7237c9f0a6Schristos  * This is the routine that actually implements
7337c9f0a6Schristos  * (the portable versions of) bcopy, memcpy, and memmove.
7437c9f0a6Schristos  */
75f5c28010Sapb #if defined(MEMCOPY)
7637c9f0a6Schristos void *
memcpy(void * dst0,const void * src0,size_t length)77a8565cf9Schristos memcpy(void *dst0, const void *src0, size_t length)
78f5c28010Sapb #elif defined(MEMMOVE)
7937c9f0a6Schristos void *
80a8565cf9Schristos memmove(void *dst0, const void *src0, size_t length)
8137c9f0a6Schristos #else
8237c9f0a6Schristos void
83a8565cf9Schristos bcopy(const void *src0, void *dst0, size_t length)
8437c9f0a6Schristos #endif
8537c9f0a6Schristos {
8637c9f0a6Schristos 	char *dst = dst0;
8737c9f0a6Schristos 	const char *src = src0;
8837c9f0a6Schristos 	size_t t;
8937c9f0a6Schristos 	unsigned long u;
9037c9f0a6Schristos 
9137c9f0a6Schristos 	if (length == 0 || dst == src)		/* nothing to do */
9237c9f0a6Schristos 		goto done;
9337c9f0a6Schristos 
9437c9f0a6Schristos 	/*
9537c9f0a6Schristos 	 * Macros: loop-t-times; and loop-t-times, t>0
9637c9f0a6Schristos 	 */
9737c9f0a6Schristos #define	TLOOP(s) if (t) TLOOP1(s)
9837c9f0a6Schristos #define	TLOOP1(s) do { s; } while (--t)
9937c9f0a6Schristos 
10037c9f0a6Schristos 	if ((unsigned long)dst < (unsigned long)src) {
10137c9f0a6Schristos 		/*
10237c9f0a6Schristos 		 * Copy forward.
10337c9f0a6Schristos 		 */
10437c9f0a6Schristos 		u = (unsigned long)src;	/* only need low bits */
10537c9f0a6Schristos 		if ((u | (unsigned long)dst) & wmask) {
10637c9f0a6Schristos 			/*
10737c9f0a6Schristos 			 * Try to align operands.  This cannot be done
10837c9f0a6Schristos 			 * unless the low bits match.
10937c9f0a6Schristos 			 */
11037c9f0a6Schristos 			if ((u ^ (unsigned long)dst) & wmask || length < wsize)
11137c9f0a6Schristos 				t = length;
11237c9f0a6Schristos 			else
11337c9f0a6Schristos 				t = wsize - (size_t)(u & wmask);
11437c9f0a6Schristos 			length -= t;
11537c9f0a6Schristos 			TLOOP1(*dst++ = *src++);
11637c9f0a6Schristos 		}
11737c9f0a6Schristos 		/*
11837c9f0a6Schristos 		 * Copy whole words, then mop up any trailing bytes.
11937c9f0a6Schristos 		 */
12037c9f0a6Schristos 		t = length / wsize;
12137c9f0a6Schristos 		TLOOP(*(word *)(void *)dst = *(const word *)(const void *)src; src += wsize; dst += wsize);
12237c9f0a6Schristos 		t = length & wmask;
12337c9f0a6Schristos 		TLOOP(*dst++ = *src++);
12437c9f0a6Schristos 	} else {
12537c9f0a6Schristos 		/*
12637c9f0a6Schristos 		 * Copy backwards.  Otherwise essentially the same.
12737c9f0a6Schristos 		 * Alignment works as before, except that it takes
12837c9f0a6Schristos 		 * (t&wmask) bytes to align, not wsize-(t&wmask).
12937c9f0a6Schristos 		 */
13037c9f0a6Schristos 		src += length;
13137c9f0a6Schristos 		dst += length;
13237c9f0a6Schristos 		_DIAGASSERT((unsigned long)dst >= (unsigned long)dst0);
13337c9f0a6Schristos 		_DIAGASSERT((unsigned long)src >= (unsigned long)src0);
13437c9f0a6Schristos 		u = (unsigned long)src;
13537c9f0a6Schristos 		if ((u | (unsigned long)dst) & wmask) {
13637c9f0a6Schristos 			if ((u ^ (unsigned long)dst) & wmask || length <= wsize)
13737c9f0a6Schristos 				t = length;
13837c9f0a6Schristos 			else
13937c9f0a6Schristos 				t = (size_t)(u & wmask);
14037c9f0a6Schristos 			length -= t;
14137c9f0a6Schristos 			TLOOP1(*--dst = *--src);
14237c9f0a6Schristos 		}
14337c9f0a6Schristos 		t = length / wsize;
14437c9f0a6Schristos 		TLOOP(src -= wsize; dst -= wsize; *(word *)(void *)dst = *(const word *)(const void *)src);
14537c9f0a6Schristos 		t = length & wmask;
14637c9f0a6Schristos 		TLOOP(*--dst = *--src);
14737c9f0a6Schristos 	}
14837c9f0a6Schristos done:
14937c9f0a6Schristos #if defined(MEMCOPY) || defined(MEMMOVE)
15037c9f0a6Schristos 	return (dst0);
15137c9f0a6Schristos #else
15237c9f0a6Schristos 	return;
15337c9f0a6Schristos #endif
15437c9f0a6Schristos }
155f5c28010Sapb #else /* __OPTIMIZE_SIZE__ */
156f5c28010Sapb #if defined(MEMCOPY)
1579e32ad04Schristos /*
1589e32ad04Schristos  * This is designed to be small, not fast.
1599e32ad04Schristos  */
1609e32ad04Schristos void *
memcpy(void * s1,const void * s2,size_t n)1619e32ad04Schristos memcpy(void *s1, const void *s2, size_t n)
1629e32ad04Schristos {
1639e32ad04Schristos 	const char *f = s2;
1649e32ad04Schristos 	char *t = s1;
1659e32ad04Schristos 
1669e32ad04Schristos 	while (n-- > 0)
1679e32ad04Schristos 		*t++ = *f++;
1689e32ad04Schristos 	return s1;
1699e32ad04Schristos }
17093f951ceSchristos #elif defined(MEMMOVE)
1719e32ad04Schristos /*
1729e32ad04Schristos  * This is designed to be small, not fast.
1739e32ad04Schristos  */
1749e32ad04Schristos void *
memmove(void * s1,const void * s2,size_t n)1759e32ad04Schristos memmove(void *s1, const void *s2, size_t n)
1769e32ad04Schristos {
1779e32ad04Schristos 	const char *f = s2;
1789e32ad04Schristos 	char *t = s1;
1799e32ad04Schristos 
1809e32ad04Schristos 	if (f < t) {
1819e32ad04Schristos 		f += n;
1829e32ad04Schristos 		t += n;
1839e32ad04Schristos 		while (n-- > 0)
1849e32ad04Schristos 			*--t = *--f;
1859e32ad04Schristos 	} else {
1869e32ad04Schristos 		while (n-- > 0)
1879e32ad04Schristos 			*t++ = *f++;
1889e32ad04Schristos 	}
1899e32ad04Schristos 	return s1;
1909e32ad04Schristos }
19193f951ceSchristos #else
19293f951ceSchristos /*
19393f951ceSchristos  * This is designed to be small, not fast.
19493f951ceSchristos  */
1959f2bc34fSchristos void
bcopy(const void * s2,void * s1,size_t n)19693f951ceSchristos bcopy(const void *s2, void *s1, size_t n)
19793f951ceSchristos {
19893f951ceSchristos 	const char *f = s2;
19993f951ceSchristos 	char *t = s1;
20093f951ceSchristos 
20193f951ceSchristos 	while (n-- > 0)
20293f951ceSchristos 		*t++ = *f++;
20393f951ceSchristos }
2049e32ad04Schristos #endif
205f5c28010Sapb #endif /* __OPTIMIZE_SIZE__ */
206