asm-cat/cat.s

302 lines
4.6 KiB
ArmAsm
Raw Normal View History

2022-08-28 14:29:25 -07:00
;; -*- mode: nasm -*-
;; Select the one that matches your os
%include "linux.s"
;%include "freebsd.s"
%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