From 2d1e11d865a357a67e34496b057c038eb5a53167 Mon Sep 17 00:00:00 2001 From: Rose Date: Fri, 9 Aug 2024 12:34:46 -0500 Subject: [PATCH] new string.h implementation & tests --- Makefile | 2 +- dosfs/div.c | 15 +++ dosfs/dosfs.c | 3 +- dosfs/tmpstring.c | 99 --------------- host_test/Makefile | 24 ++++ host_test/main.c | 14 ++ host_test/str_test.c | 297 +++++++++++++++++++++++++++++++++++++++++++ host_test/test | Bin 0 -> 16544 bytes include/string.h | 10 ++ string.nasm | 235 ++++++++++++++++++++++++++++++++++ 10 files changed, 598 insertions(+), 101 deletions(-) create mode 100644 dosfs/div.c delete mode 100644 dosfs/tmpstring.c create mode 100644 host_test/Makefile create mode 100644 host_test/main.c create mode 100644 host_test/str_test.c create mode 100755 host_test/test create mode 100644 include/string.h create mode 100644 string.nasm diff --git a/Makefile b/Makefile index c3920a2..0de770a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o gdt.o\ paging.o fault.o tests.o kbd.o helper.o disk.o file.o fs.o dosfs/dosfs.o fs_dos.o\ - progs.o hexedit.o textedit.o + progs.o hexedit.o textedit.o string.o CFLAGS = -target "i386-elf" -m32 -mgeneral-regs-only -ffreestanding\ -march=i386 -fno-stack-protector -Wno-int-conversion -nostdlib -c -Iinclude LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib diff --git a/dosfs/div.c b/dosfs/div.c new file mode 100644 index 0000000..5e428db --- /dev/null +++ b/dosfs/div.c @@ -0,0 +1,15 @@ +#pragma once +#include + +/* STDLIB DIV FUNCTIONS */ +typedef struct { int32_t quot, rem; } div_t; +typedef struct { int64_t quot, rem; } ldiv_t; +div_t div(int num, int den) +{ + return (div_t){ num/den, num%den }; +} +ldiv_t ldiv(long num, long den) +{ + return (ldiv_t){ num/den, num%den }; +} + diff --git a/dosfs/dosfs.c b/dosfs/dosfs.c index 6ce007b..9e3479d 100755 --- a/dosfs/dosfs.c +++ b/dosfs/dosfs.c @@ -1,4 +1,5 @@ -#include "tmpstring.c" +#include +#include "div.c" /* DOSFS Embedded FAT-Compatible Filesystem diff --git a/dosfs/tmpstring.c b/dosfs/tmpstring.c deleted file mode 100644 index 4fc821a..0000000 --- a/dosfs/tmpstring.c +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once -#include -#include - -void *memcpy(void *restrict dest, const void *restrict src, size_t n) -{ - unsigned char *d = dest; - const unsigned char *s = src; - for (; n; n--) *d++ = *s++; - return dest; -} - -void *memset(void *dest, int c, size_t n) -{ - unsigned char *s = dest; - size_t k; - - /* Fill head and tail with minimal branching. Each - * conditional ensures that all the subsequently used - * offsets are well-defined and in the dest region. */ - - if (!n) return dest; - s[0] = c; - s[n-1] = c; - if (n <= 2) return dest; - s[1] = c; - s[2] = c; - s[n-2] = c; - s[n-3] = c; - if (n <= 6) return dest; - s[3] = c; - s[n-4] = c; - if (n <= 8) return dest; - - /* Advance pointer to align it at a 4-byte boundary, - * and truncate n to a multiple of 4. The previous code - * already took care of any head/tail that get cut off - * by the alignment. */ - - k = -(uintptr_t)s & 3; - s += k; - n -= k; - n &= -4; - - /* Pure C fallback with no aliasing violations. */ - for (; n; n--, s++) *s = c; - - return dest; -} - -size_t strlen(const char *s) -{ - const char *a = s; - for (; *s; s++); - return s-a; -} - -int memcmp(const void *vl, const void *vr, size_t n) -{ - const unsigned char *l=vl, *r=vr; - for (; n && *l == *r; n--, l++, r++); - return n ? *l-*r : 0; -} - -char *strncpy(char *restrict d, const char *restrict s, size_t n) -{ - for (; n && (*d=*s); n--, s++, d++); - memset(d, 0, n); - return d; -} - -char *strcpy(char *restrict dest, const char *restrict src) -{ - char *restrict d = dest; - const char *restrict s = src; - for (; (*d=*s); s++, d++); - - return d; -} - -int strcmp(const char *l, const char *r) -{ - for (; *l==*r && *l; l++, r++); - return *(unsigned char *)l - *(unsigned char *)r; -} - - -/* STDLIB DIV FUNCTIONS */ -typedef struct { int32_t quot, rem; } div_t; -typedef struct { int64_t quot, rem; } ldiv_t; -div_t div(int num, int den) -{ - return (div_t){ num/den, num%den }; -} -ldiv_t ldiv(long num, long den) -{ - return (ldiv_t){ num/den, num%den }; -} - diff --git a/host_test/Makefile b/host_test/Makefile new file mode 100644 index 0000000..6b6f63c --- /dev/null +++ b/host_test/Makefile @@ -0,0 +1,24 @@ +rose_objects = string.o +objects = main.o +CFLAGS = -m32 -mgeneral-regs-only -march=i386 -fno-stack-protector -Wno-int-conversion -c -Iinclude +LFLAGS = -m32 + +all: test + ./test + +test: $(objects) $(rose_objects) + clang $(LFLAGS) -o $@ $^ + +%.o: ../%.nasm + nasm -f elf32 -o $@ $< + objcopy --prefix-symbols=rose_ $@ + +%.o: %.c + clang $(CFLAGS) -ffunction-sections -fdata-sections -Os -o $@ $< + +%.o: ../%.c + clang $(CFLAGS) -nostdlib -ffunction-sections -fdata-sections -Os -o $@ $< + objcopy --prefix-symbols=rose_ $@ + +clean: + rm -f $(objects) $(rose_objects) test diff --git a/host_test/main.c b/host_test/main.c new file mode 100644 index 0000000..d610ab9 --- /dev/null +++ b/host_test/main.c @@ -0,0 +1,14 @@ +#include + +#include "str_test.c" + +int main() { + int fail = 0; + puts("\t--- Host tests for ROSE ---\n"); + + fail |= do_str_test(); + + puts(fail ? "\n\t--- ROSE FAILED TEST ---" : "\n\t--- ROSE PASSED TEST ---"); + return fail; +} + diff --git a/host_test/str_test.c b/host_test/str_test.c new file mode 100644 index 0000000..6ef643e --- /dev/null +++ b/host_test/str_test.c @@ -0,0 +1,297 @@ +#include +#include +#include +#include + +int rose_memcmp(const void *s1, const void *s2, size_t n); + +const char *MEMCMP_S0 = "0000000000000000"; +const char *MEMCMP_S1 = "0000000000000001"; +const char *MEMCMP_S2 = "0000000000000002"; +int test_memcmp() { + int res, test, fail = 0; + + res = rose_memcmp(MEMCMP_S0, MEMCMP_S0, 0); + test = res == 0; + printf("%s\tmemcmp n=0\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(MEMCMP_S0, MEMCMP_S1, 1); + test = res == 0; + printf("%s\tmemcmp n=1, strings equal\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(MEMCMP_S0, MEMCMP_S1, 2); + test = res == 0; + printf("%s\tmemcmp n=2, strings equal\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(MEMCMP_S0, MEMCMP_S1, 3); + test = res == 0; + printf("%s\tmemcmp n=3, strings equal\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(MEMCMP_S0, MEMCMP_S1, 4); + test = res == 0; + printf("%s\tmemcmp n=4, strings equal\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(MEMCMP_S0, MEMCMP_S1, 15); + test = res == 0; + printf("%s\tmemcmp n=15, strings equal\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(MEMCMP_S0, MEMCMP_S1, 16); + test = res == -1; + printf("%s\tmemcmp n=16, first less\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(MEMCMP_S2, MEMCMP_S1, 16); + test = res == 1; + printf("%s\tmemcmp n=16, first greater\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(&MEMCMP_S1[1], &MEMCMP_S2[1], 1000000); + test = res == -1; + printf("%s\tmemcmp n=1000000, first less\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcmp(&MEMCMP_S2[1], &MEMCMP_S1[1], 1000000); + test = res == 1; + printf("%s\tmemcmp n=1000000, first greater\n", test ? "PASS" : "FAIL"); + fail |= !test; + + return fail; +} + + +int rose_strcmp(const void *s1, const void *s2); + +const char *STRCMP_S0 = "0000000000000000"; +const char *STRCMP_S1 = "0000000000000001"; +const char *STRCMP_S2 = "0000000000000002"; +int test_strcmp() { + int res, test, fail = 0; + + res = rose_strcmp(STRCMP_S0, STRCMP_S0); + test = res == 0; + printf("%s\tstrcmp, strings equal\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_strcmp(&STRCMP_S0[1], STRCMP_S0); + test = res == -'0'; + printf("%s\tstrcmp, first shorter\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_strcmp(STRCMP_S0, &STRCMP_S0[1]); + test = res == '0'; + printf("%s\tstrcmp, second shorter\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_strcmp(STRCMP_S0, STRCMP_S1); + test = res == -1; + printf("%s\tstrcmp, first less\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_strcmp(STRCMP_S2, STRCMP_S1); + test = res == 1; + printf("%s\tstrcmp, first greater\n", test ? "PASS" : "FAIL"); + fail |= !test; + + char n = 0; + res = rose_strcmp(&n, &n); + test = res == 0; + printf("%s\tstrcmp, empty strings\n", test ? "PASS" : "FAIL"); + fail |= !test; + + return fail; +} + +/* Thanks Plasma Ofthedawn! */ +int rose_strlen(const void *s1); + +const char STRLEN_S0[] = {'a', 'b', 'c', 'd', 'e', '\0'}; +const char STRLEN_S1[] = {'\0', 'a', 'b', 'c', '\0'}; +const char STRLEN_S2[] = {'\1', '\xff', '\0'}; + +int test_strlen() { + int res, test, fail = 0; + + res = rose_strlen(STRLEN_S0); + test = res == 5; + printf("%s\tstrlen, normal string. is %d, should be 5\n", test ? "PASS" : "FAIL", res); + fail |= !test; + + res = rose_strlen(STRLEN_S1); + test = res == 0; + printf("%s\tstrlen, length 0. is %d, should be 0\n", test ? "PASS" : "FAIL", res); + fail |= !test; + + res = rose_strlen(STRLEN_S2); + test = res == 2; + printf("%s\tstrlen, weird charcacters. is %d, should be 2\n", test ? "PASS" : "FAIL", res); + fail |= !test; + + return fail; +} + +void *rose_memcpy(void *dest, const void *src, size_t n); + +int test_memcpy() { + void *res; + int test, fail = 0; + + const size_t n = 1 << 20; + char *d = malloc(n); + char *s = malloc(n); + + getrandom(s, n, 0); + + s[15] = 0; + d[15] = 1; + + res = rose_memcpy(d, s, 15); + test = res == d && d[15] == 1 && memcmp(s, d, 15) == 0; + printf("%s\tmemcpy, length 15\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memcpy(d, s, n); + test = res == d && memcmp(s, d, n) == 0; + printf("%s\tmemcpy, length %d\n", test ? "PASS" : "FAIL", n); + fail |= !test; + + d[0] = s[0] - 1; + res = rose_memcpy(d, s, 0); + test = res == d && memcmp(d, s, 1) == -1; + printf("%s\tmemcpy, length 0\n", test ? "PASS" : "FAIL"); + fail |= !test; + + free(d); + free(s); + + return fail; +} + +char *rose_strcpy(char *restrict dst, const char *restrict src); + +int test_strcpy() { + void *res; + int test, fail = 0; + + const size_t n = 1 << 16; + char *d = malloc(n); + char *s = malloc(n); + + getrandom(s, n, 0); + for (int i = 1; i < 256; i++) s[i - 1] = i; + s[n-1] = 0; // fix very unlikely case + + res = rose_strcpy(d, s); + test = res == d && strcmp(s, d) == 0; + printf("%s\tstrcpy, random string\n", test ? "PASS" : "FAIL"); + fail |= !test; + + d[0] = 1; + s[0] = 0; + res = rose_strcpy(d, s); + test = res == d && d[0] == 0; + printf("%s\tstrcpy, length 0\n", test ? "PASS" : "FAIL"); + fail |= !test; + + free(d); + free(s); + + return fail; +} + +void *rose_memset(void *s, int c, size_t n); + +int test_memset() { + void *res; + int test, fail = 0; + + const size_t n = 1 << 16; + char *s = malloc(n); + char *d = malloc(n); + const int c = 0x42; + memset(d, c, n); + + res = rose_memset(s, c, n); + test = res == s && memcmp(s, d, n) == 0; + printf("%s\tmemset, length %d\n", test ? "PASS" : "FAIL", n); + fail |= !test; + + res = rose_memset(s, 0, 1); + test = res == s && s[0] == 0 && s[1] == c; + printf("%s\tmemset, bound check\n", test ? "PASS" : "FAIL"); + fail |= !test; + + res = rose_memset(s, c, 0); + test = res == s && s[0] == 0; + printf("%s\tmemset, length 0\n", test ? "PASS" : "FAIL"); + fail |= !test; + + free(s); + free(d); + + return fail; +} + +char *rose_strncpy(char *restrict dst, const char *restrict src, size_t dsize); + +int test_strncpy() { + void *res; + int test, fail = 0; + + const size_t n = 1 << 16; + char *d = malloc(n); + char *s = malloc(n); + char *x = malloc(n); + + getrandom(s, n, 0); + for (int i = 1; i < 256; i++) s[i - 1] = i; + + strncpy(x, s, n); + res = rose_strncpy(d, s, n); + test = res == d && memcmp(x, d, n) == 0; + printf("%s\tstrcpy, random string, length %d\n", test ? "PASS" : "FAIL", n); + fail |= !test; + + memset(s, 0x42, n); + strncpy(x, s, 255); + x[255] = 0; + d[255] = 1; + res = rose_strncpy(d, s, 255); + test = res == d && memcmp(x, d, 256) == -1; + printf("%s\tstrcpy, bounds check\n", test ? "PASS" : "FAIL"); + fail |= !test; + + d[0] = 1; + res = rose_strncpy(d, s, 0); + test = res == d && d[0] == 1; + printf("%s\tstrcpy, length 0\n", test ? "PASS" : "FAIL"); + fail |= !test; + + free(d); + free(s); + free(x); + + return fail; +} + +int do_str_test() { + int fail = 0; + + puts("[String Tests]"); + + fail |= test_memcmp(); + fail |= test_strcmp(); + fail |= test_strlen(); + fail |= test_memcpy(); + fail |= test_strcpy(); + fail |= test_memset(); + fail |= test_strncpy(); + puts(fail ? "STRING TESTS FAILED" : "STRING TESTS PASSED"); + + return fail; +} diff --git a/host_test/test b/host_test/test new file mode 100755 index 0000000000000000000000000000000000000000..0646005719bb3eb9dcf1540fd349bc55df59910c GIT binary patch literal 16544 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 + +int memcmp(const void *s1, const void *s2, uint32_t n); +void *memcpy(void *dest, const void *src, uint32_t n); +void *memset(void *s, int c, uint32_t n); +int strcmp(const char *s1, const char *s2); +char *stpcpy(char *restrict dst, const char *restrict src); +char *strcpy(char *restrict dst, const char *restrict src); +uint32_t strlen(const char *s); +char *strncpy(char *restrict dst, const char *restrict src, uint32_t dsize); diff --git a/string.nasm b/string.nasm new file mode 100644 index 0000000..4ade6c5 --- /dev/null +++ b/string.nasm @@ -0,0 +1,235 @@ +; C string.h implementations + +global memcmp +global memcpy +global memset +global strcmp +global stpcpy +global strcpy +global strlen +global strncpy + +; return eax(, edx) parameters stack scratch eax ecx edx preserved ebx esi edi ebp esp + +; int memcmp(const void s1[], const void s2[], size_t n); +memcmp: +mov ecx, [esp+12] +jecxz .z ; return 0 if n is 0 +push esi +push edi +mov esi, [esp+12] +mov edi, [esp+16] +mov edx, ecx +shr ecx, 2 +jz .ld +repe cmpsd ; find non-matching dwords +jne .f2 +.ld: +and edx, 3 +jz .sz ; none left, so all matched +mov al, byte [esi+0] +sub al, byte [edi+0] +jnz .f +dec edx +jz .sz +mov al, byte [esi+1] +sub al, byte [edi+1] +jnz .f +dec edx +jz .sz +mov al, byte [esi+2] +sub al, byte [edi+2] +jmp .f ; last byte +.sz: ; no non-matching bytes +pop edi +pop esi +.z: +xor eax, eax +ret +.f: ; diff in al +movsx eax, al +pop edi +pop esi +ret +.f2: ; found non-matching dword at ESI-4 <-> EDI-4 +mov eax, [esi-4] +mov ecx, [edi-4] +sub al, cl +jnz .d +shr eax, 8 ; ESI-3 +shr ecx, 8 +sub al, cl +jnz .d +shr eax, 8 ; ESI-2 +shr ecx, 8 +sub al, cl +jnz .d +shr eax, 8 ; ESI-1 +shr ecx, 8 +sub al, cl +.d: +movsx eax, al +pop edi +pop esi +ret + +; void *memcpy(void dest[], const void src[], size_t n); +memcpy: +mov ecx, [esp+12] +jecxz .none +push esi +push edi +mov edi, [esp+12] +mov esi, [esp+16] +mov edx, ecx +shr ecx, 2 +jz .dword_done +rep movsd +.dword_done: +test edx, 2 +jz .word_done +movsw +.word_done: +test edx, 1 +jz .done +movsb +.done: +pop edi +pop esi +.none: +mov eax, [esp+4] +ret + +; void *memset(void s[], int c, size_t n); +memset: +mov ecx, [esp+12] +jecxz .none +push edi +mov edi, [esp+8] +mov eax, [esp+12] +mov ah, al +mov edx, eax +shl eax, 16 +mov ax, dx +mov edx, ecx +shr ecx, 2 +jz .dword_done +rep stosd +.dword_done: +test edx, 2 +jz .word_done +stosw +.word_done: +test edx, 1 +jz .done +stosb +.done: +pop edi +.none: +mov eax, [esp+4] +ret + +; int strcmp(const char *s1, const char *s2); +strcmp: +push esi +push edi +mov esi, [esp+12] +mov edi, [esp+16] +xor ecx, ecx +jmp .l_inner +.l: +inc ecx +.l_inner: +xor eax, eax +or al, [esi+ecx] +jz .s1_end +or ah, [edi+ecx] +jz .s2_end +sub al, ah +jz .l ; equal +.done: +movsx eax, al +pop edi +pop esi +ret +.s1_end: +mov ah, [edi+ecx] +.s2_end: +sub al, ah +jmp .done + +; char *stpcpy(char *restrict dst, const char *restrict src); +stpcpy: +push esi +push edi +mov edi, [esp+12] +mov esi, [esp+16] +xor ecx, ecx +.l: +xor eax, eax +or al, [esi+ecx] +mov [edi+ecx], al +jz .done +inc ecx +jmp .l +.done: +lea eax, [edi+ecx] +pop edi +pop esi +ret +; char *strcpy(char *restrict dst, const char *restrict src); +strcpy: +push esi +push edi +mov edi, [esp+12] +mov esi, [esp+16] +xor ecx, ecx +.l: +xor eax, eax +or al, [esi+ecx] +mov [edi+ecx], al +jz .done +inc ecx +jmp .l +.done: +mov eax, [esp+12] +pop edi +pop esi +ret + +; size_t strlen(const char *s); +strlen: +push edi +mov edi, [esp+8] +xor eax, eax +mov ecx, -1 +repne scasb ; find AL in EDI +not ecx +lea eax, [ecx-1] +pop edi +ret + +; char *strncpy(char dst[restrict .dsize], const char *restrict src, size_t dsize); +strncpy: +push esi +push edi +mov edi, [esp+12] +mov esi, [esp+16] +mov ecx, [esp+20] +jecxz .done +.l: +xor eax, eax +or al, [esi] +jz .src_empty +stosb +inc esi +loop .l +jmp .done +.src_empty: +rep stosb +.done: +mov eax, [esp+12] +pop edi +pop esi +ret +