[CRIU] [PATCH 04/23] pie: provide own memcpy for x86

Kir Kolyshkin kir at openvz.org
Tue Oct 11 18:46:42 PDT 2016


When compiling criu with clang, I discovered compilation fails like
this:

    GEN      criu/pie/restorer-blob.h
 restorer_blob: Error (compel/src/lib/handle-elf-host.c:328): Unexpected
 undefined symbol: `memcpy'. External symbol in PIE?

This happens because clang emits a call to memcpy for struct
initialization (specifically, struct vdso_symtable in vdso_proxify()).
Naturally, as pie is complied without libc there is no memcpy()
so "compel piegen" rightfully complains.

There are a number of possible solutions to that:
 1. Write our own vdso_init_symtable() function instead of using =
 2. Use some compiler flags that disables using memcpy
 3. Provide own version of memcpy

Now, (1) looks ugly, (2) I was not able to find such flags. Another
argument in favor of (3) is we already have implementation of
builtin_memcpy() optimized for x86.

The only problem is it is not named memcpy(). Using assembler file (.S)
we can have a function with two names (entry points).

For a similar issue in ppc, see commits 0570dd8 and 1ad7817. Ultimately,
we should get rid of builtin_mem* names and just use memcpy(), memcmp()
etc, which in case of non-libc linked objects are to be provided by us.

Cc: Laurent Dufour <ldufour at linux.vnet.ibm.com>
Cc: Cyrill Gorcunov <gorcunov at openvz.org>
Signed-off-by: Kir Kolyshkin <kir at openvz.org>
---
 criu/arch/x86/include/asm/string.h | 19 ++++++++-----------
 criu/arch/x86/memcpy.S             | 30 ++++++++++++++++++++++++++++++
 criu/pie/Makefile.library          |  1 +
 3 files changed, 39 insertions(+), 11 deletions(-)
 create mode 100644 criu/arch/x86/memcpy.S

diff --git a/criu/arch/x86/include/asm/string.h b/criu/arch/x86/include/asm/string.h
index e1d875e..ca4d4ab 100644
--- a/criu/arch/x86/include/asm/string.h
+++ b/criu/arch/x86/include/asm/string.h
@@ -6,19 +6,16 @@
 #include "compiler.h"
 #include "asm-generic/string.h"
 
-static always_inline void *builtin_memcpy(void *to, const void *from, unsigned int n)
+#ifdef CR_NOGLIBC
+extern void *memcpy_x86(void *to, const void *from, size_t n);
+static inline void *builtin_memcpy(void *to, const void *from, size_t n)
 {
-	int d0, d1, d2;
-	asm volatile("rep ; movsl		\n"
-		     "movl %4,%%ecx		\n"
-		     "andl $3,%%ecx		\n"
-		     "jz 1f			\n"
-		     "rep ; movsb		\n"
-		     "1:"
-		     : "=&c" (d0), "=&D" (d1), "=&S" (d2)
-		     : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from)
-		     : "memory");
+	if (n)
+		memcpy_x86(to, from, n);
 	return to;
 }
+#else
+#define builtin_memcpy memcpy
+#endif /* CR_NOGLIBC */
 
 #endif /* __CR_ASM_STRING_H__ */
diff --git a/criu/arch/x86/memcpy.S b/criu/arch/x86/memcpy.S
new file mode 100644
index 0000000..3d6cb19
--- /dev/null
+++ b/criu/arch/x86/memcpy.S
@@ -0,0 +1,30 @@
+#include "asm/linkage.h"
+
+/* The following code is taken from Linux kernel (arch/x86/lib/memcpy_64.S).
+ * There are 3 implementations in there, we use the one that relies on
+ * X86_FEATURE_REP_GOOD ("rep microcode works well").
+ */
+
+/*
+ * memcpy - Copy a memory block.
+ *
+ * Input:
+ *  rdi destination
+ *  rsi source
+ *  rdx count
+ *
+ * Output:
+ * rax original destination
+ */
+ENTRY(memcpy_x86)
+ENTRY(memcpy)
+	movq %rdi, %rax
+	movq %rdx, %rcx
+	shrq $3, %rcx
+	andl $7, %edx
+	rep movsq
+	movl %edx, %ecx
+	rep movsb
+	ret
+END(memcpy)
+END(memcpy_x86)
diff --git a/criu/pie/Makefile.library b/criu/pie/Makefile.library
index e1e28c0..c00877f 100644
--- a/criu/pie/Makefile.library
+++ b/criu/pie/Makefile.library
@@ -13,6 +13,7 @@ ifeq ($(ARCH),x86)
         CFLAGS_native	+= -DCONFIG_X86_64
         CFLAGS_compat	+= -fno-pic -m32 -DCONFIG_X86_32
         CFLAGS_util-vdso-elf32.o	+= -DCONFIG_X86_32
+        OBJS		+= ./$(ARCH_DIR)/memcpy.o
 endif
 
 OBJS			+= log-simple.o util-fd.o util.o
-- 
2.7.4



More information about the CRIU mailing list