307 lines
5.7 KiB
ArmAsm
307 lines
5.7 KiB
ArmAsm
;; -*- mode: nasm -*-
|
|
%define SYS_open 0x2
|
|
%define SYS_close 0x3
|
|
%define SYS_write 0x1
|
|
%define SYS_read 0x0
|
|
%define SYS_lseek 0x8
|
|
%define SYS_exit 0x3c
|
|
|
|
%define O_RDONLY 0x0
|
|
%define SEEK_SET 0x0
|
|
%define FD_stderr 2
|
|
%define FD_stdout 1
|
|
%define FD_stdin 0
|
|
|
|
%define BUFFER_SIZE 2048
|
|
|
|
section .text
|
|
global _start
|
|
_start:
|
|
pop rax ; argc
|
|
pop QWORD [exec_name] ; argv[0]
|
|
|
|
check_arg_loop:
|
|
mov rdi,[rsp] ; argv[i]
|
|
; check for null
|
|
cmp rdi,0
|
|
je print_stdin_and_exit
|
|
|
|
; check for flags
|
|
call check_flag
|
|
cmp rax,0
|
|
je print_files ; no more flags
|
|
|
|
pop rdi ; remove argv[i] (a flag)
|
|
jmp check_arg_loop
|
|
|
|
print_files:
|
|
mov rdi,[rsp] ; argv[i]
|
|
cmp rdi,0
|
|
je print_files_end
|
|
|
|
; check if argv[i] is '-'
|
|
mov rsi,dash_str
|
|
call streql
|
|
cmp rax,0
|
|
jne print_files_stdin
|
|
|
|
; open file
|
|
mov rdi,[rsp] ; argv[i]
|
|
call open_file
|
|
|
|
; print file
|
|
mov rdi,rax
|
|
pop rsi ; argv[i]
|
|
call print_file
|
|
|
|
jmp print_files
|
|
|
|
print_files_stdin:
|
|
pop rdi ; argv[i]
|
|
mov rdi,FD_stdin
|
|
mov rsi,stdin_name
|
|
call print_file
|
|
|
|
; rewind stdin
|
|
mov rax,SYS_lseek
|
|
mov rdi,FD_stdin
|
|
mov rsi,0
|
|
mov rdx,SEEK_SET
|
|
syscall
|
|
|
|
jmp print_files
|
|
|
|
print_files_end:
|
|
xor rdi,rdi
|
|
jmp exit
|
|
|
|
open_file: ; int open_file(const char *path)
|
|
push rdi ; path
|
|
|
|
; open file
|
|
mov rax,SYS_open
|
|
; rdi already set
|
|
mov rsi,O_RDONLY
|
|
syscall
|
|
|
|
; check return
|
|
cmp rax,0
|
|
jl open_error
|
|
|
|
pop rdi ; path
|
|
ret
|
|
open_error:
|
|
call start_error
|
|
|
|
; message
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
mov rsi,open_error_text
|
|
mov rdx,open_error_text_len
|
|
syscall
|
|
|
|
; detail
|
|
mov rdi,[rsp] ; path
|
|
call strlen
|
|
|
|
mov rdx,rax
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
pop rsi ; path
|
|
syscall
|
|
|
|
call end_error
|
|
|
|
mov rdi,1
|
|
jmp exit
|
|
|
|
print_stdin_and_exit:
|
|
mov rdi,FD_stdin
|
|
mov rsi,stdin_name
|
|
call print_file
|
|
xor rdi,rdi
|
|
jmp exit
|
|
|
|
print_file: ; void print_file(int fd, const char *name)
|
|
push rdi ; fd
|
|
push rsi ; name
|
|
print_file_loop:
|
|
mov rax,SYS_read
|
|
mov rdi,[rsp + 8] ; fd
|
|
mov rsi,read_buff
|
|
mov rdx,BUFFER_SIZE
|
|
syscall
|
|
|
|
; check error
|
|
cmp rax,0
|
|
jl read_file_error
|
|
|
|
; no more bytes
|
|
je print_file_end
|
|
|
|
; print message
|
|
mov rdx,rax
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stdout
|
|
mov rsi,read_buff
|
|
syscall
|
|
|
|
jmp print_file_loop
|
|
|
|
print_file_end:
|
|
pop rsi ; name
|
|
pop rdi ; fd
|
|
ret
|
|
|
|
read_file_error:
|
|
call start_error
|
|
|
|
; message
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
mov rsi,read_error_text
|
|
mov rdx,read_error_text_len
|
|
syscall
|
|
|
|
; detail
|
|
mov rdi,[rsp] ; name
|
|
call strlen
|
|
|
|
mov rdx,rax
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
pop rsi ; name
|
|
syscall
|
|
|
|
call end_error
|
|
|
|
mov rdi,1
|
|
jmp exit
|
|
|
|
;; check arg for -u, exit if unknown flag
|
|
;; return 1 if found, 0 otherwise
|
|
check_flag: ; bool check_arg(const char *arg)
|
|
xor rax,rax
|
|
; check if arg[0] == '-'
|
|
cmp BYTE [rdi],'-'
|
|
jne check_flag_end
|
|
|
|
inc rdi
|
|
; rax still set
|
|
check_flag_loop:
|
|
; check null byte
|
|
mov cl,[rdi]
|
|
cmp cl,0
|
|
je check_flag_end
|
|
|
|
; check for u
|
|
cmp cl,'u'
|
|
jne check_flag_error
|
|
|
|
mov rax,1
|
|
inc rdi
|
|
jmp check_flag_loop
|
|
check_flag_error:
|
|
push rdi ; arg + i
|
|
call start_error
|
|
|
|
; message
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
mov rsi,arg_error_text
|
|
mov rdx,arg_error_text_len
|
|
syscall
|
|
|
|
; character
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
pop rsi ; arg + i
|
|
mov rdx,1
|
|
syscall
|
|
|
|
call end_error
|
|
|
|
mov rdi,1
|
|
jmp exit
|
|
check_flag_end:
|
|
ret
|
|
|
|
;; print exec_name and a colon_space
|
|
start_error: ; void start_error(void)
|
|
mov rdi,[exec_name]
|
|
call strlen
|
|
mov rdx,rax
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
mov rsi,[exec_name]
|
|
syscall
|
|
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
mov rsi,colon_space
|
|
mov rdx,colon_space_len
|
|
syscall
|
|
ret
|
|
|
|
;; print newline
|
|
end_error: ; void end_error(void)
|
|
mov rax,SYS_write
|
|
mov rdi,FD_stderr
|
|
mov rsi,newline_ptr
|
|
mov rdx,1
|
|
syscall
|
|
ret
|
|
|
|
streql: ; bool streql(const char *s1, const char *s2)
|
|
; check if both are zero
|
|
mov cl,[rdi] ; s1[i]
|
|
or cl,[rsi]
|
|
jz streql_true
|
|
|
|
; check if equal
|
|
mov cl,[rdi]
|
|
xor cl,[rsi]
|
|
jnz streql_false
|
|
|
|
inc rdi
|
|
inc rsi
|
|
jmp streql
|
|
streql_true:
|
|
mov rax,1
|
|
ret
|
|
streql_false:
|
|
xor rax,rax
|
|
ret
|
|
|
|
exit: ; NORETURN void exit(int status)
|
|
mov rax,SYS_exit
|
|
syscall
|
|
|
|
strlen: ; uint64 strlen(const char *str)
|
|
mov rax,rdi
|
|
strlen_loop:
|
|
cmp BYTE [rax],0
|
|
je strlen_end
|
|
inc rax
|
|
jmp strlen_loop
|
|
strlen_end:
|
|
sub rax,rdi
|
|
ret
|
|
|
|
section .bss
|
|
exec_name resq 1
|
|
read_buff resb BUFFER_SIZE
|
|
|
|
section .data
|
|
dash_str db "-",0x0
|
|
colon_space db ": "
|
|
colon_space_len equ $ - colon_space
|
|
newline_ptr db 0xA
|
|
stdin_name db "<stdin>",0x0
|
|
arg_error_text db "unknown flag: "
|
|
arg_error_text_len equ $ - arg_error_text
|
|
read_error_text db "read error: "
|
|
read_error_text_len equ $ - read_error_text
|
|
open_error_text db "could not open file for reading: "
|
|
open_error_text_len equ $ - open_error_text
|