diff --git a/libc/README.md b/libc/README.md index 5ba54e3..57cab3b 100644 --- a/libc/README.md +++ b/libc/README.md @@ -26,6 +26,4 @@ Somewhat nice implementations of: ## Correctness: -This library is 100% untested. Feel free to report bugs using github issues. I'm sure ther are many. We are working on testing! - - +This library is only lightly tested, so be careful and report bugs when you find them! \ No newline at end of file diff --git a/libc/stdlib.s b/libc/stdlib.s index a12f4b5..6845c73 100644 --- a/libc/stdlib.s +++ b/libc/stdlib.s @@ -96,7 +96,11 @@ free: // s0 = &_atexit_count // s2 = &_atexit_calls // s1 = updated value of atexit +// s3 = exit code exit: + // save exit code to s3 + mv s3, a0 +_exit_start: la s0, _atexit_count // s0 = &_atexit_count lw s1, 0(s0) // s1 = *(&_atexit_count) // exit if no atexit() calls remain @@ -108,12 +112,12 @@ exit: li s2, _atexit_calls add s1, s1, s2 // s1 = &_atexit_calls + (s1) lw s1, 0(s1) // s1 = *s1 - la ra, exit // set ra up to point to exit + la ra, _exit_start // set ra up to point to exit jalr zero, s1, 0 // jump to address in s1 // jalr will call the other function, which will then return back // to the beginning of exit. _exit: - li a0, 0 + mv a0, s3 li a7, 93 ecall diff --git a/libc/string.s b/libc/string.s index 0dd933b..55725cb 100644 --- a/libc/string.s +++ b/libc/string.s @@ -3,8 +3,9 @@ // Copyright (c) 2023 Anton Lydike // SPDX-License-Identifier: MIT +// Create NullPtr constant +.equ NULL, 0x00 .global NULL -// A global constant representing zero .global strlen @@ -35,15 +36,13 @@ // copies the character c to the first n characters of str. +// missing implementations //.global memcmp //.global memcpy //.global strcat -// Create NullPtr constant -.set NULL, 0x00 - - .text +.text strlen: // size_t strlen(char* str) // push s1, s2 to the stack @@ -101,7 +100,7 @@ __strncpy_end: strcpy: -// char *strncpy(char *dest, const char *src) +// char *strcpy(char *dest, const char *src) sw s1, sp, -4 // push s1 to the stack sw s2, sp, -8 // push s1 to the stack add s1, a0, zero // save dest pointer for return @@ -124,15 +123,16 @@ __strcpy_loop: memchr: // void *memchr(const void *str, char c, size_t n) sw s1, sp, -4 // push s1 to the stack + andi a1, a1, 0xff // trim a1 to be byte-sized __memchr_loop: beq a2, zero, __memchr_ret_null lb s1, a0, 0 addi a0, a0, 1 // let a0 point to the next byte addi a2, a2, -1 // decrement bytes to copy by 1 - bne s1, s2, __memchr_loop + bne s1, a1, __memchr_loop // return pointer to prev byte (as the prev byte actually matched a1) addi a0, a0, -1 - // pop s1, s2 from stack + // pop s1, from stack lw s1, sp, -4 ret __memchr_ret_null: diff --git a/test/filecheck/libc/test-string.s b/test/filecheck/libc/test-string.s new file mode 100644 index 0000000..b3cb66f --- /dev/null +++ b/test/filecheck/libc/test-string.s @@ -0,0 +1,114 @@ +// RUN: python3 -m riscemu -v %s libc/string.s libc/stdlib.s libc/crt0.s | filecheck %s + +.data + +data: +.byte 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 +.byte 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00 + +dest: +.byte 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB +.byte 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB + +small_str: +.string "test" + +.text + +.globl main +main: +// test that strlen(data) == 15 + addi sp, sp, -4 + sw ra, 0(sp) + la a0, data + // call strlen(data) + jal strlen + li t0, 15 + bne a0, t0, _fail + +// now memcpy strlen(data)+1 bytes from data to dest + la a0, dest + la a1, data + li a2, 16 + // call strncpy(dest, data, 16) + jal strncpy + la a1, dest + // fail because strncpy should return pointer to dest + bne a0, a1, _fail + // check that dest and data are the same + jal check_data_dest_is_same + la a0, dest + li a1, 0x11 + li a2, 16 +// test that memset(dest) workds + // call memset(dest, 0x11, 16) + jal memset + // check that all of dest is 0x11111111 + li t1, 0x11111111 + la a0, dest + lw t0, 0(a0) + bne t0, t1, _fail + lw t0, 1(a0) + bne t0, t1, _fail + lw t0, 2(a0) + bne t0, t1, _fail + lw t0, 3(a0) + bne t0, t1, _fail +// test memchr + // test memchr + la a0, data + li a1, 0x55 + li a2, 16 + // memchr(data, 0x55, 16) + jal memchr + la t0, data + addi t0, t0, 4 + // fail if a0 != data+4 + bne a0, t0, _fail + la a0, data + li a1, 0x12 + li a2, 16 + // memchr(data, 0x12, 16) + jal memchr + // check that result is NULL + bne a0, zero, _fail +// test strcpy + la a0, dest + la a1, small_str + // call strcpy(dest, small_str) + jal strcpy + la t0, dest + lw t1, 0(a0) + // ascii for "tset", as risc-v is little endian + li t2, 0x74736574 + bne t1, t2, _fail + +// return to exit() wrapper + lw ra, 0(sp) + addi sp, sp, 4 + li a0, 0 + ret + +_fail: + ebreak + // fail the test run + li a0, -1 + jal exit + + +check_data_dest_is_same: + la a0, data + la a1, dest + li a2, 4 +1: + lw t0, 0(a0) + lw t1, 0(a1) + bne t0, t1, _fail + addi a0, a0, 4 + addi a1, a1, 4 + addi a2, a2, -1 + blt zero, a2, 1b + ret + + +//CHECK: [CPU] Program exited with code 0 diff --git a/test/filecheck/lit.cfg b/test/filecheck/lit.cfg index 10030fb..129e4b6 100644 --- a/test/filecheck/lit.cfg +++ b/test/filecheck/lit.cfg @@ -6,4 +6,4 @@ xdsl_src = os.path.dirname(os.path.dirname(config.test_source_root)) config.name = "riscemu" config.test_format = lit.formats.ShTest(preamble_commands=[f"cd {xdsl_src}"]) -config.suffixes = ['.asm'] +config.suffixes = ['.asm', '.s']