Skip to content

Instantly share code, notes, and snippets.

@maxkarelov
Created January 17, 2016 17:09
Show Gist options
  • Save maxkarelov/392b152b00d7453ea403 to your computer and use it in GitHub Desktop.
Save maxkarelov/392b152b00d7453ea403 to your computer and use it in GitHub Desktop.
masm task6, mdlp
; ВАРИАНТ №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