libc: add tests and fix a bunch of bugs in string.s

master
Anton Lydike 1 year ago
parent 41d17daeaf
commit 8ac4a56c08

@ -26,6 +26,4 @@ Somewhat nice implementations of:
## Correctness: ## 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!

@ -96,7 +96,11 @@ free:
// s0 = &_atexit_count // s0 = &_atexit_count
// s2 = &_atexit_calls // s2 = &_atexit_calls
// s1 = updated value of atexit // s1 = updated value of atexit
// s3 = exit code
exit: exit:
// save exit code to s3
mv s3, a0
_exit_start:
la s0, _atexit_count // s0 = &_atexit_count la s0, _atexit_count // s0 = &_atexit_count
lw s1, 0(s0) // s1 = *(&_atexit_count) lw s1, 0(s0) // s1 = *(&_atexit_count)
// exit if no atexit() calls remain // exit if no atexit() calls remain
@ -108,12 +112,12 @@ exit:
li s2, _atexit_calls li s2, _atexit_calls
add s1, s1, s2 // s1 = &_atexit_calls + (s1) add s1, s1, s2 // s1 = &_atexit_calls + (s1)
lw s1, 0(s1) // s1 = *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 zero, s1, 0 // jump to address in s1
// jalr will call the other function, which will then return back // jalr will call the other function, which will then return back
// to the beginning of exit. // to the beginning of exit.
_exit: _exit:
li a0, 0 mv a0, s3
li a7, 93 li a7, 93
ecall ecall

@ -3,8 +3,9 @@
// Copyright (c) 2023 Anton Lydike // Copyright (c) 2023 Anton Lydike
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// Create NullPtr constant
.equ NULL, 0x00
.global NULL .global NULL
// A global constant representing zero
.global strlen .global strlen
@ -35,13 +36,11 @@
// copies the character c to the first n characters of str. // copies the character c to the first n characters of str.
// missing implementations
//.global memcmp //.global memcmp
//.global memcpy //.global memcpy
//.global strcat //.global strcat
// Create NullPtr constant
.set NULL, 0x00
.text .text
strlen: strlen:
@ -101,7 +100,7 @@ __strncpy_end:
strcpy: 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 s1, sp, -4 // push s1 to the stack
sw s2, sp, -8 // push s1 to the stack sw s2, sp, -8 // push s1 to the stack
add s1, a0, zero // save dest pointer for return add s1, a0, zero // save dest pointer for return
@ -124,15 +123,16 @@ __strcpy_loop:
memchr: memchr:
// void *memchr(const void *str, char c, size_t n) // void *memchr(const void *str, char c, size_t n)
sw s1, sp, -4 // push s1 to the stack sw s1, sp, -4 // push s1 to the stack
andi a1, a1, 0xff // trim a1 to be byte-sized
__memchr_loop: __memchr_loop:
beq a2, zero, __memchr_ret_null beq a2, zero, __memchr_ret_null
lb s1, a0, 0 lb s1, a0, 0
addi a0, a0, 1 // let a0 point to the next byte addi a0, a0, 1 // let a0 point to the next byte
addi a2, a2, -1 // decrement bytes to copy by 1 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) // return pointer to prev byte (as the prev byte actually matched a1)
addi a0, a0, -1 addi a0, a0, -1
// pop s1, s2 from stack // pop s1, from stack
lw s1, sp, -4 lw s1, sp, -4
ret ret
__memchr_ret_null: __memchr_ret_null:

@ -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

@ -6,4 +6,4 @@ xdsl_src = os.path.dirname(os.path.dirname(config.test_source_root))
config.name = "riscemu" config.name = "riscemu"
config.test_format = lit.formats.ShTest(preamble_commands=[f"cd {xdsl_src}"]) config.test_format = lit.formats.ShTest(preamble_commands=[f"cd {xdsl_src}"])
config.suffixes = ['.asm'] config.suffixes = ['.asm', '.s']

Loading…
Cancel
Save