diff --git a/.asm-lsp.toml b/.asm-lsp.toml new file mode 100644 index 0000000..242ea26 --- /dev/null +++ b/.asm-lsp.toml @@ -0,0 +1,7 @@ +[default_config] +version = "0.10.0" +instruction_set = "arm" +assembler = "gas" + +[default_config.opts] +compiler = "arm-linux-gnueabihf-gcc" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1841b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.out +out diff --git a/constants.S b/constants.S new file mode 100644 index 0000000..ef34aad --- /dev/null +++ b/constants.S @@ -0,0 +1,9 @@ + +/* Linux standard file descriptors */ +.equ STDIN, 0x0 +.equ STDOUT, 0x1 +.equ STDERR, 0x2 + +.equ ENOENT, 0xFFFFFFFE +.equ ENOTDIR, 0xFFFFFFEC + diff --git a/errors.S b/errors.S deleted file mode 100644 index 0a89993..0000000 --- a/errors.S +++ /dev/null @@ -1,4 +0,0 @@ - -.equ ENOENT, 0xFFFFFFFE -.equ ENOTDIR, 0xFFFFFFEC - diff --git a/main.S b/main.S index d22b079..2316e5b 100644 --- a/main.S +++ b/main.S @@ -1,18 +1,33 @@ .include "syscalls.S" -.include "errors.S" +.include "constants.S" +.include "string.S" .global _start -exit: @ r0 should have the status code to exit with - mov r7, #SYS_EXIT @ Move the exit syscall number to r7 (which is the register svc reads to know which syscall to execute) - svc 0 @ execute the syscall +/* + Exits the program with the provided exit code -print: @ r1 => buffer to print. r2 => how many bytes to print. clobbers r0 - @ print to stdout - mov r0, #1 @ Use STDOUT fd as the write fd - mov r7, #SYS_WRITE @ call write(2) + @args: + r0 => exit code +*/ +exit: + mov r7, #SYS_EXIT svc 0 - bx lr @ return to caller + +/* + print to stdout + + @args: + r1 => pointer to buffer to print + r2 => how many bytes to print + @clobbers: + r0 +*/ +print: + mov r0, #STDOUT + mov r7, #SYS_WRITE + svc 0 + bx lr open_fail: push {r0} @@ -48,81 +63,12 @@ fd_not_found: mov r0, #1 bl exit -open_and_read_file: - @ open file - ldr r0, =FILE @ filepath - mov r1, #0 @ flags - mov r2, #0 @ mode_t - mov r7, #SYS_OPEN - svc 0 - - cmp r0, #0 - blt open_fail - - @ read the file contents - @ r0 needs the fd, which it should already be since the call to open() set r0 to the fd. - ldr r1, =buffer @ pointer to buffer to read into - mov r2, #50 @ how many bytes to read - mov r7, #SYS_READ - svc 0 - - @ print the contents of the buffer - ldr r1, =buffer - mov r2, #50 @ FIXME: hardcoded badness - bl print - - ldr r1, =NEWLINE - mov r2, #1 - bl print - - mov r0, #0 - bl exit - -strlen: @ r0 holds the string length. r1 should be a pointer to the start of the string. - mov r0, #0 -strlen_loop: - ldrb r2, [r1, r0] - cmp r2, #0 - bxle lr - - add r0, r0, #1 - b strlen_loop - -direntry_loop: - cmp r4, r8 - bxge lr - - push {lr} - - add r1, r5, #10 @ offset 10 bytes into the dirent struct to reach d_name. - bl strlen - mov r2, r0 - bl print - - ldr r1, =NEWLINE - mov r2, #1 - bl print - - pop {lr} - - @ load the value (as 16-bits zero-extended as opposed to loading 32-bits and then extending that ourselves with UXTH) - @ in the memory address of r5 offset by 8 bytes to get us the d_reclen - ldrh r6, [r5, #8] - add r5, r5, r6 @ skip to the next dirent - - add r4, r4, r6 @ accumulate how many bytes we read - - b direntry_loop - -@ TODO: alphabetically sort the directory entries before printing them. _start: ldr r0, [sp] cmp r0, #1 ldrgt r0, [sp, #8] ldrle r0, =FALLBACK_DIR - @ open file - @ldr r0, =FALLBACK_DIR @ filepath mov r1, #0 @ flags mov r2, #0 @ mode_t mov r7, #SYS_OPEN @@ -133,7 +79,6 @@ _start: cmp r0, #0 blt open_fail - @ read the directory contents @ r0 needs the fd, which it should already be since the call to open() set r0 to the fd. ldr r1, =buffer @ pointer to linux_dirent structure @ TODO: we can allocate the required memory on the stack instead of in the bss section I think. @@ -146,16 +91,36 @@ _start: cmp r0, #0 blt dir_read_fail - mov r8, r0 @ store how many bytes the getdents syscall read, so we can use that to exit the direntry loop mov r4, #0 @ initialize r4 to 0 ldr r5, =buffer - bl direntry_loop +1: + push {r0} + + add r1, r5, #10 @ offset 10 bytes into the dirent struct to reach d_name. + bl strlen + mov r2, r0 + bl print + + ldr r1, =NEWLINE + mov r2, #1 + bl print + + pop {r0} + + @ load the value (as 16-bits zero-extended as opposed to loading 32-bits and then extending that ourselves with UXTH) + @ in the memory address of r5 offset by 8 bytes to get us the d_reclen + ldrh r6, [r5, #8] + add r5, r5, r6 @ skip to the next dirent + + add r4, r4, r6 @ accumulate how many bytes we read + + cmp r4, r0 + blt 1b mov r0, #0 bl exit .data - FILE: .asciz "/home/illusion/asm.txt" FALLBACK_DIR: .asciz "." OPEN_FAIL: .ascii "Failed to open file descriptor" DIR_READ_FAIL: .ascii "Failed to read the directory\n" diff --git a/string.S b/string.S new file mode 100644 index 0000000..45a285f --- /dev/null +++ b/string.S @@ -0,0 +1,25 @@ +/* + Current implementation only counts the bytes instead of characters. + + @args: + r1 => pointer to the string + @returns: + r0 => string length + @clobbers: + r2 +*/ +strlen: + mov r0, #0 +1: + ldrb r2, [r1, r0] + cmp r2, #0 + bxle lr + + add r0, r0, #1 + b 1b + +/* + @input r1, r2 - pointers to the strings to compare + @return r0 - 0 if equal, -1 if a < b, 1 if a > b +*/ +strcmp: @ TODO: implement