Created
January 17, 2016 17:09
-
-
Save maxkarelov/392b152b00d7453ea403 to your computer and use it in GitHub Desktop.
masm task6, mdlp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; ВАРИАНТ №252 | |
; F = 0x2569 + (0x12 + x - y) | |
; Макрос выделяет место в стеке под 4 обязательных | |
; аргумента функций, а также, если необходимо, | |
; под дополнительные | |
STACKALLOC macro argc | |
; Запоминаем указатель на изначальный стек | |
push r15 | |
mov r15, rsp | |
; Стек должен быть выровнен по адресу, | |
; кратному 16, обнуляем последние 4 бита | |
and spl, 0F0h | |
; Выделяем место под обязательные аргументы | |
sub rsp, 8 * 4 | |
; Если нужно, выделяем место под | |
; дополнительные аргументы | |
if argc | |
sub rsp, 8 * argc | |
endif | |
endm | |
; Макрос восстанавливает стек | |
; после работы STACKALLOC | |
STACKFREE macro | |
mov rsp, r15 | |
pop r15 | |
endm | |
; Макрос, используемый для обнуления пятого | |
; аргумента некоторых процедур | |
NULL_FIFTH_ARG macro | |
mov qword ptr[rsp+20h], 0h | |
endm | |
; Подключение WinAPI | |
extrn ExitProcess: proc | |
extrn GetStdHandle: proc | |
extrn ReadConsoleA: proc, WriteConsoleA: proc | |
extrn lstrlenA: proc | |
; Номер стандартного потока вывода | |
STD_OUTPUT_HANDLE equ -11 | |
; Номер стандартного потока ввода | |
STD_INPUT_HANDLE equ -10 | |
.data? | |
; Данные переменные будут хранить | |
; указатели на дескрипторы ввода/вывода | |
hStdInput dq ? | |
hStdOutput dq ? | |
.data | |
enterNums db "Enter X and Y: ", 0Ah, 0h | |
answer db "Calculating", 0Ah, "0x2569 + (0x12 + X - Y)", 0Ah, 0h | |
goodbye db 0Ah, "Press any key to exit...", 0h | |
; Значения определяются выданным вариантом | |
a dq 2569h | |
b dq 12h | |
.code | |
; Процедура, которая ждет ввода перед выходом из программы | |
WaitInput proc uses rcx rdx r8 r9 | |
; Локальные переменные, используемые в качестве | |
; "заглушек" при вызове ReadConsoleA | |
local bytesRead: dword | |
local readStr: dword | |
; Выводим пользователю строку | |
lea rcx, goodbye | |
call PrintString | |
STACKALLOC 1 | |
; Перечисляем аргументы ReadConsoleA | |
mov rcx, hStdInput | |
lea rdx, readStr | |
mov r8, 1 | |
lea r9, bytesRead | |
NULL_FIFTH_ARG | |
call ReadConsoleA | |
STACKFREE | |
ret | |
WaitInput ENDP | |
; Процедура печатает строку в поток вывода | |
; аргументы: RCX - указатель на строку | |
PrintString proc uses rcx rdx r8 r9 | |
; Сохраним указатель на строку в переменной | |
local lStr: qword | |
mov lStr, rcx | |
STACKALLOC 1 | |
; Получим длину выводимой строки | |
mov rcx, lStr | |
call lstrlenA | |
; Перечисление аргументов WriteConsoleA | |
mov rcx, hStdOutput | |
mov rdx, lStr | |
mov r8, rax | |
mov r9, qword ptr 0 | |
NULL_FIFTH_ARG | |
call WriteConsoleA | |
STACKFREE | |
ret 8 | |
PrintString endp | |
; Процедура считывает знаковое шестнадцатиричное | |
; число с потока ввода и помещает его в RAX | |
ReadNumber proc uses rcx rdx r8 r9 | |
; Число считанных байт | |
local bytesRead: dword | |
; Считанная строка | |
local readStr[32]: byte | |
; ReadConsole считывает с потока ввода строку, | |
; поэтому ее необходимо будет преобразовать в число | |
mov r10, 0h | |
STACKALLOC 2 | |
; Перечисление аргументов | |
mov rcx, hStdInput | |
lea rdx, readStr | |
mov r8, 32 | |
lea r9, bytesRead | |
NULL_FIFTH_ARG | |
call ReadConsoleA | |
; Строка содержит служенбные символы в конце, | |
; их необходимо удалить и терминировать строку нулем | |
xor rcx, rcx | |
mov ecx, bytesRead | |
sub rcx, 2 | |
mov byte ptr readStr[rcx], 0h | |
; R8 будет хранить степень 10h, умножая очередную | |
; цифру числа на которую, будем получать | |
; необходимый разряд числа | |
mov r8, 1h | |
; В R9 будет получено итоговое число | |
xor r9, r9 | |
; Конвертация строки в число | |
; В RCX лежит длина строки, будем анализировать | |
; симолы, начиная с последнего, постепенно | |
; уменьшая RCX | |
_convert_string_to_number: | |
; Пока не прошли всю строку | |
cmp rcx, 0 | |
; Так как не произошло перехода на отрицательную метку, | |
; переходим на положительную | |
je _positive | |
dec rcx | |
xor rax, rax | |
; Если символ - минус, то записанное число отрицательно, | |
; переход на соответствующую метку | |
cmp readStr[rcx], '-' | |
je _negative | |
; Очередной символ строки перенесем в AL | |
mov al, readStr[rcx] | |
; Преобразуем символ в AL в числовое представление | |
sub al, 30h | |
cmp al, 09h | |
jle _l2 | |
sub al, 07h | |
; Умножим очередную цифру на заготовленную степеь десятки, | |
; получая истинный разряд итогового числа | |
_l2:mul r8 | |
; Прибавляем полученную цифру к итоговому числу | |
add r9, rax | |
; Получаем слудующую степень десятки | |
mov rax, 10h | |
mul r8 | |
mov r8, rax | |
; Переход на следующую итерацию | |
jmp _convert_string_to_number | |
; Умножим полученное число на -1, | |
; а также перенесем его в RAX | |
_negative: | |
mov rax, r9 | |
mov r9, -1 | |
mul r9 | |
jmp _exit_ReadNumber | |
; Перенесем число в RAX | |
_positive: | |
mov rax, r9 | |
jmp _exit_ReadNumber | |
; Завершение работы процедуры | |
_exit_ReadNumber: | |
STACKFREE | |
ret 8 * 2 | |
ReadNumber endp | |
; Процедура, обратная предыдущей: | |
; печатает знаковое шестнадцатиричное число | |
; аргументы: RCX - печатаемое число | |
PrintNumber proc uses rax rbx rcx rdx r8 r9 | |
; Число необходимо преобразовать в строку | |
local numberStr[32]: byte | |
STACKALLOC 1 | |
; Число символов в получаемой строке | |
mov r8, 0 | |
; Если число меньше нуля, запишем в строку знак "минус", | |
; а также получим модуль числа | |
cmp rcx, 0 | |
jg _positive | |
mov numberStr[0], '-' | |
inc r8 | |
mov rax, rcx | |
mov rcx, -1 | |
mul rcx | |
; | |
_positive: | |
mov rbx, 10h | |
; В RCX будет число цифр числа | |
xor rcx, rcx | |
; Цикл, который поместит в стек символы цифр числа, начиная с последней | |
; Производится это простым делением числа из RAX на 10h, | |
; получая при этом в RAX частное от деления, | |
; а в RDX - остаток (являющийся единственной цифрой) | |
_push_printed_symbol: | |
cmp rax, 0 | |
je _collect_pushed_symbols | |
xor rdx, rdx | |
div rbx | |
; Преобразуем цифру в ее ASCII код | |
add rdx, 30h | |
cmp rdx, 39h | |
jle _l1 | |
add rdx, 07h | |
_l1:push rdx | |
inc rcx | |
; Переход на следующую итерацию | |
jmp _push_printed_symbol | |
; В данном цикле "соберем" полученные в стеке символы в строку | |
; В предыдущем цикле в RCX записывали число итераций, | |
; поэтому здесь можно использовать loop | |
_collect_pushed_symbols: | |
pop rdx | |
mov numberStr[r8], dl | |
inc r8 | |
loop _collect_pushed_symbols | |
; Завершим строку терминирующим нулем | |
mov numberStr[10], 0 | |
; Напечатаем строку с помощью уже реализованной процедуры | |
lea rcx, numberStr | |
call PrintString | |
; Завершение работы процедуры | |
STACKFREE | |
ret 8 | |
PrintNumber endp | |
; Основная программа | |
Main proc | |
; Поместим дескрипторы потоков ввода/вывода | |
; в соответствующие переменные для удобства | |
mov rcx, STD_OUTPUT_HANDLE | |
call GetStdHandle | |
mov hStdOutput, rax | |
mov rcx, STD_INPUT_HANDLE | |
call GetStdHandle | |
mov hStdInput, rax | |
; Выведем строки приветствия | |
lea rcx, answer | |
call PrintString | |
lea rcx, enterNums | |
call PrintString | |
; Считаем Х и поместим его в r8 регистр | |
call ReadNumber | |
mov rcx, rax | |
mov r8, rax | |
; Считаем Y и поместим его в r9 регистр | |
call ReadNumber | |
mov r9, rax | |
; Далее можно посчитать число по необходимой формуле | |
xor rax, rax | |
add rax, a | |
add rax, b | |
add rax, r8 | |
sub rax, r9 | |
; Выведем полученное значение | |
mov rcx, rax | |
call PrintNumber | |
; Завершение работы программы | |
call WaitInput | |
call ExitProcess | |
Main endp | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment