summaryrefslogtreecommitdiffstats
path: root/cat.asm
blob: 13d7918ad7061988e24eb69967f21126d5a4c91a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
; Version	: 1.0
; Updated	: 28/10/2020
; Description   : cat(1) in assembly
; Copyright (C)	: 2020, 2021 Gentoo-libre Install
; License	: GPLv3+

section .bss
	Buff resb 16384		;read data up to 16384 bytes at a time
	bufflen equ $-Buff

section .data

section .text
	global _start
_start:
pop rsi			;Pop number of args from the stack

cmp esi,1
je stdin		;go to stdin mode if there are no arguments


pop rsi			;discard argv[0]

nextarg:
pop rsi			;get pointer to argv[x]

; we could use argc as a loop counter, but we can just check to see if we popped a zero intead
test rsi, rsi
jz exit

; open each file for reading
open:
	mov eax, 2	;sys_open
	mov rdi, rsi	;filename = pointer to null terminated filename
	xor esi, esi	;O_RDONLY
	xor edx, edx	;don't set a mode
	syscall

	; the result is returned in rax
	test rax, rax
	js nextarg	;get the next argv if rax is negative (as the file couldn't be opened)

copy:
	mov edi, eax	;move the fd to rdi for read
	mov r15, rax	;copy the fd to an AMD64 additional register for safekeeping
	call read

output:
	mov edi, 1	;stdout
	mov edx, eax	;rax contains the number of bytes read
	call write

	mov ecx, eax	;copy the amount written to a different register
	mov rax, r15	;copy the fd back to rax

	test ecx, bufflen	;check if all the bytes in the buffer have been used
	jnz copy	;if so, jump to copy the remaining bytes not read into the buffer yet

close:
	mov rdi, r15	;move fd into rdi
	mov eax, 3	;sys_close
	syscall

	jmp nextarg




stdin:
        xor edi, edi		;stdin == 0
	call read

        test eax,eax		;Check if the return value was 0
        je exit			;Jump to exit on EOF recieved

	mov edi, 1		;file descriptor = stdout
	mov edx, eax		;move num bytes read to number of bytes to write
	call write

	jmp stdin




; read function, takes rdi as an argument (a fd)
read:
	mov edx, bufflen	;read up to bufflen bytes at once
        mov rsi, Buff		;Address of buffer to read into
	xor eax, eax		;sys_read
        syscall
	ret

; write function, takes rdi as an argument (a fd) and also rdx (number of bytes)
write:
	mov rsi, Buff		;mov address of buffer
	mov eax, 1		;sys_write
	syscall
	ret

exit:
	xor edi, edi      	; exit status == 0
	mov eax, 60       	; SYSCALL number for EXIT
	syscall