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