Files
gcc/libgo/runtime/go-memmove.c
Ian Lance Taylor 479872227c runtime: avoid libc memmove and memclr
The libc memmove and memclr don't reliably operate on full memory words.
We already avoided them on PPC64, but the same problem can occur even
on x86, where some processors use "rep movsb" and "rep stosb".
Always use C code that stores full memory words.

While we're here, clean up the C code. We don't need special handling
if the memmove/memclr pointers are not pointer-aligned.

Unfortunately, this will likely be slower. Perhaps some day we can
have our own assembly code that operates a word at a time,
or we can use different operations when we know there are no pointers.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/685178
2025-07-08 15:49:16 -07:00

72 lines
1.7 KiB
C

/* 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;
}
}
}