1 /* SPDX-License-Identifier: GPL-2.0 */
3 #include <linux/export.h>
4 #include <linux/linkage.h>
6 SYM_FUNC_START(memmove)
8 * void *memmove(void *dest_in, const void *src_in, size_t n)
9 * -mregparm=3 passes these in registers:
13 * See also: arch/x86/entry/calling.h for description of the calling convention.
15 * n can remain in %ecx, but for `rep movsl`, we'll need dest in %edi and src
31 * Save all callee-saved registers, because this function is going to clobber
35 movl %esp, %ebp // set standard frame pointer
40 pushl %eax // save 'dest_in' parameter [eax] as the return value
45 /* Handle more 16 bytes in loop */
49 /* Decide forward/backward copy mode */
54 * movs instruction have many startup latency
55 * so we handle small size by general register.
58 jb .Ltoo_small_forwards
59 /* movs instruction is only good for aligned case. */
67 /* We gobble 16 bytes forward in each loop. */
68 .Lmove_16B_forwards_loop:
80 jae .Lmove_16B_forwards_loop
84 /* Handle data forward by movs. */
88 leal -4(dest, n), tmp1
94 /* Handle data backward by movs. */
100 leal -4(dest, n), dest
108 /* Start to prepare for backward copy. */
112 jb .Ltoo_small_backwards
118 /* Calculate copy position to tail. */
119 .Ltoo_small_backwards:
124 /* We gobble 16 bytes backward in each loop. */
125 .Lmove_16B_backwards_loop:
130 movl tmp0, -1*4(dest)
131 movl tmp1, -2*4(dest)
134 movl tmp0, -3*4(dest)
135 movl tmp1, -4*4(dest)
137 leal -0x10(dest), dest
138 jae .Lmove_16B_backwards_loop
139 /* Calculate copy position to head. */
144 /* Move data from 8 bytes to 15 bytes. */
151 movl -2*4(src, n), tmp2
152 movl -1*4(src, n), src
156 movl tmp2, -2*4(dest, n)
157 movl src, -1*4(dest, n)
160 /* Move data from 4 bytes to 7 bytes. */
166 movl -1*4(src, n), tmp1
168 movl tmp1, -1*4(dest, n)
171 /* Move data from 2 bytes to 3 bytes. */
177 movw -1*2(src, n), tmp1w
178 movw tmp0w, 0*2(dest)
179 movw tmp1w, -1*2(dest, n)
182 /* Move data for 1 byte. */
191 popl dest_in // restore 'dest_in' [eax] as the return value
192 /* Restore all callee-saved registers: */
199 SYM_FUNC_END(memmove)
200 EXPORT_SYMBOL(memmove)