Skip to content
Open

Asm #31

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
375 changes: 375 additions & 0 deletions asm/mul.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,375 @@
section .text

global _start
_start:

sub rsp, 2 * 128 * 8
lea rdi, [rsp + 128 * 8]
mov rcx, 128
call read_long
mov rdi, rsp
call read_long
lea rsi, [rsp + 128 * 8]



sub rsp, 2 * 128 * 8 ; выделяем место под ответ
mov r10, rsp

push rdi
mov rcx, 256
mov rdi, r10
call set_zero ; нужно занулить место под ответ
mov rcx, 128
pop rdi

call mul_long_long


mov rcx, 256 ; подготовим регистры и выведем ответ
mov rdi, r10
call write_long

mov al, 0x0a
call write_char

jmp exit

; multiplies two long number
; rdi -- address of term #1 (long number)
; rsi -- address of term #2 (long number)
; rcx -- length of long numbers in qwords
; result:
; result is written to r10
mul_long_long:
push rdi
push rsi
push rcx

push rax
push rbx
push rbp
push r8
push r9

; далее просто перебираем разряды обоих чисел, умножаем и прибавляем к результату

xor r8, r8
loop_outer:


xor r9, r9
loop_inner:

;
; [r10 + 8 * (r8 + r9)] += [rdi + 8 * r8] * [rsi + 8 * r9] грубо говоря
;

lea rax, [rdi + 8 * r8]
mov rax, [rax] ; грубо превратили индекс в значение, ну да ладно
lea rbx, [rsi + 8 * r9]
mov rbx, [rbx]


; high:low
mul rbx ; rdx:rax = rax * rbx

mov rbp, r8
add rbp, r9 ; rbp = r8 + r9
lea rbp, [r10 + 8 * rbp] ; rbp - индекс, куда надо прибавлять


add [rbp], rax ; прибавляем и ставим CF
lea rbp, [rbp + 8]
adc [rbp], rdx ; снова керри флаг
while_carry:
jnc end_of_while ; если CF = 0 то конец
lea rbp, [rbp + 8]
adc QWORD [rbp], 0
jmp while_carry
end_of_while:


inc r9
cmp rcx, r9
ja loop_inner


inc r8
cmp rcx, r8
ja loop_outer


pop r9
pop r8
pop rbp
pop rbx
pop rax

pop rcx
pop rsi
pop rdi
ret

; adds 64-bit number to long number
; rdi -- address of summand #1 (long number)
; rax -- summand #2 (64-bit unsigned)
; rcx -- length of long number in qwords
; result:
; sum is written to rdi
add_long_short:
push rdi
push rcx
push rdx

xor rdx,rdx
.loop:
add [rdi], rax
adc rdx, 0
mov rax, rdx
xor rdx, rdx
add rdi, 8
dec rcx
jnz .loop

pop rdx
pop rcx
pop rdi
ret

; multiplies long number by a short
; rdi -- address of multiplier #1 (long number)
; rbx -- multiplier #2 (64-bit unsigned)
; rcx -- length of long number in qwords
; result:
; product is written to rdi
mul_long_short:
push rax
push rdi
push rcx

xor rsi, rsi
.loop:
mov rax, [rdi]
mul rbx
add rax, rsi
adc rdx, 0
mov [rdi], rax
add rdi, 8
mov rsi, rdx
dec rcx
jnz .loop

pop rcx
pop rdi
pop rax
ret

; divides long number by a short
; rdi -- address of dividend (long number)
; rbx -- divisor (64-bit unsigned)
; rcx -- length of long number in qwords
; result:
; quotient is written to rdi
; rdx -- remainder
div_long_short:
push rdi
push rax
push rcx

lea rdi, [rdi + 8 * rcx - 8]
xor rdx, rdx

.loop:
mov rax, [rdi]
div rbx
mov [rdi], rax
sub rdi, 8
dec rcx
jnz .loop

pop rcx
pop rax
pop rdi
ret

; assigns a zero to long number
; rdi -- argument (long number)
; rcx -- length of long number in qwords
set_zero:
push rax
push rdi
push rcx

xor rax, rax
rep stosq

pop rcx
pop rdi
pop rax
ret

; checks if a long number is a zero
; rdi -- argument (long number)
; rcx -- length of long number in qwords
; result:
; ZF=1 if zero
is_zero:
push rax
push rdi
push rcx

xor rax, rax
rep scasq

pop rcx
pop rdi
pop rax
ret

; read long number from stdin
; rdi -- location for output (long number)
; rcx -- length of long number in qwords
read_long:
push rcx
push rdi

call set_zero
.loop:
call read_char
or rax, rax
js exit
cmp rax, 0x0a
je .done
cmp rax, '0'
jb .invalid_char
cmp rax, '9'
ja .invalid_char

sub rax, '0'
mov rbx, 10
call mul_long_short
call add_long_short
jmp .loop

.done:
pop rdi
pop rcx
ret

.invalid_char:
mov rsi, invalid_char_msg
mov rdx, invalid_char_msg_size
call print_string
call write_char
mov al, 0x0a
call write_char

.skip_loop:
call read_char
or rax, rax
js exit
cmp rax, 0x0a
je exit
jmp .skip_loop

; write long number to stdout
; rdi -- argument (long number)
; rcx -- length of long number in qwords
write_long:
push rax
push rcx

mov rax, 20
mul rcx
mov rbp, rsp
sub rsp, rax

mov rsi, rbp

.loop:
mov rbx, 10
call div_long_short
add rdx, '0'
dec rsi
mov [rsi], dl
call is_zero
jnz .loop

mov rdx, rbp
sub rdx, rsi
call print_string

mov rsp, rbp
pop rcx
pop rax
ret

; read one char from stdin
; result:
; rax == -1 if error occurs
; rax \in [0; 255] if OK
read_char:
push rcx
push rdi

sub rsp, 1
xor rax, rax
xor rdi, rdi
mov rsi, rsp
mov rdx, 1
syscall

cmp rax, 1
jne .error
xor rax, rax
mov al, [rsp]
add rsp, 1

pop rdi
pop rcx
ret
.error:
mov rax, -1
add rsp, 1
pop rdi
pop rcx
ret

; write one char to stdout, errors are ignored
; al -- char
write_char:
sub rsp, 1
mov [rsp], al

mov rax, 1
mov rdi, 1
mov rsi, rsp
mov rdx, 1
syscall
add rsp, 1
ret

exit:
mov rax, 60
xor rdi, rdi
syscall

; print string to stdout
; rsi -- string
; rdx -- size
print_string:
push rax

mov rax, 1
mov rdi, 1
syscall

pop rax
ret


section .rodata
invalid_char_msg:
db "Invalid character: "
invalid_char_msg_size: equ $ - invalid_char_msg
Loading