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
|
; Version : 1.00
; Updated : 20/8/2021
; Licence : GPLv3
; Set the case of ASCII text to upper or lower case.
default rel ; we always want this.
extern printf
%define argv0 r12
%define upper r13 ;make r13 the boolean
%define scratch r14
%define file r15
section .rodata
Usage db `%s OPTION [filename]\n Option Description\n-u Make characters uppercase.\n-l Make characters lowercase.\n`,0
OpenError: db `Could not open: %s\n`,0
section .text
global main
usage:
push rbx ;align the stack if not already done
mov rsi, [argv0] ;get argv[0]
lea rdi, [rel Usage] ;copy the usage to rdi
xor eax,eax ;al == 0 means no FP args in XMM registers
call printf wrt ..plt ;call printf with `wrt ..plt` so dynamic linking works
pop rbx ;pop rbx off the stack
mov eax, 1 ;exit with value 1
ret
stdin:
xor edi, edi ; file descriptor = stdin = 0
lea rsi, [scratch] ; buffer = address to store the bytes read
mov edx, 1 ; number of bytes to read
xor eax, eax ; syscall for read == 0
syscall
test eax, eax ; If syscall returns 0 in rax, the character is EOF
je exit ; if char is EOF: exit
call process_char
jmp stdin
process_char:
test upper,upper
jz lower ;jump to lower if upper is false
;fall through if uppercase
cmp byte[scratch],'a' ;check if read char is below 'a'
jl skip_modification ;if below 'a', it's not a lowercase char
cmp byte[scratch],'z' ;check if read char is equal to or below z
ja skip_modification ;if not equal or above, it's not a lowercase char
sub byte[scratch], 32 ;subtract 32 from ASCII char to capitalise it
jmp skip_modification ;skip lowercase
lower:
cmp byte[scratch],'A' ;check if read char is below 'A'
jl skip_modification ;if below 'A', it's not a uppercase char
cmp byte[scratch],'Z' ;check if read char is equal to or below 'Z'
ja skip_modification ;if not equal or above, it's not a lowercase char
add byte[scratch], 32 ;add 32 to ASCII char to make it lowercase
skip_modification:
mov edi, 1 ; file descriptor = stdout
lea rsi, [scratch] ; buffer = address to write to console
mov edx, 1 ; number of bytes to write
mov eax, 1 ; SYSCALL number for writing to STDOUT
syscall ; make the syscall
ret ; read the next char
file_error:
push rbx ;align the stack if not already done
mov rsi, scratch ;get argv[2]
lea rdi, [rel OpenError];copy the filename to rdi
xor eax,eax ;al == 0 means no FP args in XMM registers
call printf wrt ..plt ;call printf with `wrt ..plt` so dynamic linking works
pop rbx ;pop rbx off the stack
mov eax, 1 ;exit with value 1
ret
open_file:
add rsi, 8 ;get pointer-to-pointer to argv[2]
mov scratch,[rsi] ;get pointer to argv[2] and copy it to scratch
mov eax, 2 ;syscall sys_open
mov rdi, scratch ;place pointer to filename string in rdi
xor esi, esi ;O_RDONLY
xor edx, edx ;don't need a mode
syscall
test eax, eax
js file_error ;if nonzero, sys_open failed
mov file, rax ;store fp in file
read_file:
mov rdi, file ;file descriptor = rax from sys_open above
lea rsi, [scratch] ;read into scratch
mov edx, 1 ;number of bytes to read
xor eax, eax ;syscall for read == 0
syscall
test eax, eax ;If syscall returns 0 in rax, the character is EOF
je close_file ;if char is EOF, close the file and exit
call process_char
jmp read_file
main:
mov argv0, rsi ;save argv[0] for later
cmp edi, 2
jl usage ;show usage if not enough args are provided
check_args:
add rsi, 8 ;get pointer-to-pointer to argv[1]
mov scratch, [rsi] ;get pointer to argv[1] and copy it to scratch
cmp byte[scratch], '-'
jne usage ;show usage if there is no argument (missing -)
xor upper, upper ;assume lowercase by default
cmp byte[scratch+1], 'u'
jne false ;fall through if argv[1][1] == 'u' and thus set upper boolean to true
mov upper,1
false:
cmp edi, 3
jl stdin ;go to stdin mode if no filename is provided
jg usage ;go to usage if more that 3 args are provided
jmp open_file ;jump to file opening
close_file:
mov rdi, file ;fp to close
mov eax, 3 ;sys_close
syscall
exit:
xor eax, eax
ret
|