fork download
  1. section .data
  2. prompt1 db "Введите первое число: ", 0
  3. prompt2 db "Введите второе число: ", 0
  4. result_msg db "Сумма: ", 0
  5. newline db 10, 0
  6. buffer times 256 db 0
  7. num1 times 32 db 0 ; Максимум 32 байта для первого числа
  8. num2 times 32 db 0 ; Максимум 32 байта для второго числа
  9. sum times 32 db 0 ; Результат сложения
  10.  
  11. section .bss
  12. N resb 1 ; Размер чисел в байтах (1-32)
  13.  
  14. section .text
  15. global _start
  16.  
  17. _start:
  18. ; Получаем размер чисел N от пользователя
  19. mov rax, prompt1
  20. call print_string
  21. call read_hex_byte
  22. mov [N], al
  23.  
  24. ; Проверяем корректность N (1-32)
  25. cmp al, 1
  26. jl exit_program
  27. cmp al, 32
  28. jg exit_program
  29.  
  30. ; Читаем первое число
  31. mov rax, prompt1
  32. call print_string
  33. movzx rcx, byte [N]
  34. mov rdi, num1
  35. call read_hex_number
  36.  
  37. ; Читаем второе число
  38. mov rax, prompt2
  39. call print_string
  40. movzx rcx, byte [N]
  41. mov rdi, num2
  42. call read_hex_number
  43.  
  44. ; Складываем числа
  45. movzx rcx, byte [N]
  46. call add_numbers
  47.  
  48. ; Выводим результат
  49. mov rax, result_msg
  50. call print_string
  51. movzx rcx, byte [N]
  52. mov rsi, sum
  53. call print_hex_number
  54.  
  55. ; Новая строка
  56. mov rax, newline
  57. call print_string
  58.  
  59. exit_program:
  60. mov rax, 60 ; sys_exit
  61. xor rdi, rdi ; код возврата 0
  62. syscall
  63.  
  64. ; ============================================
  65. ; Процедура сложения двух чисел
  66. ; Вход: RCX = размер чисел в байтах
  67. ; num1, num2 - складываемые числа
  68. ; Выход: sum = num1 + num2
  69. ; ============================================
  70. add_numbers:
  71. push rcx
  72. push rsi
  73. push rdi
  74. xor rsi, rsi ; Индекс байта
  75. clc ; Сбрасываем флаг переноса
  76.  
  77. .add_loop:
  78. mov al, [num1 + rsi]
  79. mov bl, [num2 + rsi]
  80.  
  81. ; Сложение с учетом переноса
  82. adc al, bl
  83. mov [sum + rsi], al
  84.  
  85. inc rsi
  86. loop .add_loop ; Уменьшает RCX и повторяет если не 0
  87.  
  88. pop rdi
  89. pop rsi
  90. pop rcx
  91. ret
  92.  
  93. ; ============================================
  94. ; Чтение шестнадцатеричного числа
  95. ; Вход: RCX = количество байтов
  96. ; RDI = указатель на буфер для числа
  97. ; ============================================
  98. read_hex_number:
  99. push rcx
  100. push rdi
  101. push rsi
  102.  
  103. ; Читаем строку
  104. mov rax, 0 ; sys_read
  105. mov rdi, 0 ; stdin
  106. mov rsi, buffer
  107. mov rdx, 256
  108. syscall
  109.  
  110. ; Конвертируем hex строку в число
  111. mov rsi, buffer
  112. mov rdx, rdi ; Сохраняем указатель на выходной буфер
  113.  
  114. ; Пропускаем пробелы
  115. .skip_spaces:
  116. lodsb
  117. cmp al, ' '
  118. je .skip_spaces
  119. cmp al, 10 ; Новая строка
  120. je .done
  121. cmp al, 13 ; Возврат каретки
  122. je .done
  123.  
  124. dec rsi ; Возвращаемся к первому символу
  125.  
  126. ; Определяем, отрицательное ли число
  127. mov al, [rsi]
  128. cmp al, '-'
  129. jne .parse_positive
  130.  
  131. ; Отрицательное число
  132. inc rsi ; Пропускаем минус
  133. call parse_hex_string
  134. call negate_number
  135. jmp .done
  136.  
  137. .parse_positive:
  138. call parse_hex_string
  139.  
  140. .done:
  141. pop rsi
  142. pop rdi
  143. pop rcx
  144. ret
  145.  
  146. ; ============================================
  147. ; Парсинг шестнадцатеричной строки
  148. ; Вход: RSI = указатель на строку
  149. ; RCX = размер числа в байтах
  150. ; RDX = указатель на буфер результата
  151. ; ============================================
  152. parse_hex_string:
  153. push rcx
  154. push rdx
  155. push rbx
  156.  
  157. mov rdi, rdx
  158. add rdi, rcx
  159. dec rdi ; RDI указывает на последний байт буфера
  160.  
  161. ; Очищаем буфер
  162. mov rdx, rdi
  163. .clear_buffer:
  164. mov byte [rdx], 0
  165. dec rdx
  166. cmp rdx, rdi
  167. jge .clear_buffer
  168.  
  169. xor rbx, rbx ; Счетчик считанных символов
  170.  
  171. .read_char:
  172. lodsb ; Загружаем символ из строки
  173.  
  174. ; Проверяем конец строки
  175. cmp al, 0
  176. je .parse_done
  177. cmp al, 10 ; Новая строка
  178. je .parse_done
  179. cmp al, 13 ; Возврат каретки
  180. je .parse_done
  181. cmp al, ' ' ; Пробел
  182. je .parse_done
  183.  
  184. ; Преобразуем символ в число
  185. call char_to_hex
  186. cmp al, 0xFF
  187. je .invalid_char
  188.  
  189. ; Сдвигаем текущее значение и добавляем новое
  190. push rcx
  191. mov rcx, 4 ; Сдвигаем на 4 бита
  192.  
  193. .shift_buffer:
  194. push rdi
  195. mov rdx, rdi
  196. sub rdx, rcx
  197. inc rdx
  198.  
  199. .shift_loop:
  200. mov bl, [rdx]
  201. shl bl, 4
  202. mov [rdx], bl
  203. inc rdx
  204. cmp rdx, rdi
  205. jle .shift_loop
  206.  
  207. pop rdi
  208.  
  209. ; Добавляем новый полубайт
  210. mov bl, [rdi]
  211. or bl, al
  212. mov [rdi], bl
  213.  
  214. pop rcx
  215.  
  216. inc rbx
  217. cmp rbx, rcx ; Проверяем, не превысили ли размер
  218. jl .read_char
  219.  
  220. .parse_done:
  221. pop rbx
  222. pop rdx
  223. pop rcx
  224. ret
  225.  
  226. .invalid_char:
  227. ; В случае ошибки возвращаем 0
  228. mov rdi, rdx
  229. mov byte [rdi], 0
  230. jmp .parse_done
  231.  
  232. ; ============================================
  233. ; Преобразование символа в шестнадцатеричное число
  234. ; Вход: AL = символ
  235. ; Выход: AL = число (0-15) или 0xFF при ошибке
  236. ; ============================================
  237. char_to_hex:
  238. cmp al, '0'
  239. jl .invalid
  240. cmp al, '9'
  241. jg .check_upper
  242.  
  243. sub al, '0'
  244. ret
  245.  
  246. .check_upper:
  247. cmp al, 'A'
  248. jl .invalid
  249. cmp al, 'F'
  250. jg .check_lower
  251.  
  252. sub al, 'A' - 10
  253. ret
  254.  
  255. .check_lower:
  256. cmp al, 'a'
  257. jl .invalid
  258. cmp al, 'f'
  259. jg .invalid
  260.  
  261. sub al, 'a' - 10
  262. ret
  263.  
  264. .invalid:
  265. mov al, 0xFF
  266. ret
  267.  
  268. ; ============================================
  269. ; Инверсия числа (дополнительный код)
  270. ; Вход: RCX = размер числа в байтах
  271. ; RDI = указатель на число
  272. ; ============================================
  273. negate_number:
  274. push rcx
  275. push rsi
  276.  
  277. mov rsi, rdi
  278. add rsi, rcx
  279. dec rsi ; RSI указывает на последний байт
  280.  
  281. ; Инвертируем все биты
  282. .not_loop:
  283. not byte [rsi]
  284. dec rsi
  285. cmp rsi, rdi
  286. jge .not_loop
  287.  
  288. ; Добавляем 1
  289. mov rsi, rdi
  290. mov byte al, 1
  291.  
  292. .add_one_loop:
  293. add byte [rsi], al
  294. jnc .done_negate
  295. mov al, 1
  296. inc rsi
  297. cmp rsi, rdi
  298. add rsi, rcx
  299. dec rsi
  300. jle .add_one_loop
  301.  
  302. .done_negate:
  303. pop rsi
  304. pop rcx
  305. ret
  306.  
  307. ; ============================================
  308. ; Вывод шестнадцатеричного числа
  309. ; Вход: RCX = размер числа в байтах
  310. ; RSI = указатель на число
  311. ; ============================================
  312. print_hex_number:
  313. push rcx
  314. push rsi
  315. push rdi
  316.  
  317. ; Проверяем знак числа
  318. mov al, [rsi + rcx - 1]
  319. test al, 0x80 ; Проверяем старший бит
  320. jz .print_positive
  321.  
  322. ; Отрицательное число
  323. push rcx
  324. push rsi
  325.  
  326. ; Копируем число во временный буфер
  327. mov rdi, buffer
  328. rep movsb
  329.  
  330. pop rsi
  331. pop rcx
  332.  
  333. ; Выводим минус
  334. mov byte [buffer], '-'
  335. mov rax, buffer
  336. call print_string
  337.  
  338. ; Преобразуем в дополнительный код
  339. mov rdi, rsi
  340. call negate_number
  341. dec rcx ; Уже вывели минус
  342.  
  343. .print_positive:
  344. mov rdi, rsi
  345. add rdi, rcx
  346. dec rdi ; RDI указывает на последний байт
  347.  
  348. ; Пропускаем ведущие нули
  349. .find_first_nonzero:
  350. cmp byte [rdi], 0
  351. jne .print_hex
  352. dec rdi
  353. cmp rdi, rsi
  354. jge .find_first_nonzero
  355.  
  356. ; Все нули - выводим "0"
  357. mov byte [buffer], '0'
  358. mov byte [buffer + 1], 0
  359. mov rax, buffer
  360. call print_string
  361. jmp .done_print
  362.  
  363. .print_hex:
  364. ; Преобразуем байт в два hex символа
  365. mov al, [rdi]
  366. mov bl, al
  367. shr al, 4
  368. call hex_to_char
  369. mov [buffer], al
  370. mov al, bl
  371. and al, 0x0F
  372. call hex_to_char
  373. mov [buffer + 1], al
  374. mov byte [buffer + 2], 0
  375.  
  376. mov rax, buffer
  377. call print_string
  378.  
  379. dec rdi
  380. cmp rdi, rsi
  381. jge .print_hex
  382.  
  383. .done_print:
  384. pop rdi
  385. pop rsi
  386. pop rcx
  387. ret
  388.  
  389. ; ============================================
  390. ; Преобразование числа 0-15 в символ hex
  391. ; Вход: AL = число (0-15)
  392. ; Выход: AL = символ hex
  393. ; ============================================
  394. hex_to_char:
  395. cmp al, 10
  396. jl .digit
  397.  
  398. add al, 'A' - 10
  399. ret
  400.  
  401. .digit:
  402. add al, '0'
  403. ret
  404.  
  405. ; ============================================
  406. ; Чтение одного байта в hex
  407. ; Выход: AL = прочитанное число
  408. ; ============================================
  409. read_hex_byte:
  410. push rsi
  411. push rdx
  412.  
  413. mov rax, 0 ; sys_read
  414. mov rdi, 0 ; stdin
  415. mov rsi, buffer
  416. mov rdx, 3 ; Максимум 2 символа + новая строка
  417. syscall
  418.  
  419. ; Конвертируем hex в число
  420. mov rsi, buffer
  421. xor rax, rax
  422.  
  423. .read_digit:
  424. mov dl, [rsi]
  425. cmp dl, 10 ; Новая строка
  426. je .done_read
  427. cmp dl, 13 ; Возврат каретки
  428. je .done_read
  429.  
  430. call char_to_hex
  431. cmp al, 0xFF
  432. je .invalid_input
  433.  
  434. shl rax, 4
  435. add al, [rsi]
  436. inc rsi
  437. jmp .read_digit
  438.  
  439. .invalid_input:
  440. xor al, al
  441.  
  442. .done_read:
  443. pop rdx
  444. pop rsi
  445. ret
  446.  
  447. ; ============================================
  448. ; Вывод строки
  449. ; Вход: RAX = указатель на строку
  450. ; ============================================
  451. print_string:
  452. push rsi
  453. push rdx
  454. push rdi
  455.  
  456. mov rsi, rax
  457. mov rdx, 0
  458.  
  459. .strlen_loop:
  460. cmp byte [rsi + rdx], 0
  461. je .strlen_done
  462. inc rdx
  463. jmp .strlen_loop
  464.  
  465. .strlen_done:
  466. mov rax, 1 ; sys_write
  467. mov rdi, 1 ; stdout
  468. syscall
  469.  
  470. pop rdi
  471. pop rdx
  472. pop rsi
  473. ret
Success #stdin #stdout 0s 5268KB
stdin
Standard input is empty
stdout
Введите первое число: