Compare commits
1 Commits
main
..
6549711bfe
| Author | SHA1 | Date | |
|---|---|---|---|
|
6549711bfe
|
@@ -1,8 +1,8 @@
|
|||||||
cat: cat.o
|
cat: cat.o
|
||||||
ld -o cat cat.o
|
ld -o cat cat.o
|
||||||
|
|
||||||
cat.o: cat.nasm
|
cat.o: cat.s
|
||||||
nasm -f elf64 cat.nasm
|
nasm -g -f elf64 cat.s
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# cat
|
# cat
|
||||||
[](https://ci.zander.im/job/asm-cat/)
|
|
||||||
|
|
||||||
Posix compliant cat written in NASM Assembler for practice. This program
|
Posix compliant cat written in NASM Assembler for practice.
|
||||||
**ONLY** works on Linux.
|
|
||||||
@@ -1,306 +0,0 @@
|
|||||||
;; -*- mode: asm; -*-
|
|
||||||
%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
|
|
||||||
@@ -0,0 +1,310 @@
|
|||||||
|
%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 SYS_fcntl 0x48
|
||||||
|
|
||||||
|
%define O_RDONLY 0x0
|
||||||
|
%define O_NONBLOCK 0x800
|
||||||
|
%define F_GETFL 3
|
||||||
|
%define F_SETFL 4
|
||||||
|
%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
|
||||||
Reference in New Issue
Block a user