:: commit 155362570e4ee0caa5cdb25c9e03381cf201e652

mintsuki <mintsuki@protonmail.com> — 2020-08-27 23:25

parents: e2a87ca33e

Reimplement memcpy, memmove, memcmp, and memset in assembly to work around potentially buggy compilers generating references to those function recursively within the function bodies

diff --git a/qloader2.bin b/qloader2.bin
index 77c0ed6b..db2355a5 100644
Binary files a/qloader2.bin and b/qloader2.bin differ
diff --git a/src/lib/libc.c b/src/lib/libc.c
index c8b8e84c..d8038002 100644
--- a/src/lib/libc.c
+++ b/src/lib/libc.c
@@ -1,6 +1,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <lib/libc.h>
+#include <lib/asm.h>
 
 int toupper(int c) {
     if (c >= 'a' && c <= 'z') {
@@ -16,54 +17,88 @@ int tolower(int c) {
     return c;
 }
 
+__attribute__((naked))
 void *memcpy(void *dest, const void *src, size_t n) {
-    uint8_t *pdest = dest;
-    const uint8_t *psrc = src;
-
-    for (size_t i = 0; i < n; i++) {
-        pdest[i] = psrc[i];
-    }
-
-    return dest;
+    ASM_BASIC(
+        "push esi\n\t"
+        "push edi\n\t"
+        "mov eax, dword ptr [esp+12]\n\t"
+        "mov edi, eax\n\t"
+        "mov esi, dword ptr [esp+16]\n\t"
+        "mov ecx, dword ptr [esp+20]\n\t"
+        "rep movsb\n\t"
+        "pop edi\n\t"
+        "pop esi\n\t"
+        "ret\n\t"
+    );
 }
 
+__attribute__((naked))
 void *memset(void *s, int c, size_t n) {
-    uint8_t *p = s;
-
-    for (size_t i = 0; i < n; i++) {
-        p[i] = (uint8_t)c;
-    }
-
-    return s;
+    ASM_BASIC(
+        "push edi\n\t"
+        "mov edx, dword ptr [esp+8]\n\t"
+        "mov edi, edx\n\t"
+        "mov eax, dword ptr [esp+12]\n\t"
+        "mov ecx, dword ptr [esp+16]\n\t"
+        "rep stosb\n\t"
+        "mov eax, edx\n\t"
+        "pop edi\n\t"
+        "ret\n\t"
+    );
 }
 
+__attribute__((naked))
 void *memmove(void *dest, const void *src, size_t n) {
-    uint8_t *pdest = dest;
-    const uint8_t *psrc = src;
-
-    if (src > dest) {
-        for (size_t i = 0; i < n; i++) {
-            pdest[i] = psrc[i];
-        }
-    } else if (src < dest) {
-        for (size_t i = n; i > 0; i--) {
-            pdest[i-1] = psrc[i-1];
-        }
-    }
-
-    return dest;
+    ASM_BASIC(
+        "push esi\n\t"
+        "push edi\n\t"
+        "mov eax, dword ptr [esp+12]\n\t"
+        "mov edi, eax\n\t"
+        "mov esi, dword ptr [esp+16]\n\t"
+        "mov ecx, dword ptr [esp+20]\n\t"
+
+        "cmp edi, esi\n\t"
+        "ja 1f\n\t"
+
+        "rep movsb\n\t"
+        "jmp 2f\n\t"
+
+        "1:\n\t"
+        "lea edi, [edi+ecx-1]\n\t"
+        "lea esi, [esi+ecx-1]\n\t"
+        "std\n\t"
+        "rep movsb\n\t"
+        "cld\n\t"
+
+        "2:\n\t"
+        "pop edi\n\t"
+        "pop esi\n\t"
+        "ret\n\t"
+    );
 }
 
+__attribute__((naked))
 int memcmp(const void *s1, const void *s2, size_t n) {
-    const uint8_t *p1 = s1;
-    const uint8_t *p2 = s2;
-
-    for (size_t i = 0; i < n; i++) {
-        if (p1[i] != p2[i])
-            return p1[i] < p2[i] ? -1 : 1;
-    }
-
-    return 0;
+    ASM_BASIC(
+        "push esi\n\t"
+        "push edi\n\t"
+        "mov edi, dword ptr [esp+12]\n\t"
+        "mov esi, dword ptr [esp+16]\n\t"
+        "mov ecx, dword ptr [esp+20]\n\t"
+        "repe cmpsb\n\t"
+        "jecxz 1f\n\t"
+        "mov al, byte ptr [edi-1]\n\t"
+        "sub al, byte ptr [esi-1]\n\t"
+        "movsx eax, al\n\t"
+        "jmp 2f\n\t"
+        "1:\n\t"
+        "mov eax, ecx\n\t"
+        "2:\n\t"
+        "pop edi\n\t"
+        "pop esi\n\t"
+        "ret\n\t"
+    );
 }
 
 char *strcpy(char *dest, const char *src) {
tab: 248 wrap: offon