summaryrefslogtreecommitdiff
path: root/PGU/CHAP5/toupper.up
blob: d4c236780037bd7764e2ffca5296d0def1b28b5e (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# CONVERT AN INPUT FILE TO AN OUTPUT FILE WITH ALL
# LETTERS CONVERTED TO UPPERCASE

.SECTION .DATA

# CONSTANTS
.EQU SYS_OPEN, 2
.EQU SYS_WRITE, 1
.EQU SYS_READ, 0
.EQU SYS_CLOSE, 3
.EQU SYS_EXIT, 60

# WE HAVE NO ACCESS TO HEADERS, SO, LET'S DEFINE OUR FLAGS
.EQU O_RDONLY, 0
.EQU O_CREAT_WRONLY_TRUNC, 03101

# ADD SOME OTHER NAMING TO MAKE MY LIFE EASIER
.EQU STDIN, 0
.EQU STDOUT, 1
.EQU STDERR, 2

.EQU END_OF_FILE, 0

.EQU NUMBER_ARGUMENTS, 2

################################################################

.SECTION .BSS

.EQU BUFFER_SIZE, 500
.LCOMM BUFFER_DATA, BUFFER_SIZE

################################################################

.SECTION .TEXT

# STACK POSITIONS

.EQU ST_SIZE_RESERVE, 16
.EQU ST_FD_IN, -8
.EQU ST_FD_OUT, -16
.EQU ST_ARGC, 0	# NUMBER OF ARGUMENTS
.EQU ST_ARGV_0, 8	# PROGRAM'S NAME
.EQU ST_ARGV_1, 16	# INPUT FILE NAME
.EQU ST_ARGV_2, 24	# OUTPUT FILE NAME

.GLOBL _START
.GLOBAL CONVERT_TO_UPPER # DECLARATION ONLY

### START OF PROGRAM ###
_START:

	# SAVE STACK POINTER
	MOVQ %RSP, %RBP

	# ALLOC SPACE FOR FDS ON THE STACK
	SUBQ $ST_SIZE_RESERVE, %RSP

# LABELS ARE HERE JUST TO MAKE MY LIFE EASIER IN SPLITTING THE SECTIONS
# I WON'T BE JUMPING AROUND...

# INT OPEN(CONST CHAR *PATHNAME, INT FLAGS, MODE_T MODE)
# ARGUMENT'S ORDER:   %RDI, %RSI, %RDX

OPEN_FILES:
OPEN_FD_IN:
	MOVQ $SYS_OPEN, %RAX		# SETUP SYSCALL NUMBER
	MOVQ ST_ARGV_1(%RBP), %RDI	# INPUT FILENAME INTO %RDI
	MOVQ $O_RDONLY, %RSI		# OPEN IN O_RDONLY
	MOVQ $0666, %RDX		# REGULAR POSIX PERMS
	SYSCALL				# INVOKE KERNEL TO CALL SYS_OPEN()

STORE_FD_IN:
	MOVQ %RAX, ST_FD_IN(%RBP)	# SAVE FILE'S FD

OPEN_FD_OUT:
	MOVQ $SYS_OPEN, %RAX		# SETUP SYSCALL NUMBER
	MOVQ ST_ARGV_2(%RBP), %RDI	# OUTPUT FILE NAME LOCATION TO %EBX
	MOVQ $O_CREAT_WRONLY_TRUNC, %RSI# SETUP WRITING FLAGS
	MOVQ $0666, %RDX		# POSIX MODE
	SYSCALL				# INVOKE KERNEL (SYS_OPEN())

STORE_FD_OUT:
	MOVQ %RAX, ST_FD_OUT(%RBP)	# SAVE OUTPUT FD IN THE STACK


################################################################

# SSIZE_T READ(INT FD, VOID *BUF, SIZE_T COUNT);
# SSIZE_T WRITE(INT FD, CONST VOID *BUF, SIZE_T COUNT);

READ_LOOP_BEGIN:
	MOVQ $SYS_READ, %RAX
	MOVQ ST_FD_IN(%RBP), %RDI	# READ FROM THIS FD
	MOVQ $BUFFER_DATA, %RSI		# COPY BUFFER'S ADDRESS TO %RSI, SO
					# READ() KNOWS WHERE TO PUT DATA READ

	MOVQ $BUFFER_SIZE, %RDX		# SET BUFFER SIZE FOR READ()
	SYSCALL				# INVOKE KERNEL

	# NUMBER OF BYTES READ SHOULD BE IN %EAX

	# LEAVE LOOP IF WE ARE AT EOF
	CMPQ $END_OF_FILE, %RAX
	JLE END_LOOP

CONTINUE_READ_LOOP:
	# CALL CONVERT FUNCTION FOR THE CURRENT BUFFER
	PUSHQ $BUFFER_DATA	# BUFFER LOCATION - 2ND ARGUMENT
	PUSHQ %RAX		# BUFFER SIZE - 1ST ARGUMENT
				# (RETURNED FROM READ() SYSCALL)

	CALL CONVERT_TO_UPPER
	POPQ %RAX		# GET SIZE BACK
	ADDQ $8, %RSP		# CLEANUP STACK USED FOR BUFFER_DATA LOCATION

WRITE_FILE:
	MOVQ %RAX, %RDX			# USE NUMBER OF BYTES READ TO WRITE TO
					# OUTPUT FILE
	MOVQ $SYS_WRITE, %RAX
	MOVQ ST_FD_OUT(%RBP), %RDI	# WRITE TO THIS FD
	MOVQ $BUFFER_DATA, %RSI		# THIS BUFFER
	SYSCALL				# INVOKE KERNEL

	JMP READ_LOOP_BEGIN # KEEP READING THE FILE

END_LOOP:
	MOVQ $SYS_CLOSE, %RAX
	MOVQ ST_FD_OUT(%RBP), %RDI
	SYSCALL

	MOVQ $SYS_CLOSE, %RAX
	MOVQ ST_FD_IN(%RBP), %RDI
	SYSCALL

	MOVQ $SYS_EXIT, %RAX
	MOVQ $0, %RDI
	SYSCALL


# CONVERT_TO_UPPER:
#
# CONVERT ALL ASCII CHARACTERS IN $BUFFER
# TO UPPERCASE
#
# - 1ST ARGUMENT: BUFFER SIZE
# - 2ND ARGUMENT: BUFFER ADDRESS
#
# REMEMBER: ARGUMENTS MUST BE PUSHED IN THE REVERSE ORDER AS THEY ARE DOCUMENTED
#
#	- %EAX - BEGINNING OF BUFFER
#	- %RDI - BUFFER LENGTH
#	- %RSI - CURRENT BUFFER OFFSET
#	- %CL  - BYTE BEING EXAMINED (LOWER BYTE OF %RCX)

## CONSTANTS
.EQU LOWERCASE_A, 'A' # LOWER BUNDARY
.EQU LOWERCASE_Z, 'Z' # UPPER BOUNDARY

# CONVERSION
.EQU UPPER_CONVERSION, 'A' - 'A'

## STACK STUFF
.EQU ST_BUFFER_LEN, 16	# BUFFER LENGTH
.EQU ST_BUFFER, 24	# ACTUAL BUFFER


.TYPE CONVERT_TO_UPPER, @FUNCTION

CONVERT_TO_UPPER:
	PUSHQ %RBP	# SETUP FUNCTION'S STACK FRAME. SAVE CURRENT %EBP
	MOVQ %RSP, %RBP # AND SET IT TO CURRENT STACK POINTER

	MOVQ ST_BUFFER(%RBP), %RAX
	MOVQ ST_BUFFER_LEN(%RBP), %RDI
	MOVQ $0, %RSI

	# IF A ZERO LENGTH BUFFER WAS GIVEN, JUST LEAVE
	CMPQ $0, %RAX
	JE END_CONVERT_LOOP

CONVERT_LOOP:
	MOVB (%RAX, %RSI, 1), %CL	# GET CURRENT BYTE

	# CHECK IF CURRENT BYTE IS ALREADY IN LOW CASE
	CMPB $LOWERCASE_A, %CL
	JL NEXT_BYTE
	CMPB $LOWERCASE_Z, %CL
	JG NEXT_BYTE

	# CONVERT IF WE ARE STILL HERE
	ADDB $UPPER_CONVERSION, %CL
	MOVB %CL, (%RAX, %RSI, 1) # REPLACE OLD VALUE WITH THE NEW ONE

NEXT_BYTE:
	INCQ %RSI
	CMPQ %RSI, %RDI		# CONTINUE CONVERSION UNLESS WE REACHED
	JNE CONVERT_LOOP	# THE END OF THE BUFFER

END_CONVERT_LOOP:
	# NO RETURN VALUE, JUST RESTORE STACK POINTER
	# AND BASE POINTER AND RETURN.
	MOVQ %RBP, %RSP
	POPQ %RBP
	RET