libc: add tests and fix a bunch of bugs in string.s
This commit is contained in:
parent
41d17daeaf
commit
8ac4a56c08
@ -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!
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
114
test/filecheck/libc/test-string.s
Normal file
114
test/filecheck/libc/test-string.s
Normal file
@ -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.test_format = lit.formats.ShTest(preamble_commands=[f"cd {xdsl_src}"])
|
||||
config.suffixes = ['.asm']
|
||||
config.suffixes = ['.asm', '.s']
|
||||
|
Loading…
Reference in New Issue
Block a user