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