; 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