1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) 1994-2009  Red Hat, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from this
18  * software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34 FUNCTION
35 	<<memmove>>---move possibly overlapping memory
36 
37 INDEX
38 	memmove
39 
40 ANSI_SYNOPSIS
41 	#include <string.h>
42 	void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>);
43 
44 TRAD_SYNOPSIS
45 	#include <string.h>
46 	void *memmove(<[dst]>, <[src]>, <[length]>)
47 	void *<[dst]>;
48 	void *<[src]>;
49 	size_t <[length]>;
50 
51 DESCRIPTION
52 	This function moves <[length]> characters from the block of
53 	memory starting at <<*<[src]>>> to the memory starting at
54 	<<*<[dst]>>>. <<memmove>> reproduces the characters correctly
55 	at <<*<[dst]>>> even if the two areas overlap.
56 
57 RETURNS
58 	The function returns <[dst]> as passed.
59 
60 PORTABILITY
61 <<memmove>> is ANSI C.
62 
63 <<memmove>> requires no supporting OS subroutines.
64 
65 QUICKREF
66 	memmove ansi pure
67 */
68 
69 #include <string.h>
70 #include "_ansi.h"
71 #include <stddef.h>
72 #include <limits.h>
73 
74 /* Nonzero if either X or Y is not aligned on a "long" boundary.  */
75 #define UNALIGNED(X, Y) \
76 	(((long)X & (sizeof(long) - 1)) | ((long)Y & (sizeof(long) - 1)))
77 
78 /* How many bytes are copied each iteration of the 4X unrolled loop.  */
79 #define BIGBLOCKSIZE    (sizeof(long) << 2)
80 
81 /* How many bytes are copied each iteration of the word copy loop.  */
82 #define LITTLEBLOCKSIZE (sizeof(long))
83 
84 /* Threshhold for punting to the byte copier.  */
85 #define TOO_SMALL(LEN)  ((LEN) < BIGBLOCKSIZE)
86 
87 /* SUPPRESS 20 */
88 _PTR
89 _DEFUN(memmove, (dst_void, src_void, length), _PTR dst_void _AND _CONST _PTR
90 	src_void _AND size_t length)
91 {
92 #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
93 	char *dst = dst_void;
94 	_CONST char *src = src_void;
95 
96 	if (src < dst && dst < src + length) {
97 		/* Have to copy backwards */
98 		src += length;
99 		dst += length;
100 		while (length--)
101 			*--dst = *--src;
102 	} else {
103 		while (length--)
104 			*dst++ = *src++;
105 	}
106 
107 	return dst_void;
108 #else
109 	char *dst = dst_void;
110 	_CONST char *src = src_void;
111 	long *aligned_dst;
112 	_CONST long *aligned_src;
113 
114 	if (src < dst && dst < src + length) {
115 		/* Destructive overlap...have to copy backwards */
116 		src += length;
117 		dst += length;
118 		while (length--)
119 			*--dst = *--src;
120 	} else {
121 		/*
122 		 * Use optimizing algorithm for a non-destructive copy to
123 		 * closely match memcpy. If the size is small or either SRC or
124 		 * DST is unaligned, then punt into the byte copy loop.  This
125 		 * should be rare.
126 		 */
127 		if (!TOO_SMALL(length) && !UNALIGNED(src, dst)) {
128 			aligned_dst = (long *)dst;
129 			aligned_src = (long *)src;
130 
131 			/* Copy 4X long words at a time if possible.  */
132 			while (length >= BIGBLOCKSIZE) {
133 				*aligned_dst++ = *aligned_src++;
134 				*aligned_dst++ = *aligned_src++;
135 				*aligned_dst++ = *aligned_src++;
136 				*aligned_dst++ = *aligned_src++;
137 				length -= BIGBLOCKSIZE;
138 			}
139 
140 			/* Copy one long word at a time if possible.  */
141 			while (length >= LITTLEBLOCKSIZE) {
142 				*aligned_dst++ = *aligned_src++;
143 				length -= LITTLEBLOCKSIZE;
144 			}
145 
146 			/* Pick up any residual with a byte copier.  */
147 			dst = (char *)aligned_dst;
148 			src = (char *)aligned_src;
149 		}
150 
151 		while (length--)
152 			*dst++ = *src++;
153 	}
154 
155 	return dst_void;
156 #endif /* not PREFER_SIZE_OVER_SPEED */
157 }
158