Files
klibc/src/string.asm

219 lines
4.5 KiB
NASM

%include "src/constants.asm"
section .text
global strlen
global strcpy
global strcat
global strclr
global strcmp
global strfind
;----- strlen(*str[]) -----;
; Gets the length of given string
; Return value: Length of given string
; Used registers:
; rax* Byte to check in str[] >> (ret) length of given string
; rdi* (arg) Pointer to str[]
; rcx* Counter for scasb
strlen:
xor al, al
mov rcx, -1
cld
repne scasb
mov rax, rcx
not rax
dec rax
ret
;----- strcpy(*dest[], *src[], maxLength) -----;
; Copies one string (src) into the other (dest), overwriting dest
; NOTE: maxLength must never exceed size of dest[].
; Return value: Pointer to dest[]
; Used registers:
; rax* (ret) Pointer to dest[]
; rdi* (arg) Pointer to dest[]
; rsi* (arg) Pointer to src[]
; rdx (arg) Size of dest[]
; rcx* Counter for movsb
; r8* Backup for rdi
strcpy:
mov r8, rdi
mov rdi, rsi
call strlen
inc rax
cmp rax, rdx
cmova rcx, rdx
cmovbe rcx, rax
cmp rcx, rdx
jb .copy
dec rcx
.copy:
mov rdi, r8
cld
rep movsb
mov byte [rdi], EOS
mov rax, r8
ret
;----- strcat(*dest[], *src[], maxLength) -----;
; Concatenate src[] into dest[]
; Return value: Pointer to dest[]
; Used registers:
; rax* (ret) Pointer to dest[]
; rdi* (arg) Pointer to dest[]
; rsi* (arg) Pointer to src[]
; rdx (arg) Size of dest[]
; rcx* Counter for movsb
; r8* Backup for rdi (point to start of dest)
; r9* Backup for rsi
; r10* Backup for rdi (point to end of dest)
; r11* Backup for strlen(dest)
strcat:
mov r8, rdi
mov r9, rsi
call strlen
mov r11, rax
sub rdx, rax
dec rdi
mov r10, rdi
mov rdi, rsi
call strlen
cmp rax, rdx
jb .copy
dec rdx
.copy:
cmp rdx, r11
jle .quit
mov rcx, rdx
mov rsi, r9
mov rdi, r10
cld
rep movsb
mov byte [rdi], EOS
.quit:
mov rax, r8
ret
;----- strclr(*str[], maxLength) -----;
; Clears a string by placing [maxLength] EOS into string.
; Thus DANGEROUS function: MAKE SURE maxLength IS SIZE OF str[] - greater values WILL cause issues and eventually crashes
; Return value: N/A
; Used registers:
; rdi* (arg) Pointer to str[]
; rsi (arg) Length of str[]
; rcx* Counter for STOSB
; rax* Character storage (AL) for STOSB
strclr:
mov rcx, rsi
xor al, al
cld
rep stosb
ret
;----- strcmp(*str1[], *str2[]) -----;
; Compares str2 against str1
; Return values:
; 0 Two strings are the same, OR str1 or str2 is empty
; Length of str1 str2 is longer than str1, but no difference was found in between str1 and str2 -up to the point str1 ended-
; Anything else Position (index+1) where str1 and str2 differ
; Used registers:
; rax* (ret)
; rdi Pointer to str1
; rsi Pointer to str2
; rcx* Counter for scasb
; rdx* Length of str1
; r8* Backup for rdi
strcmp:
xor rax, rax
cmp byte [rdi], EOS
je .equal
cmp byte [rsi], EOS
je .equal
mov r8, rdi
call strlen
mov rcx, rax
mov rdx, rax
mov rdi, r8
cld
repe cmpsb
je .equal
mov rax, rdx
sub rax, rcx
jmp .quit
.equal:
cmp byte [rsi], EOS
jne .quit
xor rax, rax
.quit:
ret
;----- strfind(*str[], *what[], start_at) -----;
; Finds string inside another string.
; Return values: 0 if what[] wasn't found within str[]. Position (index+1) where first character was found in str[] otherwise
; Used registers:
; rax* (ret)
; rdi (arg) Pointer to str[]
; rsi (arg) Pointer to what[]
; rdx (arg) Where to start looking in str[] (index)
; rcx* Keeps track of current position in str[]
; r8* Stores index where first character match of what[] was found
; r9* Used to move byte for cmp instruction
; r10* Keeps track if there is currently a match between str[] and what[]
; r11* Backup for original pointer to what[]
strfind:
xor rax, rax
mov rcx, 1
add rcx, rdx
add rdi, rdx
xor r10b, r10b
mov r11, rsi
.findStr:
cmp byte [rsi], EOS
je .testFullMatch
cmp byte [rdi], EOS
je .quit
mov r9b, byte [rsi]
cmp byte [rdi], r9b
jne .noMatch
;.hasMatch:
test r10b, r10b
jnz .notFirstChar
mov r10b, 1
mov r8, rcx
.notFirstChar:
inc rsi
jmp .continueLoop
.noMatch:
; not gonna figure out here if there was an existing match already. just XOR r10b,r10b and load original pointer to what[] to rsi
; EDIT: actually yes I am. strfind("gidgiddy", "giddy", 0); [gid]giddy<>[gid]dy is a match but then gid[g]iddy<>gid[d]y is not while it should check gid[g]iddy<>[g]iddy
test r10b, r10b
jz .continueLoop
mov rsi, r11
mov r9b, byte [rsi]
cmp byte [rdi], r9b
jne .itReallyWasNoMatchAfterAll
mov r8, rcx
inc rsi
jmp .continueLoop
.itReallyWasNoMatchAfterAll:
xor r10b, r10b
mov rsi, r11
.continueLoop:
inc rdi
inc rcx
jmp .findStr
.testFullMatch:
test r10b, r10b
jz .quit
mov rax, r8
.quit:
ret