Repository navigation
Expand file tree
/
Copy pathdot_product.asm
More file actions
338 lines (301 loc) · 13.7 KB
/
Copy pathdot_product.asm
File metadata and controls
338 lines (301 loc) · 13.7 KB
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
;; Definition of the .data section
section .data
;; Number of the `sys_read` system call.
SYS_READ equ 0
;; Number of the `sys_write` system call.
SYS_WRITE equ 1
;; Number of the `sys_exit` system call.
SYS_EXIT equ 60
;; Number of the standard input file descriptor.
STD_IN equ 0
;; Number of the standard output file descriptor.
STD_OUT equ 1
;; Exit code from the program. The 0 status code is a success.
EXIT_CODE equ 0
;; Maximum number of elements in a vector
MAX_ELEMS equ 100
;; Buffer size that we will use to read vectors.
BUFFER_SIZE equ 1024
;; Prompt for the first vector
FIRST_INPUT_MSG: db "Input the first vector: "
;; Length of the prompt for the first vector
FIRST_INPUT_MSG_LEN equ 24
;; Prompt for the second vector
SECOND_INPUT_MSG: db "Input the second vector: "
;; Length of the prompt for the second vector
SECOND_INPUT_MSG_LEN equ 25
;; Error message to print if the number of items in the vectors is not the same.
;; `10` is the ASCII code of the new line symbol. `0` is the NUL terminator.
ERROR_MSG: db "Error: the number of values in vectors should be the same", 10, 0
;; Length of the error message.
ERROR_MSG_LEN equ 59
;; Error messge to print if the given vectors are empty.
;; `10` is the ASCII code of the new line symbol. `0` is the NUL terminator.
ERROR_EMPTY_MSG: db "Error: the vectors are empty", 10, 0
;; Length of the error message.
ERROR_EMPTY_MSG_LEN equ 30
;; Format string for the result
PRINTF_FORMAT: db "Dot product = %f", 0xA, 0
;; Definition of the .bss section
section .bss
;; Buffer to store double values of the first vector
vector_1: resq MAX_ELEMS
;; Buffer to store double values of the second vector
vector_2: resq MAX_ELEMS
;; Buffer to store input for the first vector
buffer_1: resq BUFFER_SIZE
;; Pointer within the `buffer_1` which points to the current position
;; that we use to parse floating point numbers
end_buffer_1: resq 1
;; Buffer to store input for the second vector
buffer_2: resq BUFFER_SIZE
;; Pointer within the `buffer_2` which points to the current position
;; that we use to parse floating point numbers
end_buffer_2: resq 1
;; Definition of the .text section
section .text
;; Reference to the C stdlib functions that we will use
extern strtod, printf
;; Reference to the entry point of our program.
global _start
;; Entry point of the program.
_start:
;; Align stack to 16-byte boundary at start.
;; Mask off lower 4 bits to force alignment.
and rsp, -16
;; Jump to the _read_first_float_vector label
jmp _read_first_float_vector
;; Read the first input string with floating-point values
_read_first_float_vector:
;; Set the length the of the prompt string to print.
mov rdx, FIRST_INPUT_MSG_LEN
;; Specify the system call number (1 is `sys_write`).
mov rax, SYS_WRITE
;; Set the first argument of `sys_write` to 1 (`stdout`).
mov rdi, STD_OUT
;; Set the second argument of `sys_write` to the reference of the prompt string to print.
mov rsi, FIRST_INPUT_MSG
;; Call the `sys_write` system call.
syscall
;; Set the length of the string we want to read from the standard input.
mov rdx, BUFFER_SIZE
;; Specify the system call number (0 is `sys_read`)
mov rax, SYS_READ
;; Set the first argument of `sys_read` to 0 (`stdin`)
mov rdi, STD_IN
;; Set the second argument of `sys_read` to the reference of the buffer where we will
;; read the data for the vector.
mov rsi, buffer_1
;; Call the `sys_read` system call.
syscall
;; Save the number of bytes we have read from the standard input in the rcx register.
mov rcx, rax
;; Set the pointer to the beginning of the buffer with the input data to the rdx register.
mov rdx, buffer_1
;; Move the pointer within the buffer to the end of input.
add rdx, rcx
;; Fill the last byte of the input with 0.
mov byte [rdx], 0
;; Reset the value of the r14 register to store the number of floating-point numbers
;; from the first vector.
xor r14, r14
;; Set the pointer to the beginning of the buffer with the input data to the rdi register.
mov rdi, buffer_1
;; Parse the floating-point values from the input buffer.
_parse_first_float_vector:
;; Initialize the rsi register with the pointer to the place where
;; the strtod(3) will finish its work.
mov rsi, end_buffer_1
;; Preserve the pointer to the current floating-point value in the r12 register,
;; because the strtod(3) may change it.
mov r12, rdi
;; Call the strtod(3) to convert a floating-point value from the input buffer to double representation.
call strtod
;; Preserve the pointer to the next floating-point value from the input buffer
;; in the rax register.
mov rax, [rel end_buffer_1]
;; Check whether it is the end of the input string.
cmp rax, r12
;; Proceed with the second vector if we reached the end of the first vector.
je _read_second_float_vector
;; Store the reference to the beginning of the buffer where we will store
;; our double values to the rdx register.
mov rdx, vector_1
;; Store the number of floating-point values we already have read in the rcx register.
mov rcx, r14
;; Multiply the number of floating-point values by 8.
shl rcx, 3
;; Move the pointer from the beginning of the buffer with floating-point values that
;; we parsed from the input string to the next value.
add rdx, rcx
;; Store the next floating-point value in the buffer.
movq [rdx], xmm0
;; Increase the number of floating-point values that we already parsed.
inc r14
;; Move the pointer within the input buffer to the next floating-point value.
mov rdi, rax
;; Continue to parse floating-point values from the input string.
jmp _parse_first_float_vector
;; Read the second input string with floating-point values
_read_second_float_vector:
;; Set the length of the prompt string to print.
mov rdx, SECOND_INPUT_MSG_LEN
;; Specify the system call number (1 is `sys_write`).
mov rax, SYS_WRITE
;; Set the first argument of `sys_write` to 1 (`stdout`).
mov rdi, STD_OUT
;; Set the second argument of `sys_write` to the reference of the prompt string to print.
mov rsi, SECOND_INPUT_MSG
;; Call the `sys_write` system call.
syscall
;; Set the length of the string we want to read from the standard input.
mov rdx, BUFFER_SIZE
;; Specify the system call number (0 is `sys_read`).
mov rax, SYS_READ
;; Set the first argument of `sys_read` to 0 (`stdin`).
mov rdi, STD_IN
;; Set the second argument of `sys_read` to the reference of the buffer where we will
;; read the data for the vector.
mov rsi, buffer_2
;; Call the `sys_read` system call.
syscall
;; Save the number of bytes we have read from the standard input in the rcx register.
mov rcx, rax
;; Set the pointer to the beginning of the buffer with the input data to the rdx register.
mov rdx, buffer_2
;; Move the pointer within the buffer to the end of input.
add rdx, rcx
;; Fill the last byte of the input with 0.
mov byte [rdx], 0
;; Reset the value of the r15 register to store the number of floating-point numbers
;; from the second vector.
xor r15, r15
;; Set the pointer to the beginning of the buffer with the input data to the rdi register.
mov rdi, buffer_2
;; Parse the floating-point values from the input buffer.
_parse_second_float_vector:
;; Initialize the rsi register with the pointer which to the place where
;; the strtod(3) will finish its work.
mov rsi, end_buffer_2
;; Preserve the pointer to the current floating-point value in the r12 register,
;; because the strtod(3) may change it.
mov r12, rdi
;; Call the strtod(3)
call strtod
;; Preserve the pointer to the next floating-point value from the input buffer
;; in the rax register.
mov rax, [rel end_buffer_2]
;; Check whether it is the end of the input string.
cmp rax, r12
;; Calculate the dot product after we have both vectors.
je _calculate_dot_product
;; Store the reference to the beginning of the buffer where we will store
;; our double values to the rdx register.
mov rdx, vector_2
;; Store the number of floating-point values we already have read in the rcx register.
mov rcx, r15
;; Multiply the number of floating-point values by 8.
shl rcx, 3
;; Move the pointer from the beginning of the buffer with floating-point values that
;; we have parsed from the input string to the next value.
add rdx, rcx
;; Store the next floating-point value in the buffer.
movq [rdx], xmm0
;; Increase the number of floating-point value that we already have parsed.
inc r15
;; Move the pointer within the input buffer to the next floating-point value.
mov rdi, rax
;; Continue to parse floating-point values from the input string.
jmp _parse_second_float_vector
;; Prepare to calculate the dot product of the two vectors.
_calculate_dot_product:
;; Check if the number of items in our vectors is equal.
cmp r14, r15
;; Print an error and exit if not.
jne _error
;; Check if vectors are empty.
test r14, r14
;; Print an error and exit if so.
jz _error_empty
;; Set the address of the first vector to the rdi register.
mov rdi, vector_1
;; Set the address of the second vector to the rsi register.
mov rsi, vector_2
;; Set the number of values within the vectors to the rdx register.
mov rdx, r14
;; Calculate the dot product of the two vectors.
call _dot_product
;; Specify a reference to the format string for the printf(3) in the rdi register.
mov rdi, PRINTF_FORMAT
;; Number of the floating-point registers passed to printf(3).
;; We specify `1` because we need to pass only `xmm0` with the result of the program.
mov rax, 1
;; Call the printf(3) function that will print the result.
call printf
;; Exit from the program.
jmp _exit
;; Calculate the dot product of the two vectors.
_dot_product:
;; Reset the value of the rax register to 0.
xor rax, rax
;; Reset the value of the xmm1 register to 0.
pxor xmm1, xmm1
;; Current rdx contains the number of floating-point values within the vectors.
;; Multiply it by 8 using shift left operation to get the number of bytes
;; occupied by these values.
sal rdx, 3
;; Calculate the the dot product in the loop.
_loop:
;; Move the floating-point value from the first vector to the xmm0 register.
movsd xmm0, [rdi + rax]
;; Multiply the floating-point value from the second vector by the value from the first vector
;; and store the result in the xmm0 register.
mulsd xmm0, [rsi + rax]
;; Move to the next floating-point values in the vector buffers.
add rax, 8
;; Add the result of multiplying the floating-point values from the two vectors into the xmm1 register.
addsd xmm1, xmm0
;; Check if we went through all the floating-point values in the vector buffers.
cmp rax, rdx
;; If not, repeat the loop.
jne _loop
;; Move the result to the xmm0 register.
movapd xmm0, xmm1
;; Return from the `_dot_product` back to the `_calculate_dot_product`.
ret
;; Print an error and exit.
_error:
;; Set the length of the prompt string to print.
mov rdx, ERROR_MSG_LEN
;; Specify the system call number (1 is `sys_write`).
mov rax, SYS_WRITE
;; Set the first argument of `sys_write` to 1 (`stdout`).
mov rdi, STD_OUT
;; Set the second argument of `sys_write` to the reference of the prompt string to print.
mov rsi, ERROR_MSG
;; Call the `sys_write` system call.
syscall
;; Exit from the program
jmp _exit
;; Print an error and exit.
_error_empty:
;; Set the length of the prompt string to print.
mov rdx, ERROR_EMPTY_MSG_LEN
;; Specify the system call number (1 is `sys_write`).
mov rax, SYS_WRITE
;; Set the first argument of `sys_write` to 1 (`stdout`).
mov rdi, STD_OUT
;; Set the second argument of `sys_write` to the reference of the prompt string to print.
mov rsi, ERROR_EMPTY_MSG
;; Call the `sys_write` system call.
syscall
;; Exit from the program
jmp _exit
;; Exit from the program.
_exit:
;; Specify the number of the system call (60 is `sys_exit`).
mov rax, SYS_EXIT
;; Set the first argument of `sys_exit` to 0. The 0 status code is success.
mov rdi, EXIT_CODE
;; Call the `sys_exit` system call.
syscall