Override memmove() along with the other string operations to prevent the compiler from generating a reference to the built-in memcpy() when using musl as the libc with a static build, which utlimately results in an error during linking due to a duplicate memcpy symbol: ld.lld: error: duplicate symbol: memcpy >>> defined at string_override.c:23 (lib/string_override.c:23) >>> $BUILD/build/selftests/c/lib/string_override.o:(memcpy) >>> defined at memcpy.lo:(.text+0x0) in archive $BUILD/build/musl/lib/libc.a clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [Makefile.kvm:382: $BUILD/build/selftests/c/demand_paging_test] Error 1 The failure crops up when linking in the TDX library code[*] due to tdx_init_vm() generating a call to memmove(), which is "fine" until the perfect combination of static linking with musl triggers the above. All kudos goes to AI for figuring out the insanity: 1. string_override.c defines its own memcpy, memset, memcmp, and strnlen (so guest VM code doesn't jump through the dynamic linker's PLT in normal dynamic builds), but it does not define memmove. 2. In musl on x86_64, src/string/x86_64/memcpy.s (memcpy.lo) defines two global symbols at the function entry point: .global memcpy .global __memcpy_fwd .hidden __memcpy_fwd memcpy: __memcpy_fwd: 3. And musl's src/string/x86_64/memmove.s (memmove.lo) implements non-overlapping forward moves by jumping directly to __memcpy_fwd: memmove: mov %rdi,%rax sub %rsi,%rax cmp %rdx,%rax jae __memcpy_fwd 4. As long as nothing calls memmove, ld.lld already has memcpy from string_override.o and never extracts memcpy.lo from libc.a. 5. However, the one library file that calls memmove (either directly or transitively via a libc.a function like getline/stdio that only that file uses) causes ld.lld to extract memmove.lo from libc.a, which has an unresolved reference to __memcpy_fwd. To satisfy __memcpy_fwd, ld.lld is forced to extract memcpy.lo from libc.a, which also defines memcpy and collides with string_override.o! Link: https://lore.kernel.org/all/20261105-tdx-selftests-v16-3-2024e8fa517a@google.com [*] Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile.kvm | 2 +- tools/testing/selftests/kvm/lib/string_override.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 17a4256e9081..031f78643af8 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -295,7 +295,7 @@ CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \ -Wno-gnu-variable-sized-type-not-at-end -MD -MP -DCONFIG_64BIT \ -U_FORTIFY_SOURCE \ -fno-builtin-memcmp -fno-builtin-memcpy \ - -fno-builtin-memset -fno-builtin-strnlen \ + -fno-builtin-memset -fno-builtin-strnlen -fno-builtin-memmove \ -fno-stack-protector -fno-PIE -fno-strict-aliasing \ -I$(LINUX_TOOL_INCLUDE) -I$(LINUX_TOOL_ARCH_INCLUDE) \ -I$(LINUX_HDR_PATH) -Iinclude -I$(= count) + return memcpy(dest, src, count); + + while (count-- > 0) + d[count] = s[count]; + + return dest; +} + void *memset(void *s, int c, size_t count) { char *xs = s; base-commit: cf7fa575900051e489f95944c65f432ea706ed73 -- 2.56.0.542.g3ef89b7020-goog