runtime: move start of libc into separate folder
parent
a28bf834ac
commit
1bd754953c
@ -1,152 +0,0 @@
|
|||||||
; string operations in RISC-V Assembly
|
|
||||||
; All function restore all registers after use (even caller-saved ones)
|
|
||||||
|
|
||||||
.global NULL
|
|
||||||
; A global constant, points to the empty string
|
|
||||||
|
|
||||||
|
|
||||||
.global strlen
|
|
||||||
; size_t libstr_strlen(char* str)
|
|
||||||
; return the length of str
|
|
||||||
|
|
||||||
|
|
||||||
.global strncpy
|
|
||||||
; char *strncpy(char *dest, const char *src, size_t n)
|
|
||||||
; copy n bytes from source into dest. If source ends before n bytes, the rest is filled with null-bytes
|
|
||||||
; returns pointer to dest
|
|
||||||
|
|
||||||
|
|
||||||
.global strcpy
|
|
||||||
; char *strncpy(char *dest, const char *src)
|
|
||||||
; copy string src into dest, including null terminator
|
|
||||||
; returns pointer to dest
|
|
||||||
|
|
||||||
|
|
||||||
.global memchr
|
|
||||||
; void *memchr(const void *str, char c, size_t n)
|
|
||||||
; search vor the first occurance of c in str
|
|
||||||
; returns a pointer to the first occurance, or NULL
|
|
||||||
|
|
||||||
|
|
||||||
.global memset
|
|
||||||
; void *memset(void *str, char c, size_t n)
|
|
||||||
; copies the character c to the first n characters of str.
|
|
||||||
|
|
||||||
|
|
||||||
;.global memcmp
|
|
||||||
;.global memcpy
|
|
||||||
;.global strcat
|
|
||||||
|
|
||||||
; Create NullPtr constant
|
|
||||||
.set NULL, 0x00
|
|
||||||
|
|
||||||
|
|
||||||
.text
|
|
||||||
strlen:
|
|
||||||
; size_t strlen(char* str)
|
|
||||||
; push s1, s2 to the stack
|
|
||||||
sw s1, sp, -4
|
|
||||||
sw s2, sp, -8
|
|
||||||
; since no subroutines are called, we don't need to increment or decrement the sp
|
|
||||||
addi s2, zero, -1 ; length (since null byte is counted by this method, we return len - 1)
|
|
||||||
__strlen_loop:
|
|
||||||
lb s1, a0, 0 ; read character
|
|
||||||
addi s2, s2, 1 ; increment number bytes read
|
|
||||||
addi a0, a0, 1
|
|
||||||
bne s1, zero, __strlen_loop
|
|
||||||
; we are done, set return value in a0
|
|
||||||
add a0, zero, s2
|
|
||||||
; pop s1, s2, from stack
|
|
||||||
lw s1, sp, -4
|
|
||||||
lw s2, sp, -8
|
|
||||||
ret
|
|
||||||
|
|
||||||
strncpy:
|
|
||||||
; char *strncpy(char *dest, const char *src, size_t n)
|
|
||||||
; copy size bytes from source to dest
|
|
||||||
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
|
|
||||||
__strncpy_loop:
|
|
||||||
beq a2, zero, __strncpy_end
|
|
||||||
; copy byte
|
|
||||||
lb s2, a1, 0 ; read first byte from src
|
|
||||||
sb s2, a0, 0 ; write first byte to dest
|
|
||||||
; increment pointers
|
|
||||||
addi a0, a0, 1
|
|
||||||
addi a1, a1, 1
|
|
||||||
; one less byte to copy
|
|
||||||
addi a2, a2, -1
|
|
||||||
; if we read the terminating byte, jump to fill code
|
|
||||||
beq s2, zero, __strncpy_fill
|
|
||||||
; otherwise continue copying
|
|
||||||
j __strncpy_loop
|
|
||||||
__strncpy_fill:
|
|
||||||
; fill remaining space with 0 bytes
|
|
||||||
; if no bytes left, stop filling
|
|
||||||
beq a2, zero, __strncpy_end
|
|
||||||
sb zero, a0, 0
|
|
||||||
addi a0, a0, 1
|
|
||||||
addi a2, a2, -1
|
|
||||||
j __strncpy_fill
|
|
||||||
__strncpy_end:
|
|
||||||
; set return value
|
|
||||||
add a0, zero, s1
|
|
||||||
; pop s1, s2 from stack
|
|
||||||
lw s1, sp, -4
|
|
||||||
lw s2, sp, -8
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
strcpy:
|
|
||||||
; char *strncpy(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
|
|
||||||
__strcpy_loop:
|
|
||||||
; copy byte
|
|
||||||
lb s2, a1, 0 ; read first byte from src
|
|
||||||
sb s2, a0, 0 ; write first byte to dest
|
|
||||||
; increment pointers
|
|
||||||
addi a0, a0, 1
|
|
||||||
addi a1, a1, 1
|
|
||||||
bne s2, zero, __strcpy_loop
|
|
||||||
; we are done copying, return
|
|
||||||
; set return value
|
|
||||||
add a0, zero, s1
|
|
||||||
; pop s1, s2 from stack
|
|
||||||
lw s1, sp, -4
|
|
||||||
lw s2, sp, -8
|
|
||||||
ret
|
|
||||||
|
|
||||||
memchr:
|
|
||||||
; void *memchr(const void *str, char c, size_t n)
|
|
||||||
sw s1, sp, -4 ; push s1 to the stack
|
|
||||||
__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
|
|
||||||
; return pointer to prev byte (as the prev byte actually matched a1)
|
|
||||||
addi a0, a0, -1
|
|
||||||
; pop s1, s2 from stack
|
|
||||||
lw s1, sp, -4
|
|
||||||
ret
|
|
||||||
__memchr_ret_null:
|
|
||||||
; nothing found, return nullptr
|
|
||||||
addi a0, zero, NULL
|
|
||||||
lw s1, sp, -4
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
memset:
|
|
||||||
; void *memset(void *str, char c, size_t n)
|
|
||||||
__memset_loop:
|
|
||||||
beq a2, zero, __memset_ret
|
|
||||||
sb a1, a0, 0
|
|
||||||
addi a0, a0, 1
|
|
||||||
addi a2, a2, -1
|
|
||||||
j __memset_loop
|
|
||||||
__memset_ret:
|
|
||||||
ret
|
|
@ -0,0 +1,31 @@
|
|||||||
|
# RiscEmu LibC
|
||||||
|
|
||||||
|
This is a very basic implementation of libc in risc-v assembly, meant specifically for the riscemu emulator.
|
||||||
|
|
||||||
|
This is currently very incomplete, only a handful of methods are implemented, and most of them pretty basic.
|
||||||
|
|
||||||
|
## Contents:
|
||||||
|
|
||||||
|
### `stdlib.s`
|
||||||
|
|
||||||
|
Basic implementations of:
|
||||||
|
|
||||||
|
- `malloc`/`free` (that leaks memory)
|
||||||
|
- `rand`/`srand` (using xorshift)
|
||||||
|
- `exit`/`atexit` (supporting up to 8 exit handlers)
|
||||||
|
|
||||||
|
### `string.s`
|
||||||
|
|
||||||
|
Somewhat nice implementations of:
|
||||||
|
|
||||||
|
- `strlen`
|
||||||
|
- `strncpy`
|
||||||
|
- `strcpy`
|
||||||
|
- `memchr`
|
||||||
|
- `memset` (very basic byte-by-byte copy)
|
||||||
|
|
||||||
|
## 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!
|
||||||
|
|
||||||
|
|
@ -0,0 +1,154 @@
|
|||||||
|
// string operations in RISC-V Assembly
|
||||||
|
//
|
||||||
|
// Copyright (c) 2023 Anton Lydike
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
.global NULL
|
||||||
|
// A global constant representing zero
|
||||||
|
|
||||||
|
|
||||||
|
.global strlen
|
||||||
|
// size_t libstr_strlen(char* str)
|
||||||
|
// return the length of str
|
||||||
|
|
||||||
|
|
||||||
|
.global strncpy
|
||||||
|
// char *strncpy(char *dest, const char *src, size_t n)
|
||||||
|
// copy n bytes from source into dest. If source ends before n bytes, the rest is filled with null-bytes
|
||||||
|
// returns pointer to dest
|
||||||
|
|
||||||
|
|
||||||
|
.global strcpy
|
||||||
|
// char *strncpy(char *dest, const char *src)
|
||||||
|
// copy string src into dest, including null terminator
|
||||||
|
// returns pointer to dest
|
||||||
|
|
||||||
|
|
||||||
|
.global memchr
|
||||||
|
// void *memchr(const void *str, char c, size_t n)
|
||||||
|
// search vor the first occurance of c in str
|
||||||
|
// returns a pointer to the first occurance, or NULL
|
||||||
|
|
||||||
|
|
||||||
|
.global memset
|
||||||
|
// void *memset(void *str, char c, size_t n)
|
||||||
|
// copies the character c to the first n characters of str.
|
||||||
|
|
||||||
|
|
||||||
|
//.global memcmp
|
||||||
|
//.global memcpy
|
||||||
|
//.global strcat
|
||||||
|
|
||||||
|
// Create NullPtr constant
|
||||||
|
.set NULL, 0x00
|
||||||
|
|
||||||
|
|
||||||
|
.text
|
||||||
|
strlen:
|
||||||
|
// size_t strlen(char* str)
|
||||||
|
// push s1, s2 to the stack
|
||||||
|
sw s1, sp, -4
|
||||||
|
sw s2, sp, -8
|
||||||
|
// since no subroutines are called, we don't need to increment or decrement the sp
|
||||||
|
addi s2, zero, -1 // length (since null byte is counted by this method, we return len - 1)
|
||||||
|
__strlen_loop:
|
||||||
|
lb s1, a0, 0 // read character
|
||||||
|
addi s2, s2, 1 // increment number bytes read
|
||||||
|
addi a0, a0, 1
|
||||||
|
bne s1, zero, __strlen_loop
|
||||||
|
// we are done, set return value in a0
|
||||||
|
add a0, zero, s2
|
||||||
|
// pop s1, s2, from stack
|
||||||
|
lw s1, sp, -4
|
||||||
|
lw s2, sp, -8
|
||||||
|
ret
|
||||||
|
|
||||||
|
strncpy:
|
||||||
|
// char *strncpy(char *dest, const char *src, size_t n)
|
||||||
|
// copy size bytes from source to dest
|
||||||
|
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
|
||||||
|
__strncpy_loop:
|
||||||
|
beq a2, zero, __strncpy_end
|
||||||
|
// copy byte
|
||||||
|
lb s2, a1, 0 // read first byte from src
|
||||||
|
sb s2, a0, 0 // write first byte to dest
|
||||||
|
// increment pointers
|
||||||
|
addi a0, a0, 1
|
||||||
|
addi a1, a1, 1
|
||||||
|
// one less byte to copy
|
||||||
|
addi a2, a2, -1
|
||||||
|
// if we read the terminating byte, jump to fill code
|
||||||
|
beq s2, zero, __strncpy_fill
|
||||||
|
// otherwise continue copying
|
||||||
|
j __strncpy_loop
|
||||||
|
__strncpy_fill:
|
||||||
|
// fill remaining space with 0 bytes
|
||||||
|
// if no bytes left, stop filling
|
||||||
|
beq a2, zero, __strncpy_end
|
||||||
|
sb zero, a0, 0
|
||||||
|
addi a0, a0, 1
|
||||||
|
addi a2, a2, -1
|
||||||
|
j __strncpy_fill
|
||||||
|
__strncpy_end:
|
||||||
|
// set return value
|
||||||
|
add a0, zero, s1
|
||||||
|
// pop s1, s2 from stack
|
||||||
|
lw s1, sp, -4
|
||||||
|
lw s2, sp, -8
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
strcpy:
|
||||||
|
// char *strncpy(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
|
||||||
|
__strcpy_loop:
|
||||||
|
// copy byte
|
||||||
|
lb s2, a1, 0 // read first byte from src
|
||||||
|
sb s2, a0, 0 // write first byte to dest
|
||||||
|
// increment pointers
|
||||||
|
addi a0, a0, 1
|
||||||
|
addi a1, a1, 1
|
||||||
|
bne s2, zero, __strcpy_loop
|
||||||
|
// we are done copying, return
|
||||||
|
// set return value
|
||||||
|
add a0, zero, s1
|
||||||
|
// pop s1, s2 from stack
|
||||||
|
lw s1, sp, -4
|
||||||
|
lw s2, sp, -8
|
||||||
|
ret
|
||||||
|
|
||||||
|
memchr:
|
||||||
|
// void *memchr(const void *str, char c, size_t n)
|
||||||
|
sw s1, sp, -4 // push s1 to the stack
|
||||||
|
__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
|
||||||
|
// return pointer to prev byte (as the prev byte actually matched a1)
|
||||||
|
addi a0, a0, -1
|
||||||
|
// pop s1, s2 from stack
|
||||||
|
lw s1, sp, -4
|
||||||
|
ret
|
||||||
|
__memchr_ret_null:
|
||||||
|
// nothing found, return nullptr
|
||||||
|
addi a0, zero, NULL
|
||||||
|
lw s1, sp, -4
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
memset:
|
||||||
|
// void *memset(void *str, char c, size_t n)
|
||||||
|
__memset_loop:
|
||||||
|
beq a2, zero, __memset_ret
|
||||||
|
sb a1, a0, 0
|
||||||
|
addi a0, a0, 1
|
||||||
|
addi a2, a2, -1
|
||||||
|
j __memset_loop
|
||||||
|
__memset_ret:
|
||||||
|
ret
|
Loading…
Reference in New Issue