Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- .386
- .MODEL FLAT, STDCALL
- ;#region Прототипы внешних функций
- ; Внешние функции описываются директивой EXTERN,
- ; после знака @ указывается общая длина передаваемых параметров,
- ; после двоеточия указывается тип внешнего объекта – процедура
- EXTERN GetStdHandle@4: PROC ; Позволяет получить дискрипторы ввода и вывода
- EXTERN WriteConsoleA@20: PROC
- EXTERN CharToOemA@8: PROC
- EXTERN ReadConsoleA@20: PROC
- EXTERN ExitProcess@4: PROC; функция выхода из программы
- EXTERN lstrlenA@4: PROC; функция определения длины строки
- EXTERN wsprintfA: PROC; т.к. число параметров функции не фиксировано,
- ; используется соглашение, согласно которому очищает стек вызывающая процедура
- ;#endregion Прототипы внешних функций
- .DATA ; сегмент данных
- ;#region Данные
- ; выводимая строка, в конце добавлены
- ; управляющие символы: 13 – возврат каретки, 10 – переход на новую
- ; строку, 0 – конец строки; с использованием директивы DB
- ; резервируется массив байтов
- WRITE_VALUE DB "Введите число в 16-ти ричной системе: ",13,10,0
- WRITE_LENGTH DD ? ; Длина строки
- ; Деректитва DD резервирует память объемом 32 бита (4 байта)
- ; знак «?» используется для неинициализированных данных
- FIRST_STRING DB 50 dup (?); Первое число в строковм виде
- FIRST_LENGTH DD ? ; Длина первого числа
- FIRST_INT DD 0 ; Значение hex строки в dec
- SECOND_STRING DB 50 dup (?); Второе число
- SECOND_LENGTH DD ? ; Длина второго числа
- SECOND_INT DD 0 ; Значение hex строки в dec
- RESULT_INT DD ? ; Результат (dec строка)
- LENS DD ? ; Буффер для длины строки (для ввода/вывода)
- D_IN DD ? ; Дескриптор ввода
- D_OUT DD ?; Дескриптор вывода
- ;#endregion Данные
- BUFF DB 50 dup (?)
- .CODE; сегмент кода
- ;---------------------------------------------------
- ; Преобразование QWORD в десятичное число
- ; Параметры вызова:
- ; dwHigh - Старшее двойное слово
- ; dwLow - Младшее двойное слово
- ; lpBuff - указатель на буфер-приемник
- ;---------------------------------------------------
- bignum PROC
- pushad ; Сохранить все регистры
- mov edi, OFFSET BUFF ; Указатель на буфер-приемник
- xchg esi,edx ; Сохранить старший dword
- mov ebx,10 ; Основание системы счисления
- xor ecx,ecx ; Счетчик десятичных цифр
- @bignum_1:
- xchg eax,esi ; Расчитать десятичную цифру
- xor edx,edx
- div ebx
- xchg esi,eax
- div ebx
- or dl,'0' ; Преобразовать результат в символ цифры
- push edx ; Сохранить цифру в стеке
- inc ecx ; Увеличить счетчик цифр
- or eax,eax ; Все преобразовали?
- jnz @bignum_1
- @bignum_2:
- pop eax ; Записать все цифры из стека в буфер
- stosb
- loop @bignum_2
- xor eax,eax ; Признак окончания строки
- stosb
- popad ; Восстановить все регистры
- ret ; Ворзврат из процедуры
- bignum endp
- ;#region HEX_SYMBOL_TO_DEC
- ; Получает из HEX символа DEC число
- ; Входные данные:
- ; 1. Регистр BL
- ; Выходные данные:
- ; 1. Регистр BL
- HEX_SYMBOL_TO_DEC PROC
- CMP BL, '9' ;;
- JG @IfLetter ;;
- SUB BL, '0' ;; Если BL больше '9' (т.е. символ a-f)
- jmp @EndIf ;; То
- @IfLetter: ;; BL = BL - 'a' + 10
- SUB BL, 'a' ;; Иначе
- ADD BL, 10 ;; BL = BL - '0'
- @EndIf: ;;
- RET ;;
- HEX_SYMBOL_TO_DEC ENDP
- ;#endregion HEX_SYMBOL_TO_DEC
- MAIN PROC; описание процедуры
- ;#region Получаем дескрипторы ввода и вывода
- ; Аргумент функции: -10 для ввода, -11 для вывода, -12 для сообщения об ошибки
- ; Функция возвращает дескриптор в регистр EAX
- PUSH -10
- CALL GetStdHandle@4
- ; Перемещаем регистр вывода в новую переменную D_IN
- MOV D_IN, EAX
- PUSH -11
- CALL GetStdHandle@4
- ; Перемещаем регистр вывода в новую переменную D_OUT
- MOV D_OUT, EAX
- ;#endregion Получаем дескрипторы ввода и вывода
- ;#region Перекодируем строку WRITE_VALUE для DOS
- ; Сначала перекодируем строку STRN для DOS (т.к. она содержит русские буквы)
- ; Перемещаем в регистр EAX адрес строки STRN (OFFSET возвращает адрес)
- MOV EAX, OFFSET WRITE_VALUE
- ; У функции CharToOemA@8 два параметра - откуда берем строку и куда кладем
- ; Адрес строки
- PUSH EAX; параметры функции помещаются в стек командой PUSH
- PUSH EAX
- CALL CharToOemA@8; вызов функции
- ;#endregion Перекодируем строку WRITE_VALUE для DOS
- ;#region Определяем длину строки WRITE_VALUE
- ; Аргумент функции: адрес строки. Возвращаемое значение: длина строки в регистре EAX
- PUSH OFFSET WRITE_VALUE
- CALL lstrlenA@4;
- MOV WRITE_LENGTH, EAX
- ;#endregion Определяем длину строки WRITE_VALUE
- ;#region Выводим строку WRITE_VALUE
- PUSH 0; 5-ый параметр всегда 0
- PUSH OFFSET LENS; В переменную LENS запишется длина строки, которая была выведена
- PUSH WRITE_LENGTH; Длина строки, сколько хотим вывести
- PUSH OFFSET WRITE_VALUE; Адрес строки
- PUSH D_OUT; Регистр вывода
- CALL WriteConsoleA@20
- ;#endregion Выводим строку WRITE_VALUE
- ;#region Вводим строку FIRST_STRING
- ; FIRST_LENGTH больше на два, т.к. дополнительно введены
- ; 13 - возврат каретки и 10 - переход на новую строку
- PUSH 0; 5-ый параметр всегда 0
- PUSH OFFSET FIRST_LENGTH; Длина считанной строки строки
- PUSH 50; Сколько символов хотим считать
- PUSH OFFSET FIRST_STRING; Куда читаем
- PUSH D_IN; Регистр ввода
- CALL ReadConsoleA@20
- SUB FIRST_LENGTH, 2
- ;#endregion Вводим строку FIRST_STRING
- ;#region Проверка на то, что длина строки больше трех
- CMP FIRST_LENGTH, 3
- jl string_to_small ; если строка меньше 5, то переходим прыгаем
- ;#endregion Проверка на то, что длина строки больше трех
- ;#region Еще раз выводим строку WRITE_VALUE
- PUSH 0; 5-ый параметр всегда 0
- PUSH OFFSET LENS; В переменную LENS запишется длина строки, которая была выведена
- PUSH WRITE_LENGTH; Длина строки, сколько хотим вывести
- PUSH OFFSET WRITE_VALUE; Адрес строки
- PUSH D_OUT; Регистр вывода
- CALL WriteConsoleA@20
- ;#endregion Еще раз выводим строку WRITE_VALUE
- ;#region Вводим строку SECOND_STRING
- ; 6. Вводим строку SECOND_STRING
- PUSH 0; 5-ый параметр всегда 0
- PUSH OFFSET SECOND_LENGTH; Длина считанной строки строки
- PUSH 50; Сколько символов хотим считать
- PUSH OFFSET SECOND_STRING; Куда читаем
- PUSH D_IN; Регистр ввода
- CALL ReadConsoleA@20
- SUB SECOND_LENGTH, 2
- ;#endregion Вводим строку SECOND_STRING
- ;#region Проверка на то, что длина строки больше трех
- CMP SECOND_LENGTH, 3
- jl string_to_small ; если строка меньше 5, то переходим прыгаем
- ;#endregion Проверка на то, что длина строки больше трех
- ;#region Первая строка в dec
- MOV ECX, FIRST_LENGTH
- MOV ESI, OFFSET FIRST_STRING
- XOR EAX, EAX
- @READ_BYTES:
- MOV EAX, FIRST_INT
- MOV EDX, 16
- MUL EDX ; Результат кладется в EDX и EAX, но т.к. число не превышает 32 бита, то EDX пуст
- MOV FIRST_INT, EAX
- DEC CL ; Уменьшаем число символов на 1
- MOV BL, [ESI] ; Читаем символ в BL
- INC ESI
- CALL HEX_SYMBOL_TO_DEC ; Переводим его в число
- MOV AL, BL ;; Чтобы сложить это число с EDI
- cbw ;; перемещаем его в регистр AL
- cwde ;; и резайзим его до AX, а затем до EAX
- ADD FIRST_INT, EAX
- CMP ECX, 0
- JG @READ_BYTES ; Если кол-во оставшихся символов больше 0, то читаем еще один байти
- ;#endregion Первая строка в dec
- ;#region Вторая строка в dec
- MOV ECX, SECOND_LENGTH
- MOV ESI, OFFSET SECOND_STRING
- XOR EAX, EAX
- @READ_BYTES2:
- MOV EAX, SECOND_INT
- MOV EDX, 16
- MUL EDX ; Результат кладется в EDX и EAX, но т.к. число не превышает 32 бита, то EDX пуст
- MOV SECOND_INT, EAX
- DEC CL ; Уменьшаем число символов на 1
- MOV BL, [ESI] ; Читаем символ в BL
- INC ESI
- CALL HEX_SYMBOL_TO_DEC ; Переводим его в число
- MOV AL, BL ;; Чтобы сложить это число с EDI
- cbw ;; перемещаем его в регистр AL
- cwde ;; и резайзим его до AX, а затем до EAX
- ADD SECOND_INT, EAX
- CMP ECX, 0
- JG @READ_BYTES2 ; Если кол-во оставшихся символов больше 0, то читаем еще один байти
- ;#endregion Вторая строка в dec
- MOV EAX, FIRST_INT
- MUL SECOND_INT
- CALL bignum
- ; TODO:
- ; Вывести полученное число
- PUSH 0; параметр: код выхода
- CALL ExitProcess@4
- string_to_small:
- PUSH 1;
- CALL ExitProcess@4
- MAIN ENDP
- END MAIN
Advertisement