Gistrec

Asm lab 1 v2

Oct 9th, 2018
853
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. .386
  2. .MODEL FLAT, STDCALL
  3.  
  4.  
  5. ;#region Прототипы внешних функций
  6. ; Внешние функции описываются директивой EXTERN,
  7. ; после знака @ указывается общая длина передаваемых параметров,
  8. ; после двоеточия указывается тип внешнего объекта – процедура
  9. EXTERN  GetStdHandle@4: PROC ; Позволяет получить дискрипторы ввода и вывода
  10. EXTERN  WriteConsoleA@20: PROC
  11. EXTERN  CharToOemA@8: PROC
  12. EXTERN  ReadConsoleA@20: PROC
  13. EXTERN  ExitProcess@4: PROC; функция выхода из программы
  14. EXTERN  lstrlenA@4: PROC; функция определения длины строки
  15. EXTERN  wsprintfA: PROC; т.к. число параметров функции не фиксировано,
  16.         ; используется соглашение, согласно которому очищает стек вызывающая процедура
  17. ;#endregion Прототипы внешних функций
  18.  
  19. .DATA ; сегмент данных
  20. ;#region Данные
  21. ; выводимая строка, в конце добавлены
  22. ; управляющие символы: 13 – возврат каретки, 10 – переход на новую
  23. ; строку, 0 – конец строки; с использованием директивы DB
  24. ; резервируется массив байтов
  25. WRITE_VALUE DB "Введите число в 16-ти ричной системе: ",13,10,0
  26. WRITE_LENGTH DD ? ; Длина строки
  27.  
  28. ; Деректитва DD резервирует память объемом 32 бита (4 байта)
  29. ; знак «?» используется для неинициализированных данных
  30.  
  31. FIRST_STRING DB 50 dup (?); Первое число в строковм виде
  32. FIRST_LENGTH DD ? ; Длина первого числа
  33. FIRST_INT DD 0 ; Значение hex строки в dec
  34.  
  35. SECOND_STRING DB 50 dup (?); Второе число
  36. SECOND_LENGTH DD ? ; Длина второго числа
  37. SECOND_INT DD 0 ; Значение hex строки в dec
  38.  
  39. RESULT_INT DD ? ; Результат (dec строка)
  40.  
  41. LENS DD ? ; Буффер для длины строки (для ввода/вывода)
  42. D_IN DD ? ; Дескриптор ввода
  43. D_OUT DD ?; Дескриптор вывода
  44. ;#endregion Данные
  45. BUFF DB 50 dup (?)
  46. .CODE; сегмент кода
  47.  
  48. ;---------------------------------------------------
  49. ; Преобразование QWORD в десятичное число
  50. ; Параметры вызова:
  51. ; dwHigh - Старшее двойное слово
  52. ; dwLow  - Младшее двойное слово
  53. ; lpBuff - указатель на буфер-приемник
  54. ;---------------------------------------------------
  55. bignum PROC
  56.         pushad                   ; Сохранить все регистры
  57.         mov     edi, OFFSET BUFF     ; Указатель на буфер-приемник
  58.  
  59.         xchg    esi,edx          ; Сохранить старший dword
  60.         mov     ebx,10           ; Основание системы счисления
  61.         xor     ecx,ecx          ; Счетчик десятичных цифр
  62. @bignum_1:
  63.         xchg    eax,esi          ; Расчитать десятичную цифру
  64.         xor     edx,edx
  65.         div     ebx
  66.         xchg    esi,eax
  67.         div     ebx
  68.         or      dl,'0'           ; Преобразовать результат в символ цифры
  69.         push    edx              ; Сохранить цифру в стеке
  70.         inc     ecx              ; Увеличить счетчик цифр
  71.         or      eax,eax          ; Все преобразовали?
  72.         jnz     @bignum_1
  73. @bignum_2:
  74.         pop     eax              ; Записать все цифры из стека в буфер
  75.         stosb
  76.         loop    @bignum_2
  77.         xor     eax,eax          ; Признак окончания строки
  78.         stosb
  79.         popad                    ; Восстановить все регистры
  80.         ret                      ; Ворзврат из процедуры
  81. bignum endp
  82.  
  83. ;#region HEX_SYMBOL_TO_DEC
  84. ; Получает из HEX символа DEC число
  85. ; Входные данные:
  86. ;    1. Регистр BL
  87. ; Выходные данные:
  88. ;    1. Регистр BL
  89. HEX_SYMBOL_TO_DEC PROC
  90.     CMP BL, '9'      ;;
  91.     JG @IfLetter     ;;
  92.     SUB BL, '0'      ;; Если BL больше '9' (т.е. символ a-f)
  93.     jmp @EndIf       ;; То
  94.     @IfLetter:       ;;     BL = BL - 'a' + 10
  95.     SUB BL, 'a'      ;; Иначе
  96.     ADD BL, 10       ;;     BL = BL - '0'
  97.     @EndIf:          ;;
  98.     RET              ;;
  99. HEX_SYMBOL_TO_DEC ENDP
  100.  
  101. ;#endregion HEX_SYMBOL_TO_DEC
  102.  
  103. MAIN PROC; описание процедуры
  104. ;#region Получаем дескрипторы ввода и вывода
  105. ; Аргумент функции: -10 для ввода, -11 для вывода, -12 для сообщения об ошибки
  106. ; Функция возвращает дескриптор в регистр EAX
  107. PUSH -10
  108. CALL GetStdHandle@4
  109. ; Перемещаем регистр вывода в новую переменную D_IN
  110. MOV D_IN, EAX
  111.  
  112. PUSH -11
  113. CALL GetStdHandle@4
  114. ; Перемещаем регистр вывода в новую переменную D_OUT
  115. MOV D_OUT, EAX
  116. ;#endregion Получаем дескрипторы ввода и вывода
  117.  
  118. ;#region Перекодируем строку WRITE_VALUE для DOS
  119. ; Сначала перекодируем строку STRN для DOS (т.к. она содержит русские буквы)
  120. ; Перемещаем в регистр EAX адрес строки STRN (OFFSET возвращает адрес)
  121. MOV  EAX, OFFSET WRITE_VALUE
  122.  
  123. ; У функции CharToOemA@8 два параметра - откуда берем строку и куда кладем
  124. ; Адрес строки
  125. PUSH EAX; параметры функции помещаются в стек командой PUSH
  126. PUSH EAX
  127. CALL CharToOemA@8; вызов функции
  128. ;#endregion Перекодируем строку WRITE_VALUE для DOS
  129.  
  130. ;#region Определяем длину строки WRITE_VALUE
  131. ; Аргумент функции: адрес строки. Возвращаемое значение: длина строки в регистре EAX
  132. PUSH OFFSET WRITE_VALUE
  133. CALL lstrlenA@4;
  134.  
  135. MOV WRITE_LENGTH, EAX
  136. ;#endregion Определяем длину строки WRITE_VALUE
  137.  
  138. ;#region Выводим строку WRITE_VALUE
  139. PUSH 0; 5-ый параметр всегда 0
  140. PUSH OFFSET LENS; В переменную LENS запишется длина строки, которая была выведена
  141. PUSH WRITE_LENGTH; Длина строки, сколько хотим вывести
  142. PUSH OFFSET WRITE_VALUE; Адрес строки
  143. PUSH D_OUT; Регистр вывода
  144. CALL WriteConsoleA@20
  145. ;#endregion Выводим строку WRITE_VALUE
  146.  
  147. ;#region Вводим строку FIRST_STRING
  148. ; FIRST_LENGTH больше на два, т.к. дополнительно введены
  149. ; 13 - возврат каретки и 10 - переход на новую строку
  150. PUSH 0; 5-ый параметр всегда 0
  151. PUSH OFFSET FIRST_LENGTH; Длина считанной строки строки
  152. PUSH 50; Сколько символов хотим считать
  153. PUSH OFFSET FIRST_STRING; Куда читаем
  154. PUSH D_IN; Регистр ввода
  155. CALL ReadConsoleA@20
  156. SUB FIRST_LENGTH, 2
  157. ;#endregion Вводим строку FIRST_STRING
  158.  
  159. ;#region Проверка на то, что длина строки больше трех
  160. CMP FIRST_LENGTH, 3
  161. jl string_to_small ; если строка меньше 5, то переходим прыгаем
  162. ;#endregion Проверка на то, что длина строки больше трех
  163.  
  164. ;#region Еще раз выводим строку WRITE_VALUE
  165. PUSH 0; 5-ый параметр всегда 0
  166. PUSH OFFSET LENS; В переменную LENS запишется длина строки, которая была выведена
  167. PUSH WRITE_LENGTH; Длина строки, сколько хотим вывести
  168. PUSH OFFSET WRITE_VALUE; Адрес строки
  169. PUSH D_OUT; Регистр вывода
  170. CALL WriteConsoleA@20
  171. ;#endregion Еще раз выводим строку WRITE_VALUE
  172.  
  173. ;#region Вводим строку SECOND_STRING
  174. ; 6. Вводим строку SECOND_STRING
  175. PUSH 0; 5-ый параметр всегда 0
  176. PUSH OFFSET SECOND_LENGTH; Длина считанной строки строки
  177. PUSH 50; Сколько символов хотим считать
  178. PUSH OFFSET SECOND_STRING; Куда читаем
  179. PUSH D_IN; Регистр ввода
  180. CALL ReadConsoleA@20
  181. SUB SECOND_LENGTH, 2
  182. ;#endregion Вводим строку SECOND_STRING
  183.  
  184. ;#region Проверка на то, что длина строки больше трех
  185. CMP SECOND_LENGTH, 3
  186. jl string_to_small ; если строка меньше 5, то переходим прыгаем
  187. ;#endregion Проверка на то, что длина строки больше трех
  188.  
  189.  
  190. ;#region Первая строка в dec
  191. MOV ECX, FIRST_LENGTH
  192. MOV ESI, OFFSET FIRST_STRING
  193.  
  194. XOR EAX, EAX
  195.  
  196. @READ_BYTES:
  197. MOV EAX, FIRST_INT
  198. MOV EDX, 16
  199. MUL EDX ; Результат кладется в EDX и EAX, но т.к. число не превышает 32 бита, то EDX пуст
  200. MOV FIRST_INT, EAX
  201.  
  202. DEC CL ; Уменьшаем число символов на 1
  203. MOV BL, [ESI]            ; Читаем символ в BL
  204. INC ESI
  205. CALL HEX_SYMBOL_TO_DEC   ; Переводим его в число
  206. MOV AL, BL   ;; Чтобы сложить это число с EDI
  207. cbw          ;; перемещаем его в регистр AL
  208. cwde         ;; и резайзим его до AX, а затем до EAX
  209.  
  210. ADD FIRST_INT, EAX
  211.  
  212. CMP ECX, 0
  213. JG @READ_BYTES ; Если кол-во оставшихся символов больше 0, то читаем еще один байти
  214. ;#endregion Первая строка в dec
  215.  
  216. ;#region Вторая строка в dec
  217. MOV ECX, SECOND_LENGTH
  218. MOV ESI, OFFSET SECOND_STRING
  219.  
  220. XOR EAX, EAX
  221.  
  222. @READ_BYTES2:
  223. MOV EAX, SECOND_INT
  224. MOV EDX, 16
  225. MUL EDX ; Результат кладется в EDX и EAX, но т.к. число не превышает 32 бита, то EDX пуст
  226. MOV SECOND_INT, EAX
  227.  
  228. DEC CL ; Уменьшаем число символов на 1
  229. MOV BL, [ESI]            ; Читаем символ в BL
  230. INC ESI
  231. CALL HEX_SYMBOL_TO_DEC   ; Переводим его в число
  232. MOV AL, BL   ;; Чтобы сложить это число с EDI
  233. cbw          ;; перемещаем его в регистр AL
  234. cwde         ;; и резайзим его до AX, а затем до EAX
  235.  
  236. ADD SECOND_INT, EAX
  237.  
  238. CMP ECX, 0
  239. JG @READ_BYTES2 ; Если кол-во оставшихся символов больше 0, то читаем еще один байти
  240. ;#endregion Вторая строка в dec
  241.  
  242.  
  243. MOV EAX, FIRST_INT
  244. MUL SECOND_INT
  245.  
  246. CALL bignum
  247.  
  248. ; TODO:
  249. ; Вывести полученное число
  250.  
  251. PUSH 0; параметр: код выхода
  252. CALL ExitProcess@4
  253.  
  254. string_to_small:
  255. PUSH 1;
  256. CALL ExitProcess@4
  257.  
  258. MAIN ENDP
  259. END MAIN
Advertisement