When building ARCH=i386 with CONFIG_LTO_CLANG_FULL=y, it's possible
(depending on additional configs which I have not been able to isolate)
to observe a failure during register allocation:
error: inline assembly requires more registers than available
when memmove is inlined into tcp_v4_fill_cb() or tcp_v6_fill_cb().
memmove is quite large and probably shouldn't be inlined due to size
alone. A noinline function attribute would be the simplest fix, but
there's a few things that stand out with the current definition:
In addition to having complex constraints that can't always be resolved,
the clobber list seems to be missing %bx and %dx, and possibly %cl. By
using numbered operands rather than symbolic operands, the constraints
are quite obnoxious to refactor.
Having a large function be 99% inline asm is a code smell that this
function should simply be written in stand-alone out-of-line assembler.
That gives the opportunity for other cleanups like fixing the
inconsistent use of tabs vs spaces and instruction suffixes, and the
label 3 appearing twice. Symbolic operands and local labels would
provide this code with a fresh coat of paint.
Moving this to out of line assembler guarantees that the
compiler cannot inline calls to memmove.
This has been done previously for 64b:
commit 9599ec0471 ("x86-64, mem: Convert memmove() to assembly file
and fix return value bug")
Bug: 247605214
Link: https://lore.kernel.org/llvm/20220927210248.3950201-1-ndesaulniers@google.com/
Reviewed-by: Kees Cook <keescook@chromium.org>
Tested-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Change-Id: I5fde7a76d915c20a594dd9e0d409015855e731b2
23 lines
464 B
C
23 lines
464 B
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/string.h>
|
|
#include <linux/export.h>
|
|
|
|
#undef memcpy
|
|
#undef memset
|
|
|
|
__visible void *memcpy(void *to, const void *from, size_t n)
|
|
{
|
|
#if defined(CONFIG_X86_USE_3DNOW) && !defined(CONFIG_FORTIFY_SOURCE)
|
|
return __memcpy3d(to, from, n);
|
|
#else
|
|
return __memcpy(to, from, n);
|
|
#endif
|
|
}
|
|
EXPORT_SYMBOL(memcpy);
|
|
|
|
__visible void *memset(void *s, int c, size_t count)
|
|
{
|
|
return __memset(s, c, count);
|
|
}
|
|
EXPORT_SYMBOL(memset);
|