-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalcasm.s
234 lines (193 loc) · 5.66 KB
/
calcasm.s
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
.section .data
.include "linux.s"
.include "ascii.s"
.include "logic.s"
.equ ST_ARGC, 0
.equ ST_ARGV_0, 8
.equ ST_ARGV_1, 16
.equ ST_ARGV_2, 24
.equ ST_ARGV_3, 32
.equ ARG_NUM, 4
ArgNumError:
.string "usage ./calcasm <number> <operator> <number>"
NotNumError:
.string "One or more inputs is not a number"
OperatorError:
.string "Invalid operator supplied"
ZeroDivError:
.string "Zero division error"
AddOp:
.string "add"
SubOp:
.string "sub"
MulOp:
.string "mul"
DivOp:
.string "div"
ModOp:
.string "mod"
PowOp:
.string "pow"
.equ ALT_OP_LEN, 3
.section .bss
.section .text
# Command line arguments
#
# (%rsp) = argc
# 8(%rsp) = argv[0] = name of application
# 16(%rsp) = argv[1] = first user-passed argument
# 24(%rsp) = argv[2] = second user-passed argument
# 32(%rsp) = argv[3] = third user-passed argument
# ...and so on
#
# Sequence of pops will place first the argc value
# and then the addresses of each argument into register
#
.globl _start
_start:
movq %rsp, %rbp # save stack pointer
movq ST_ARGC(%rbp), %rax
cmpq $ARG_NUM, %rax
jne exit_arg_error
get_first_number:
movq ST_ARGV_1(%rbp), %rdi # load string address into register
call str_len # get length of string
movq %rax, %rsi # load length into register
call is_number # check if string is a number
cmpq $FALSE, %rax
je exit_num_error # exit with error if not number
call convert_to_int # convert string to integer
movq %rax, %r11 # store integer for operation
get_second_number:
movq ST_ARGV_3(%rbp), %rdi # load string address into register
call str_len # get length of string
movq %rax, %rsi # load length into register
call is_number # check if string is a number
cmpq $FALSE, %rax
je exit_num_error # exit with error if not number
call convert_to_int # convert string to integer
movq %rax, %r12 # store integer for operation
get_operator:
movq ST_ARGV_2(%rbp), %rbx # load operator
cmpb $ADD_OPERATOR, (%rbx) # check against operator characters
je add_operation
cmpb $SUB_OPERATOR, (%rbx)
je sub_operation
cmpb $MUL_OPERATOR, (%rbx)
je mul_operation
cmpb $DIV_OPERATOR, (%rbx)
je get_quotient
cmpb $MOD_OPERATOR, (%rbx)
je get_remainder
cmpb $POW_OPERATOR, (%rbx)
je pow_operation
movq %rbx, %rdi # check length of entered operator
call str_len
cmpq $ALT_OP_LEN, %rax
jne exit_operator_error
movq $ALT_OP_LEN, %rdx # load alt operator length
movq %rbx, %rsi # load entered operator
movq $AddOp, %rdi # check against each alt operators
call string_elements_match
cmpq $TRUE, %rax
je add_operation
movq $SubOp, %rdi
call string_elements_match
cmpq $TRUE, %rax
je sub_operation
movq $MulOp, %rdi
call string_elements_match
cmpq $TRUE, %rax
je mul_operation
movq $DivOp, %rdi
call string_elements_match
cmpq $TRUE, %rax
je get_quotient
movq $ModOp, %rdi
call string_elements_match
cmpq $TRUE, %rax
je get_remainder
movq $PowOp, %rdi
call string_elements_match
cmpq $TRUE, %rax
je pow_operation
jmp exit_operator_error
get_quotient:
movq $FALSE, %r13
jmp div_operation
get_remainder:
movq $TRUE, %r13
jmp div_operation
add_operation:
addq %r12, %r11
movq %r11, %rdi
jmp print_result
sub_operation:
subq %r12, %r11
movq %r11, %rdi
jmp print_result
mul_operation:
movq %r11, %rax
mul %r12
movq %rax, %rdi
jmp print_result
# for signed integer division see:
# https://stackoverflow.com/a/10348927/5671759
# http://www.c-jump.com/CIS77/MLabs/M11arithmetic/M11_0120_idiv_instruction.htm
div_operation:
cmpq $0, %r12
je exit_zero_div_error
movq %r11, %rax # dividend in %rax
cqto # sign-extend %rax into %rdx (rdx:rax)
movq %r12, %rbx # divisor in %rbx
idivq %rbx # divide preserving sign
cmpq $TRUE, %r13
je remainder
jmp quotient
remainder:
movq %rdx, %rdi
jmp print_result
quotient:
movq %rax, %rdi
jmp print_result
pow_operation:
movq %r11, %rdi
movq %r12, %rsi
call base_to_power
movq %rax, %rdi
jmp print_result
print_result:
call write_int
call write_newline
exit:
movq $SYS_EXIT, %rax
movq $EXIT_SUCCESS, %rdx
syscall
exit_arg_error:
movq $ArgNumError, %rdi
movq $44, %rsi
call write_error_msg
call write_newline
jmp error_exit
exit_num_error:
movq $NotNumError, %rdi
movq $34, %rsi
call write_error_msg
call write_newline
jmp error_exit
exit_operator_error:
movq $OperatorError, %rdi
movq $25, %rsi
call write_error_msg
call write_newline
jmp error_exit
exit_zero_div_error:
movq $ZeroDivError, %rdi
movq $20, %rsi
call write_error_msg
call write_newline
jmp error_exit
error_exit:
movq $SYS_EXIT, %rax
movq $EXIT_FAILURE, %rdx
syscall