From 1bd754953ccf7832301de034a508cd164cc9f271 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 29 May 2023 11:48:09 +0100 Subject: [PATCH] runtime: move start of libc into separate folder --- examples/lib/libstring.asm | 152 ------------------------------- libc/README.md | 31 +++++++ {examples/lib => libc}/crt0.s | 0 {examples/lib => libc}/stdlib.s | 0 libc/string.s | 154 ++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 152 deletions(-) delete mode 100644 examples/lib/libstring.asm create mode 100644 libc/README.md rename {examples/lib => libc}/crt0.s (100%) rename {examples/lib => libc}/stdlib.s (100%) create mode 100644 libc/string.s diff --git a/examples/lib/libstring.asm b/examples/lib/libstring.asm deleted file mode 100644 index f2075e3..0000000 --- a/examples/lib/libstring.asm +++ /dev/null @@ -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 diff --git a/libc/README.md b/libc/README.md new file mode 100644 index 0000000..5ba54e3 --- /dev/null +++ b/libc/README.md @@ -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! + + diff --git a/examples/lib/crt0.s b/libc/crt0.s similarity index 100% rename from examples/lib/crt0.s rename to libc/crt0.s diff --git a/examples/lib/stdlib.s b/libc/stdlib.s similarity index 100% rename from examples/lib/stdlib.s rename to libc/stdlib.s diff --git a/libc/string.s b/libc/string.s new file mode 100644 index 0000000..0dd933b --- /dev/null +++ b/libc/string.s @@ -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