БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ
Кафедра программного обеспечения информационных технологий
Факультет ФКСиС
Специальность ПОИТ
Контрольная работа №1
по дисциплине «Языки программирования часть 1»
Вариант 5
Выполнил студент: Бордон Е.С.
группа 991051
Зачетная книжка № 99105004
Минск 2021
Условия задачи
Написать на языке Ассемблер и отладить три программы, содержащие процедуру. Программы различаются между собой способом передачи параметров в процедуру и типом процедуры:
Программа 1. Передача параметров через регистр. Тип процедуры – дальний.
Программа 2. Передача параметров через глобальные переменные. Тип процедуры – дальний.
Программа 3. Передача параметров через стек. Тип процедуры – ближний.
В программе предусмотреть ввод данных, передачу этих данных в процедуру заданного типа с использованием соответствующего способа передачи параметров и необходимые в соответствии с вариантом вычисления в теле процедуры. Программа должна содержать комментарии для каждой команды.
Ввести два 16-битовых целых числа А и В. Вычислить значение
выражения: A/B – 7*B.
Пояснения к работе программы
Программы написаны на Assembler для MASM для выполнения на современных 32-битных процессорах в ОС Windows с использованием среды разработки SASM и отладчика OllyDbg.
Программа принимает от пользователя 2 16-битных числа и производит над ними заданные условиями задачи преобразования. Поскольку результат операций может не уместится в 32 бита, то предусмотрена специальная последовательность команд, преобразующая число в строку для вывода на экран из промежуточного буфера.
Результат работы программы
Рис 1. Результат работы программы
Тестовый набор данных:
Программа 1
A |
B |
A/B – 7*B |
990 |
851 |
-5955,84 |
205 |
956 |
-6691,79 |
213 |
19 |
-121,79 |
45 |
2 |
8,50 |
403 |
515 |
-3604,22 |
0 |
3 |
-21,00 |
7 |
7 |
-48,00 |
Программа 2
A |
B |
A/B – 7*B |
990 |
851 |
-5955,84 |
205 |
956 |
-6691,79 |
213 |
19 |
-121,79 |
45 |
2 |
8,50 |
403 |
515 |
-3604,22 |
0 |
3 |
-21,00 |
7 |
7 |
-48,00 |
Программа 3
A |
B |
A/B – 7*B |
990 |
851 |
-5955,84 |
205 |
956 |
-6691,79 |
213 |
19 |
-121,79 |
45 |
2 |
8,50 |
403 |
515 |
-3604,22 |
0 |
3 |
-21,00 |
7 |
7 |
-48,00 |
Листинг программы 1
.386 ; код скомпилируется для сравнительно современных 32-битных процессоров
.model flat, stdcall ; устанавливаем модель памяти windows, очистку стека осуществляет вызываемая подпрограмма
option casemap : none ; делаем переменные регистрозависимыми
include \masm32\include\kernel32.inc ; для использования базового API Windows
include \masm32\include\msvcrt.inc ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib ; для использования базового API Windows
includelib \masm32\lib\msvcrt.lib ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
BSIZE equ 20 ; буффер для вывода 64-битных чисел
CRLF equ 13, 10 ; синоним перевода строки в консоли
.data
; далее переменные с фрагментами текста для общения с пользователем
msgInputA db "Enter decimal integer number A from 0 to 65535:", CRLF, 0 ; текст приглашения указать первое число
msgInputB db "Enter decimal integer number B from 0 to 65535:", CRLF, 0 ; текст приглашения указать второе число
msgInputY db "*** A/B-7B ***", CRLF, 0 ; условие
msgInputRes db "Result is ", 0
msgInputResm db "Result is -", 0 ; текст вступления перед выводом результата вычислений
msgInputOst db ",00", 0 ; остаток если нет
msgInputOstt db ",", 0 ; если есть остаток
msgFinal db CRLF, "Enter any char and press 'Enter' for exit", CRLF, 0; инструкция по выходу из программы
formatInt db '%d',0 ; описание формата целого числа
formatStr db '%s',0 ; описание формата строки
x db ?
.data?
numA dw ? ; переменная для хранения числа А
numB dw ? ; переменная для хранения числа В
numRes db BSIZE dup (?) ; переменная для хранения результата вычислений в строчном формате - массив из 20 символов по 1 байту
.code
start:
invoke crt_printf, ADDR formatStr, ADDR msgInputA ; выводим приглашение ввести первое число
invoke crt_scanf, ADDR formatInt, ADDR numA ; считываем первое число в переменную numA
xor esi, esi ; обнуляем регистр esi
mov si, numA ; копируем первое число в регистр si для передачи в функцию
invoke crt_printf, ADDR formatStr, ADDR msgInputB ; выводим приглашение ввести второе число
invoke crt_scanf, ADDR formatInt, ADDR numB ; считываем второе число в переменную numB
xor edi, edi ; обнуляем регистр edi
mov di, numB ; копируем первое число в регистр di для передачи в функцию
invoke crt_printf, ADDR formatStr, ADDR msgInputY ; выводим условие
call arifm ; вызываем процедуру-обработчик
invoke crt_printf, ADDR formatStr, ADDR msgFinal ; объясняем, как выйти из программы
invoke crt_scanf, ADDR formatStr, ADDR numA ; переиспользуем переменную для хранения ненужных данных
invoke ExitProcess, 0 ; закрываем программу, возвращаемся к ОС
arifm proc far ; тип вызова процедуры - дальний
;________________________________________________________________________
; a/b-7b
mov eax, esi ; в esi храниться numA
mov edx, 0 ; вводим целые числа
mov ebx, edi ; в edi храниться numB
div ebx ; (dx,ax)/bx = ax, dx **** a/b ****
mov ecx, eax ; результат a/b целая часть
mov eax, 100 ; переводим в десятичный вид для вывода в строку
mul edx
div ebx
mov edi, eax
mov eax, 7
mul ebx ; 7*b результат edx:eax
cmp ecx, eax ; тест на отрицательный результат для вывода в строку
jl min ; <
jg EndPr ; >
jz EndPr ; =
min:
cmp edi, 0
jl EndPr ; <
jg big ; >
jz EndPr ; =
big: ; если есть остаток от деления
add ecx, 1
sub edi, 100
neg edi
JMP EndPr
EndPr:
sub ecx, eax ; от целой части a/b отнимаем целую часть 7*b Ответ ecx
mov eax, ecx ; eax = ответ целая часть
test eax, eax ; тест на знак числа ответа
JZ plus
js minys
plus:
mov x, 0
JMP EndProg
minys:
neg eax ; для перевода в строку
mov x, 1
JMP EndProg
EndProg:
; eax - ответ на поставленную задачу, целая часть
; осталось вывести его на экран, преобразовав в строку с учётом того,
; что число может превышать 32-бита, т.е. стандартные функции с ним работать не могут
; подготовим вспомогательные данные
mov esi, BSIZE ; устанавливаем счётчик цикла равным длине максимального десятичного числа, помещающегося в 64-бита
mov ebx, edx ; копируем в ebx значение edx для дальнейшего оперирования обеими копиями значения
mov ecx, 10 ; для извлечения минимального десятичного числа будем делить на 10
nxt:
dec esi ; позиция следующего символа
xchg eax, ebx ; делим ...
xor edx, edx ; ... старшую ...
div ecx ; половину
xchg eax, ebx ; сохраняем частное
div ecx ; и делим остаток + младшую половину
add dl, 48 ; преобразуем в код соответствующего ASCII-символа
mov numRes[esi], dl ; сохраняем символ в буфер
mov edx, ebx ; возвращаем частное в edx
or edx, eax ; если оба частных равны нулю...
jnz nxt ; пойдём к следующей по порядку инструкции, иначе вернёмся в начало цикла
test x, 1 ; тест на знак числа ответа
jz pls
jnz mns
pls:
invoke crt_printf, ADDR formatStr, ADDR msgInputRes ; текст-пояснение 'Result is'
JMP EProg
mns:
invoke crt_printf, ADDR formatStr, ADDR msgInputResm ; текст-пояснение 'Result is -'
JMP EProg
EProg:
mov edx, offset numRes ; запоминаем адрес начала массива
add edx, esi ; добавляем смещение до первого символа, теперь в edx адрес первого символа строки результата
invoke crt_printf, ADDR formatStr, edx ; выводим результат вычислений на экран (десятичное число) целая часть
; вывод на экран дробной части
cmp edi, 0
jl mesgg ; <
jg mesgg ; >
jz mesg ; =
mesg:
invoke crt_printf, ADDR formatStr, ADDR msgInputOst ; если дробной части нет
JMP EndPrg
mesgg:
mov eax, edi ; если она есть
xor edx, edx
xor esi, esi
xor dl, dl
mov esi, BSIZE ; устанавливаем счётчик цикла равным длине максимального десятичного числа, помещающегося в 64-бита
mov ebx, edx ; копируем в ebx значение edx для дальнейшего оперирования обеими копиями значения
mov ecx, 10 ; для извлечения минимального десятичного числа будем делить на 10
nxtt:
dec esi ; позиция следующего символа
xchg eax, ebx ; делим ...
xor edx, edx ; ... старшую ...
div ecx ; половину
xchg eax, ebx ; сохраняем частное
div ecx ; и делим остаток + младшую половину
add dl, 48 ; преобразуем в код соответствующего ASCII-символа
mov numRes[esi], dl ; сохраняем символ в буфер
mov edx, ebx ; возвращаем частное в edx
or edx, eax ; если оба частных равны нулю...
jnz nxtt ; пойдём к следующей по порядку инструкции, иначе вернёмся в начало цикла
invoke crt_printf, ADDR formatStr, ADDR msgInputOstt ; выводим знак ","
mov edx, offset numRes ; запоминаем адрес начала массива
add edx, esi ; добавляем смещение до первого символа, теперь в edx адрес первого символа строки результата
invoke crt_printf, ADDR formatStr, edx ; выводим само число
JMP EndPrg
EndPrg:
ret ; возврат управления вызвавшей программе
arifm endp ; конец процедуры arifm
end start ; выполнение программы начнётся с метки start
Листинг программы 2
.386 ; код скомпилируется для сравнительно современных 32-битных процессоров
.model flat, stdcall ; устанавливаем модель памяти windows, очистку стека осуществляет вызываемая подпрограмма
option casemap : none ; делаем переменные регистрозависимыми
include \masm32\include\kernel32.inc ; для использования базового API Windows
include \masm32\include\msvcrt.inc ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib ; для использования базового API Windows
includelib \masm32\lib\msvcrt.lib ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
BSIZE equ 20 ; буффер для вывода 64-битных чисел
CRLF equ 13, 10 ; синоним перевода строки в консоли
.data
; далее переменные с фрагментами текста для общения с пользователем
msgInputA db "Enter decimal integer number A from 0 to 65535:", CRLF, 0 ; текст приглашения указать первое число
msgInputB db "Enter decimal integer number B from 0 to 65535:", CRLF, 0 ; текст приглашения указать второе число
msgInputY db "*** A/B-7B ***", CRLF, 0 ; условие
msgInputRes db "Result is ", 0
msgInputResm db "Result is -", 0 ; текст вступления перед выводом результата вычислений
msgInputOst db ",00", 0 ; остаток если нет
msgInputOstt db ",", 0 ; если есть остаток
msgFinal db CRLF, "Enter any char and press 'Enter' for exit", CRLF, 0; инструкция по выходу из программы
formatInt db '%d',0 ; описание формата целого числа
formatStr db '%s',0 ; описание формата строки
x db ?
.data?
numA dw ? ; переменная для хранения числа А
numB dw ? ; переменная для хранения числа В
numRes db BSIZE dup (?) ; переменная для хранения результата вычислений в строчном формате - массив из 20 символов по 1 байту
.code
start:
invoke crt_printf, ADDR formatStr, ADDR msgInputA ; выводим приглашение ввести первое число
invoke crt_scanf, ADDR formatInt, ADDR numA ; считываем первое число в переменную numA
invoke crt_printf, ADDR formatStr, ADDR msgInputB ; выводим приглашение ввести второе число
invoke crt_scanf, ADDR formatInt, ADDR numB ; считываем второе число в переменную numB
invoke crt_printf, ADDR formatStr, ADDR msgInputY ; выводим условие
call arifm ; вызываем процедуру-обработчик
invoke crt_printf, ADDR formatStr, ADDR msgFinal ; объясняем, как выйти из программы
invoke crt_scanf, ADDR formatStr, ADDR numA ; переиспользуем переменную для хранения ненужных данных
invoke ExitProcess, 0 ; закрываем программу, возвращаемся к ОС
arifm proc far ; тип вызова процедуры - дальний
;________________________________________________________________________
; a/b-7b
mov eax, 1
mul numA
mov edx, 0 ; вводим целые числа
div numB ; (dx,ax)/bx = ax, dx **** a/b ****
mov ecx, eax ; результат a/b целая часть
mov eax, 100 ; переводим в десятичный вид для вывода в строку
mul edx
div numB
mov edi, eax
mov eax, 7
mul numB ; 7*b результат edx:eax
cmp ecx, eax ; тест на отрицательный результат для вывода в строку
jl min ; <
jg EndPr ; >
jz EndPr ; =
min:
cmp edi, 0
jl EndPr ; <
jg big ; >
jz EndPr ; =
big: ; если есть остаток от деления
add ecx, 1
sub edi, 100
neg edi
JMP EndPr
EndPr:
sub ecx, eax ; от целой части a/b отнимаем целую часть 7*b Ответ ecx
mov eax, ecx ; eax = ответ целая часть
test eax, eax ; тест на знак числа ответа
JZ plus
js minys
plus:
mov x, 0
JMP EndProg
minys:
neg eax ; для перевода в строку
mov x, 1
JMP EndProg
EndProg:
; eax - ответ на поставленную задачу, целая часть
; осталось вывести его на экран, преобразовав в строку с учётом того,
; что число может превышать 32-бита, т.е. стандартные функции с ним работать не могут
; подготовим вспомогательные данные
mov esi, BSIZE ; устанавливаем счётчик цикла равным длине максимального десятичного числа, помещающегося в 64-бита
mov ebx, edx ; копируем в ebx значение edx для дальнейшего оперирования обеими копиями значения
mov ecx, 10 ; для извлечения минимального десятичного числа будем делить на 10
nxt:
dec esi ; позиция следующего символа
xchg eax, ebx ; делим ...
xor edx, edx ; ... старшую ...
div ecx ; половину
xchg eax, ebx ; сохраняем частное
div ecx ; и делим остаток + младшую половину
add dl, 48 ; преобразуем в код соответствующего ASCII-символа
mov numRes[esi], dl ; сохраняем символ в буфер
mov edx, ebx ; возвращаем частное в edx
or edx, eax ; если оба частных равны нулю...
jnz nxt ; пойдём к следующей по порядку инструкции, иначе вернёмся в начало цикла
test x, 1 ; тест на знак числа ответа
jz pls
jnz mns
pls:
invoke crt_printf, ADDR formatStr, ADDR msgInputRes ; текст-пояснение 'Result is'
JMP EProg
mns:
invoke crt_printf, ADDR formatStr, ADDR msgInputResm ; текст-пояснение 'Result is -'
JMP EProg
EProg:
mov edx, offset numRes ; запоминаем адрес начала массива
add edx, esi ; добавляем смещение до первого символа, теперь в edx адрес первого символа строки результата
invoke crt_printf, ADDR formatStr, edx ; выводим результат вычислений на экран (десятичное число) целая часть
; вывод на экран дробной части
cmp edi, 0
jl mesgg ; <
jg mesgg ; >
jz mesg ; =
mesg:
invoke crt_printf, ADDR formatStr, ADDR msgInputOst ; если дробной части нет
JMP EndPrg
mesgg:
mov eax, edi ; если она есть
xor edx, edx
xor esi, esi
xor dl, dl
mov esi, BSIZE ; устанавливаем счётчик цикла равным длине максимального десятичного числа, помещающегося в 64-бита
mov ebx, edx ; копируем в ebx значение edx для дальнейшего оперирования обеими копиями значения
mov ecx, 10 ; для извлечения минимального десятичного числа будем делить на 10
nxtt:
dec esi ; позиция следующего символа
xchg eax, ebx ; делим ...
xor edx, edx ; ... старшую ...
div ecx ; половину
xchg eax, ebx ; сохраняем частное
div ecx ; и делим остаток + младшую половину
add dl, 48 ; преобразуем в код соответствующего ASCII-символа
mov numRes[esi], dl ; сохраняем символ в буфер
mov edx, ebx ; возвращаем частное в edx
or edx, eax ; если оба частных равны нулю...
jnz nxtt ; пойдём к следующей по порядку инструкции, иначе вернёмся в начало цикла
invoke crt_printf, ADDR formatStr, ADDR msgInputOstt ; выводим знак ","
mov edx, offset numRes ; запоминаем адрес начала массива
add edx, esi ; добавляем смещение до первого символа, теперь в edx адрес первого символа строки результата
invoke crt_printf, ADDR formatStr, edx ; выводим само число
JMP EndPrg
EndPrg:
ret ; возврат управления вызвавшей программе
arifm endp ; конец процедуры arifm
end start ; выполнение программы начнётся с метки start
Листинг программы 3
.386 ; код скомпилируется для сравнительно современных 32-битных процессоров
.model flat, stdcall ; устанавливаем модель памяти windows, очистку стека осуществляет вызываемая подпрограмма
option casemap : none ; делаем переменные регистрозависимыми
include \masm32\include\kernel32.inc ; для использования базового API Windows
include \masm32\include\msvcrt.inc ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib ; для использования базового API Windows
includelib \masm32\lib\msvcrt.lib ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
BSIZE equ 20 ; буффер для вывода 64-битных чисел
CRLF equ 13, 10 ; синоним перевода строки в консоли
.data
; далее переменные с фрагментами текста для общения с пользователем
msgInputA db "Enter decimal integer number A from 0 to 65535:", CRLF, 0 ; текст приглашения указать первое число
msgInputB db "Enter decimal integer number B from 0 to 65535:", CRLF, 0 ; текст приглашения указать второе число
msgInputY db "*** A/B-7B ***", CRLF, 0 ; условие
msgInputRes db "Result is ", 0
msgInputResm db "Result is -", 0 ; текст вступления перед выводом результата вычислений
msgInputOst db ",00", 0 ; остаток если нет
msgInputOstt db ",", 0 ; если есть остаток
msgFinal db CRLF, "Enter any char and press 'Enter' for exit", CRLF, 0; инструкция по выходу из программы
formatInt db '%d',0 ; описание формата целого числа
formatStr db '%s',0 ; описание формата строки
x db ?
.data?
numA dw ? ; переменная для хранения числа А
numB dw ? ; переменная для хранения числа В
numRes db BSIZE dup (?) ; переменная для хранения результата вычислений в строчном формате - массив из 20 символов по 1 байту
.code
start:
invoke crt_printf, ADDR formatStr, ADDR msgInputA ; выводим приглашение ввести первое число
invoke crt_scanf, ADDR formatInt, ADDR numA ; считываем первое число в переменную numA
push numA
invoke crt_printf, ADDR formatStr, ADDR msgInputB ; выводим приглашение ввести второе число
invoke crt_scanf, ADDR formatInt, ADDR numB ; считываем второе число в переменную numB
push numB
invoke crt_printf, ADDR formatStr, ADDR msgInputY ; выводим условие
call arifm ; вызываем процедуру-обработчик
invoke crt_printf, ADDR formatStr, ADDR msgFinal ; объясняем, как выйти из программы
invoke crt_scanf, ADDR formatStr, ADDR numA ; переиспользуем переменную для хранения ненужных данных
invoke ExitProcess, 0 ; закрываем программу, возвращаемся к ОС
arifm proc near ; тип вызова процедуры - ближний
;________________________________________________________________________
; a/b-7b
mov ebp, esp ; так как регистр esp не может использоваться для косвенной адресации, то вместо esp используется ebp
mov si, [ebp + 6] ; заносим в esi значение из стека с учётом того, что на вершине стека адрес возврата и numB
mov eax, 1
mul si
mov si, [ebp + 4] ; заносим в esi значение из стека с учётом того, что на вершине стека адрес возврата
mov edx, 0 ; вводим целые числа
div si ; (dx,ax)/bx = ax, dx **** a/b ****
mov ecx, eax ; результат a/b целая часть
mov eax, 100 ; переводим в десятичный вид для вывода в строку
mul edx
div si
mov edi, eax
mov eax, 7
mul si ; 7*b результат edx:eax
cmp ecx, eax ; тест на отрицательный результат для вывода в строку
jl min ; <
jg EndPr ; >
jz EndPr ; =
min:
cmp edi, 0
jl EndPr ; <
jg big ; >
jz EndPr ; =
big: ; если есть остаток от деления
add ecx, 1
sub edi, 100
neg edi
JMP EndPr
EndPr:
sub ecx, eax ; от целой части a/b отнимаем целую часть 7*b Ответ ecx
mov eax, ecx ; eax = ответ целая часть
test eax, eax ; тест на знак числа ответа
JZ plus
js minys
plus:
mov x, 0
JMP EndProg
minys:
neg eax ; для перевода в строку
mov x, 1
JMP EndProg
EndProg:
; eax - ответ на поставленную задачу, целая часть
; осталось вывести его на экран, преобразовав в строку с учётом того,
; что число может превышать 32-бита, т.е. стандартные функции с ним работать не могут
; подготовим вспомогательные данные
mov esi, BSIZE ; устанавливаем счётчик цикла равным длине максимального десятичного числа, помещающегося в 64-бита
mov ebx, edx ; копируем в ebx значение edx для дальнейшего оперирования обеими копиями значения
mov ecx, 10 ; для извлечения минимального десятичного числа будем делить на 10
nxt:
dec esi ; позиция следующего символа
xchg eax, ebx ; делим ...
xor edx, edx ; ... старшую ...
div ecx ; половину
xchg eax, ebx ; сохраняем частное
div ecx ; и делим остаток + младшую половину
add dl, 48 ; преобразуем в код соответствующего ASCII-символа
mov numRes[esi], dl ; сохраняем символ в буфер
mov edx, ebx ; возвращаем частное в edx
or edx, eax ; если оба частных равны нулю...
jnz nxt ; пойдём к следующей по порядку инструкции, иначе вернёмся в начало цикла
test x, 1 ; тест на знак числа ответа
jz pls
jnz mns
pls:
invoke crt_printf, ADDR formatStr, ADDR msgInputRes ; текст-пояснение 'Result is'
JMP EProg
mns:
invoke crt_printf, ADDR formatStr, ADDR msgInputResm ; текст-пояснение 'Result is -'
JMP EProg
EProg:
mov edx, offset numRes ; запоминаем адрес начала массива
add edx, esi ; добавляем смещение до первого символа, теперь в edx адрес первого символа строки результата
invoke crt_printf, ADDR formatStr, edx ; выводим результат вычислений на экран (десятичное число) целая часть
; вывод на экран дробной части
cmp edi, 0
jl mesgg ; <
jg mesgg ; >
jz mesg ; =
mesg:
invoke crt_printf, ADDR formatStr, ADDR msgInputOst ; если дробной части нет
JMP EndPrg
mesgg:
mov eax, edi ; если она есть
xor edx, edx
xor esi, esi
xor dl, dl
mov esi, BSIZE ; устанавливаем счётчик цикла равным длине максимального десятичного числа, помещающегося в 64-бита
mov ebx, edx ; копируем в ebx значение edx для дальнейшего оперирования обеими копиями значения
mov ecx, 10 ; для извлечения минимального десятичного числа будем делить на 10
nxtt:
dec esi ; позиция следующего символа
xchg eax, ebx ; делим ...
xor edx, edx ; ... старшую ...
div ecx ; половину
xchg eax, ebx ; сохраняем частное
div ecx ; и делим остаток + младшую половину
add dl, 48 ; преобразуем в код соответствующего ASCII-символа
mov numRes[esi], dl ; сохраняем символ в буфер
mov edx, ebx ; возвращаем частное в edx
or edx, eax ; если оба частных равны нулю...
jnz nxtt ; пойдём к следующей по порядку инструкции, иначе вернёмся в начало цикла
invoke crt_printf, ADDR formatStr, ADDR msgInputOstt ; выводим знак ","
mov edx, offset numRes ; запоминаем адрес начала массива
add edx, esi ; добавляем смещение до первого символа, теперь в edx адрес первого символа строки результата
invoke crt_printf, ADDR formatStr, edx ; выводим само число
JMP EndPrg
EndPrg:
ret ; возврат управления вызвавшей программе
arifm endp ; конец процедуры arifm
end start ; выполнение программы начнётся с метки start