xref: /arm-trusted-firmware/lib/libc/memmove.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2013-2018, Arm Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <string.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu void *memmove(void *dst, const void *src, size_t len)
10*91f16700Schasinglulu {
11*91f16700Schasinglulu 	/*
12*91f16700Schasinglulu 	 * The following test makes use of unsigned arithmetic overflow to
13*91f16700Schasinglulu 	 * more efficiently test the condition !(src <= dst && dst < str+len).
14*91f16700Schasinglulu 	 * It also avoids the situation where the more explicit test would give
15*91f16700Schasinglulu 	 * incorrect results were the calculation str+len to overflow (though
16*91f16700Schasinglulu 	 * that issue is probably moot as such usage is probably undefined
17*91f16700Schasinglulu 	 * behaviour and a bug anyway.
18*91f16700Schasinglulu 	 */
19*91f16700Schasinglulu 	if ((size_t)dst - (size_t)src >= len) {
20*91f16700Schasinglulu 		/* destination not in source data, so can safely use memcpy */
21*91f16700Schasinglulu 		return memcpy(dst, src, len);
22*91f16700Schasinglulu 	} else {
23*91f16700Schasinglulu 		/* copy backwards... */
24*91f16700Schasinglulu 		const char *end = dst;
25*91f16700Schasinglulu 		const char *s = (const char *)src + len;
26*91f16700Schasinglulu 		char *d = (char *)dst + len;
27*91f16700Schasinglulu 		while (d != end)
28*91f16700Schasinglulu 			*--d = *--s;
29*91f16700Schasinglulu 	}
30*91f16700Schasinglulu 	return dst;
31*91f16700Schasinglulu }
32