History

KVM: selftests: Implement memcmp(), memcpy(), and memset() for guest use

Implement memcmp(), memcpy(), and memset() to override the compiler's built-in versions in order to guarantee that the compiler won't generate out-of-line calls to external functions via the PLT. This allows the helpers to be safely used in guest code, as KVM selftests don't support dynamic loading of guest code. Steal the implementations from the kernel's generic versions, sans the optimizations in memcmp() for unaligned accesses. Put the utilities in a separate compilation unit and build with -ffreestanding to fudge around a gcc "feature" where it will optimize memset(), memcpy(), etc... by generating a recursive call. I.e. the compiler optimizes itself into infinite recursion. Alternatively, the individual functions could be tagged with optimize("no-tree-loop-distribute-patterns"), but using "optimize" for anything but debug is discouraged, and Linus NAK'd the use of the flag in the kernel proper[*]. https://lore.kernel.org/lkml/CAHk-=wik-oXnUpfZ6Hw37uLykc-_P0Apyn2XuX-odh-3Nzop8w@mail.gmail.com

Sean Christopherson committed 4 years ago

Commit 6b6f7141 parent aae2e722 files · +49 −1Browse files

Unified · Split

2 files
  1. tools/testing/selftests/kvm/Makefile +10 −1
  2. tools/testing/selftests/kvm/lib/string_override.c +39 −0
tools/testing/selftests/kvm/Makefile+10−1
@@ -48,6 +48,8 @@ LIBKVM += lib/rbtree.c · 47 unmodified lines
4848 LIBKVM += lib/sparsebit.c
4949 LIBKVM += lib/test_util.c
5050
51+LIBKVM_STRING += lib/string_override.c
52+
5153 LIBKVM_x86_64 += lib/x86_64/apic.c
5254 LIBKVM_x86_64 += lib/x86_64/handlers.S
5355 LIBKVM_x86_64 += lib/x86_64/perf_test_util.c
@@ -220,7 +222,8 @@ LIBKVM_C := $(filter %.c,$(LIBKVM)) · 166 unmodified lines
220222 LIBKVM_S := $(filter %.S,$(LIBKVM))
221223 LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C))
222224 LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S))
223−LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ)
225+LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING))
226+LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ)
224227
225228 EXTRA_CLEAN += $(LIBKVM_OBJS) cscope.*
226229
@@ -231,6 +234,12 @@ $(LIBKVM_C_OBJ): $(OUTPUT)/%.o: %.c · 4 unmodified lines
231234 $(LIBKVM_S_OBJ): $(OUTPUT)/%.o: %.S
232235 $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
233236
237+# Compile the string overrides as freestanding to prevent the compiler from
238+# generating self-referential code, e.g. without "freestanding" the compiler may
239+# "optimize" memcmp() by invoking memcmp(), thus causing infinite recursion.
240+$(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.c
241+ $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@
242+
234243 x := $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS))))
235244 $(TEST_GEN_PROGS): $(LIBKVM_OBJS)
236245 $(TEST_GEN_PROGS_EXTENDED): $(LIBKVM_OBJS)
tools/testing/selftests/kvm/lib/string_override.c+39−0
@@ -0,0 +1,39 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+#include <stddef.h>
3+
4+/*
5+ * Override the "basic" built-in string helpers so that they can be used in
6+ * guest code. KVM selftests don't support dynamic loading in guest code and
7+ * will jump into the weeds if the compiler decides to insert an out-of-line
8+ * call via the PLT.
9+ */
10+int memcmp(const void *cs, const void *ct, size_t count)
11+{
12+ const unsigned char *su1, *su2;
13+ int res = 0;
14+
15+ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) {
16+ if ((res = *su1 - *su2) != 0)
17+ break;
18+ }
19+ return res;
20+}
21+
22+void *memcpy(void *dest, const void *src, size_t count)
23+{
24+ char *tmp = dest;
25+ const char *s = src;
26+
27+ while (count--)
28+ *tmp++ = *s++;
29+ return dest;
30+}
31+
32+void *memset(void *s, int c, size_t count)
33+{
34+ char *xs = s;
35+
36+ while (count--)
37+ *xs++ = c;
38+ return s;
39+}