| /* go-memmove.c -- memmove |
| |
| Copyright 2021 The Go Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style |
| license that can be found in the LICENSE file. */ |
| |
| #include "runtime.h" |
| |
| void gomemmove(void *, void *, uintptr) |
| __asm__ (GOSYM_PREFIX "runtime.memmove") |
| __attribute__ ((no_split_stack)); |
| |
| // This implementation is necessary since |
| // the __builtin_memmove might use __libc_memmove |
| // which doesn't require atomicity of pointer-sized |
| // moves. |
| |
| void |
| gomemmove(void *dst, void *src, uintptr len) |
| { |
| const uintptr ptr_size = sizeof(dst); |
| uintptr tail; |
| uintptr rem; |
| uintptr dwords; |
| uintptr i; |
| char *bdst, *bsrc; |
| |
| if (len == 0) { |
| return; |
| } |
| |
| // We expect pointer-containing values to be pointer-aligned. |
| // If these pointers are not aligned, they don't contain pointers. |
| if ((uintptr)dst % ptr_size != 0 || (uintptr)src % ptr_size != 0 || len < ptr_size) { |
| __builtin_memmove(dst, src, len); |
| return; |
| } |
| |
| bdst = (char*)dst; |
| bsrc = (char*)src; |
| |
| // Move the tail bytes to make the backward move easier. |
| rem = len; |
| tail = rem % ptr_size; |
| if (tail > 0) { |
| __builtin_memmove(bdst+rem-tail, bsrc+rem-tail, tail); |
| rem -= tail; |
| } |
| |
| // Must now be pointer alignment and rem is multiple of ptr_size. |
| dwords = rem / ptr_size; |
| |
| // Determine if a backwards move is needed. |
| // Forward or backward, move all words. |
| |
| if ((uintptr)(bdst - bsrc) < rem) { |
| bdst += rem - ptr_size; |
| bsrc += rem - ptr_size; |
| for (i = 0; i<dwords; i++) { |
| *(uintptr*)bdst = *(uintptr*)bsrc; |
| bdst -= ptr_size; |
| bsrc -= ptr_size; |
| } |
| } else { |
| for (i = 0; i<dwords; i++) { |
| *(uintptr*)bdst = *(uintptr*)bsrc; |
| bdst += ptr_size; |
| bsrc += ptr_size; |
| } |
| } |
| } |