ИСПОЛЬЗОВАНИЕ СЛУЖЕБНЫХ ПОДПРОГРАММ. ЦИКЛЫ. ФОРМИРОВАНИЕ И ВЫВОД НА ЭКРАН СТРОКИ ASCII- СИМВОЛОВ
Одесский национальный морской университет Кафедра информационных технологий А. Д. Бодарев, СИСТЕМНОЕ ПРОГРАММИРОВАНИЕ И ОПЕРАЦИОННЫЕ СИСТЕМЫ (НАЧАЛА АССЕМБЛЕРА) Методические указания и задания к лабораторным работам для студентов стационара, обучающихся по специальностям 7.080401 "Информационные управляющие системы и технологии", 7.080402 "Информационные технологии проектирования" 2-й курс, 2-й семестр Одесса 2010
ПРЕДИСЛОВИЕ
Цель выполнения заданий по данным лабораторным работам — закрепление теоретических знаний курса практическими примерами и приобретение навыков программирования на языке ассемблера.
В каждой работе рассматривается одно из средств системного программирования на ассемблере для IBM PC и с помощью него решается какая-либо практическая задача. В качестве инструмента для выполнения работ используется пакет TASM фирмы Borland, примеры приводятся в соответствии с режимом компиляции MASM данного пакета.
Данный курс во многом основывается на дисциплине "Архитектура ЭВМ", который, впрочем, не входит в программу указанных специальностей. Ниже во введении среди прочих приводятся общие сведения из этой дисциплины, знание которых весьма желательно.
Выполнение каждой лабораторной работы включает в себя следующие этапы: ознакомление с кратким теоретическим материалом; выбор варианта задания; продумывание путей его решения; воплощение алгоритма посредством блок-схемы или программы на псевдоязыке; построение ключевых фрагментов ассемблерной программы на черновике; полная реализация программы на рабочем месте, включая комментирование, настройку и отладку; оформление протокола, содержащего задание и текст программы; защита протокола в указанный срок.
|
|
ВВЕДЕНИЕ
Системное программирование, как правило, осуществляется на языке низкого уровня. Одним из языков низкого уровня является язык ассемблера (ассемблер). В его основе лежит непосредственное использование команд центрального процессора для создания программ. Кроме того, структура программы и процедура подготовки ее к выполнению приближены к архитектурным особенностям операционной системы и, таким образом, реализуют низкий уровень доступа к ресурсам. В результате системный программист получает наиболее полный контроль над процессами, происходящими как при подготовке программы к выполнению, так и при ее выполнении.
Команды процессора соответствуют отдельным мнемоническим инструкциям языка ассемблера. Большинство из них ориентировано на обработку двоичных данных, хранящихся в регистрах внутри процессора или в ячейках основной памяти. В соответствии с характером обработки выделяют группы команд: пересылки, арифметические, логические, сдвига, передачи управления и другие. Типы обрабатываемых данных чаще связываются с размерами двоичных ячеек, отводимых для их хранения, и реже — с их смысловым значением (числа, символы, адреса, команды). Ассемблер на уровне инструкций определения данных поддерживает типы "байт", "слово" (2 байта), "двойное слово" (4 байта) и другие. При программировании в реальном режиме процессора (соответствующем процессору 8086) основным типом является 16-битное слово.
|
|
Регистры процессора — его внутренние двухбайтовые ячейки — используются в основном для кратковременного хранения обрабатываемых данных небольшого размера. Использование регистров при обработке данных предпочтительно в связи с быстрым к ним доступом. Обращение к регистрам осуществляется по именам. Наиболее свободный доступ обеспечивается к регистрам общего назначения: AX, BX, CX, DX, SI, DI, SP и BP.
Для продолжительного размещения массивов данных и команд программы служит основная (оперативная) память, представляющая собой совокупность байтовых ячеек. Обращение к ячейкам памяти производится по уникальным номерам ячеек — адресам. Язык ассемблера позволяет присваивать адресам данных и команд имена. Современные реализации ассемблеров (в том числе TASM) позволяют именовать также участки исходного теста программы и потому являются макроассемблерами.
|
|
При обращении к памяти используются сегменты — участки памяти с относительной 16-битной адресацией. Полный адрес ячейки определяется в виде пары 16-битных адресов: сегментного адреса, определяющего положение сегмента в памяти, и относительного адреса, определяющего положение ячейки внутри сегмента. Сегментные адреса содержатся в сегментных регистрах CS, DS, ES и SS и указывают соответственно на сегменты команд, данных, дополнительных данных и стека. Относительные адреса указываются в соответствии с режимами адресации памяти. В случае прямой адресации относительный адрес указывается в виде константы, помещаемой в код машинной команды. В случае косвенной адресации относительный адрес определяется с помощью одного или двух регистров общего назначения (в 8086 — только BX, BP, SI или DI). Полные адреса записываются в виде адресных пар "сегментный регистр:относительный адрес". В большинстве случаев сегментный регистр не указывается, подразумеваясь по умолчанию.
|
|
Кроме регистров общего назначения и сегментных процессор 8086 имеет два специальных регистра: флагов (Flags) и указатель команд (IP). Указатель команд всегда содержит относительный адрес команды (в сегменте команд), подлежащей выполнению. Флаги представляют собой отдельные биты, которые могут быть установлены (= 1) или сброшены (= 0), индицируя тем самым определенное состояние результата некоторого действия (флаги CF, AF, OF, ZF, PF, SF) или задавая режим работы процессора (флаги DF, IF, TF).
Лабораторная работа №1 СТРУКТУРА ЕХЕ-ПРОГРАММЫ НА АССЕМБЛЕРЕ. ПОДГОТОВКА К ВЫПОЛНЕНИЮ
Теоретические сведения
Исходный текст программы на языке ассемблера должен храниться в неформатированном текстовом файле с коротким именем (до 8 латинских символов) и расширением ASM. Для его создания или редактирования удобно воспользоваться редактором, встроенным в файловую оболочку.
Обработка исходного файла осуществляется программами ассемблер и редактор связей (компоновщик). В пакете TASM эти программы реализованы в виде утилит командной строки (консоли). В простейшем случае ассемблер-транслятор осуществляет перевод мнемонических команд ASM-файла в объектный код (файл с расширением OBJ), а редактор связей преобразует OBJ-файл в исполнимый файл (EXE или COM). Эти операции называются ассемблированием (или трансляцией) и компоновкой соответственно. После завершения работы ассемблер и компоновщик выводят на экран диагностические сообщения в текстовом режиме.
Каждая инструкция исходного файла записывается в отдельной строке. В общем случае строка включает идентификатор, инструкцию, операнды инструкции и комментарии. Отдельные части строки разделяются табуляциями, так что образуются соответствующие колонки:
идентификатор инструкция операнды ; комментарий
Например, обнуление регистров данных процессора может выглядеть так:
initial: mov ax, 0 ; обнуление регистра AX
mov bx, ax ; обнуление регистра BX
mov cx, ax ; обнуление регистра CX
mov dx, ax ; обнуление регистра DX
Команды процессора 8086 могут иметь от 0 до 2 операндов. Идентификаторы и комментарии независимы от команд и указываются по мере необходимости. Начало комментария обозначается символом ";". Идентификатор, указываемый перед командой процессора, оканчивается двоеточием и является меткой — символьным обозначением адреса команды. С помощью меток можно осуществлять переходы к соответствующим командам.
Кроме процессорных команд в колонке инструкций могут записываться директивы — указания ассемблеру-транслятору, выполняемые им в процессе ассемблирования. К часто используемым, в частности, относятся директивы определения данных различных типов. Например, описание байтовой ячейки CELL и инициализация ее нулевым значением будет выглядеть так:
cell db 0 ; определение нулевого байта в памяти
В данном случае директива DB (Define Byte) указывает ассемблеру на необходимость определения в объектном модуле нулевой байтовой ячейки (переменной). Имя CELL соответствует относительному адресу этой ячейки. После запуска исполнительного модуля в памяти будет отведена байтовая ячейка и заполнена нулевым значением. Часто также используется директива определения словных переменных DW, директивы сегментации (см. далее).
Команды, директивы, имена регистров являются зарезервированными словами. В качестве идентификаторов можно использовать любые слова, кроме зарезервированных, и не начинающиеся с цифр.
Идентификаторы представляют собой мнемонические обозначения некоторых констант в программе. Константы могут записываться также в виде чисел и кодов символов (ASCII). Запись числа начинается с цифры (от 0 до 9). Числа могут записываться в разных системах счисления. По умолчанию используется десятичная система. После 16-ричных чисел указывается буква "h", после двоичных — "b". Символьные описания заключаются в одинарные кавычки. Каждый символ в кавычках соответствует константе, равной ASCII-коду этого символа. Ниже приведены несколько примеров с использованием констант:
my_var db 65, 41h, 'A' ; три байта с одинаковым содержимым
my_bin db 3 dup(1000001b) ; такие же три байта, но уже по другому адресу
my_address dw my_var ; слово со значением адреса переменной my_var
my_string db 'Моя строка' ; 10 байт со значениями кодов букв 'М', 'о'...
copying: mov al, [my_string] ; копирование в регистр AL кода буквы 'М'
mov ah, [my_string+1] ; копирование в регистр AH кода буквы 'о'
jmp copying ; переход по метке copying к команде mov
Операционная система DOS поддерживает два вида исполнимых файлов: ЕХЕ и СОМ. По умолчанию редактор связей TLINK генерирует ЕХЕ-файл, как более общий. ЕХЕ-программа может включать произвольное количество сегментов памяти. Обычно используется три сегмента: команд, данных и стека. Каждый из сегментов используется для доступа к соответствующей информации. Исходный текст должен содержать директивы, определяющие структуру сегментов программы. Имеется два способа описания данной структуры: с помощью моделей памяти и с помощью директив явной сегментации. Второй способ является стандартным и обеспечивает бόльшую наглядность и более гибкие возможности при определении структуры сегментов. Для явной сегментации используются директивы SEGMENT (начало сегмента), ENDS (конец сегмента) и ASSUME. Например, для описания сегмента команд (кода) с именем COMMANDS могут быть использованы следующие директивы:
commands segment ; начало описания сегмента команд
assume cs:commands
[. . .] ; тело сегмента
commands ends ; конец описания сегмента команд
Директива ASSUME указывается только в сегменте команд и служит для установления соответствия между сегментными регистрами и именами описанных сегментов, в данном случае между регистром CS и именем COMMANDS. При запуске исполняемого модуля регистр CS будет заполнен соответствующим значением сегментного адреса.
Завершается описание программы директивой END с указанием метки входа, с которой необходимо начинать выполнение.
Совокупность этих директив описывается в программах практически без изменений, поэтому имеет смысл один раз создать файл с их описанием, а затем использовать его как шаблон для создания конечных программ.
Структура типичной трехсегментной ЕХЕ-программы может выглядеть так:
; Данные
my_data segment
[. . .] ; тело сегмента данных
my_data ends
; Стек
my_stack segment stack ; описание сегмента стека
dw 32 dup(?) ; резервирование места для стека
my_stack ends
; Код
my_commands segment
assume cs:my_commands
start:
[. . .] ; исполняемая часть программы (команды)
my_commands ends
end start ; конец программы, метка входа
В готовой программе вместо символов [. . .] будут подставлены инструкции, составляющие тело каждого сегмента. Последовательность описания сегментов в большинстве случаев может быть любой (например, сегмент данных может описываться после сегмента команд).
Строение исполняемой части программы должно подчиняться правилам операционной системы, поскольку последняя служит базой для ее запуска, выполнения и завершения. В соответствии с особенностями DOS в обычных ЕХЕ-программах для обеспечения их корректной работы требуется производить следующие действия: настройку сегментного регистра DS на сегмент данных (автоматически она не производится) и вызов функции DOS завершения программы. Эти действия также можно включить в состав шаблона программы. Ниже приводится окончательный вид одного из вариантов шаблона ЕХЕ-программы, включающей три сегмента — данных, стека и кода:
; Листинг 1. Шаблон трехсегментной ЕХЕ-программы на ассемблере
; Данные
my_data segment
my_title db 'Пример строки$'
my_data ends
; Стек
my_stack segment stack ; описание сегмента стека
dw 32 dup(?) ; резервирование 32 слов для стека
my_stack ends
; Код
my_commands segment
assume cs:my_commands, ds:my_data
begin: mov ax, my_data ; занесение адреса сегмента my_data
mov ds, ax ; в сегментный регистр ds
[. . .] ; (содержательная часть программы)
exit: mov ah, 4Ch ; функция завершения программы
int 21h
my_commands ends
end begin ; конец программы, метка входа
Команды инициализации регистра DS (две команды MOV) позволяют в дальнейшем обращаться к определенным в сегменте MY_DATA данным. Данные не обязательно описывать в отдельном сегменте, необходимо лишь соблюдать правильное к ним обращение. Например, определение данных в сегменте команд должно идти до метки входа или после вызова функции завершения. Настройка регистра DS должна производиться на тот сегмент, в котором описаны нужные данные.
При резервировании памяти для стека использовался оператор "?", соответствующий неинициализированным данным. Отводимая таким образом память резервируется при запуске программы, но ничем не заполняется и содержит, как правило, неизвестные и ненужные нашей программе данные (мусор).
Предположим, листинг 1 был сохранен в файле под именем FRAME.ASM. Для проверки шаблона на наличие синтаксических ошибок можно выполнить его ассемблирование и компоновку при помощи команд
tasm /z /zi frame
tlink /x /v frame
по очереди набираемых в командной строке (о назначении параметров /z, /zi, /x и /v можно узнать, запуская ассемблер и компоновщик на выполнение без параметров).
Программа листинга 1 не выполняет никаких полезных действий, в частности, ничего не выводит на экран после запуска. Однако уже по ее корректному завершению (возврат в среду запуска) можно судить о ее правильности и работоспособности.
Если вместо символов [. . .] подставить следующие команды:
mov ah, 9 ; функция DOS вывода строки,
lea dx, my_title ; расположенной по указанному адресу
int 21h
и выполнить ассемблирование и компоновку программы, то после ее запуска на текстовый экран в текущую позицию курсора будет выведена строка "Пример строки". Эти команды осуществляют обращение к служебной функции вывода строки. Команда LEA загружает в регистр DX относительный адрес выводимой строки, а INT обеспечивает вызов функции. Использование служебных функций и вывод на экран будет подробнее рассмотрены далее; пока лишь отметим, что для правильной работы выводимая строка (здесь — MY_TITLE) должна оканчиваться значком "$". Такие строки иногда называются ASCII$-строками.
Задание
Составить шаблон ЕХЕ-программы под именем FRAME.ASM с определенным набором и порядком описания сегментов, проверить его работоспособность. На основе шаблона создать отдельную программу SURNAME.ASM: определить в сегменте данных ASCII$-строку со своей фамилией и вывести ее на экран функцией 9 DOS. Если в шаблоне по заданию сегмента данных нет, считать, что он совпадает с сегментом команд и описать строку в сегменте команд.
Варианты наборов сегментов:
1. Команд, данных, стека.
2. Данных, команд.
3. Стека, данных, команд.
4. Команд, стека, данных.
5. Данных, команд, стека.
6. Стека, команд, данных.
7. Команд, данных.
8. Стека, команд (строка — в начале).
9. Команд (строка — в конце), стека.
10. Команд (строка — в начале).
11. Стека, команд (строка — в конце).
12. Команд (строка — в начале), стека.
13. Команд (строка — в конце).
14. Данных, стека, команд.
Лабораторная работа №2
ИСПОЛЬЗОВАНИЕ СЛУЖЕБНЫХ ПОДПРОГРАММ. ЦИКЛЫ. ФОРМИРОВАНИЕ И ВЫВОД НА ЭКРАН СТРОКИ ASCII- СИМВОЛОВ
Теоретические сведения
Использование сервисных подпрограмм. Одним из основных средств, имеющихся в распоряжении системного программиста, является набор служебных подпрограмм базовой системы ввода-вывода (BIOS) и операционной системы (ОС). Их использование избавляет от необходимости настраиваться на работу каждого конкретного устройства, разрабатывать каждый раз заново служебные базовые процедуры и, поскольку эти подпрограммы являются стандартными, повышает совместимость программ.
В DOS доступ к служебным подпрограммам (их называют функциями) осуществляется с помощью программных прерываний, вызываемых по команде INT. В качестве операнда этой команды указывается номер прерывания.
Всего имеется 256 номеров, часть из них не используется. Подпрограмм значительно больше, поэтому их группируют и назначают номер прерывания целой группе. При вызове прерывания уточняют, к какой подпрограмме нужно обратиться. Чаще всего для этого используют регистр AH — в него заносят непосредственно перед вызовом прерывания номер функции. Пример вызова 1-й функции прерывания 21h:
mov ah, 1
int 21h
В результате выполнения команды INT управление передается программе обработки соответствующего прерывания (в данном случае 21h); по окончании работы управление возвращается в прерванную программу.
Многие функции нуждаются в определенных входных данных, определяющих результат ее работы. Регистры, через которые эти данные передаются, называются входными. Также функция может возвращать определенный результат — в выходных регистрах. Таким образом, в общем случае процедуру вызова N-й функции прерывания X можно записать так:
;заполнение входных регистров
mov ah, N ;AH = номер функции
int X ;вызов прерывания X
;анализ выходных регистров
По номеру прерывания можно определить, относится ли данная подпрограмма к BIOS, DOS или является пользовательской.
Большинство служебных подпрограмм DOS сведены в прерывание 21h. Среди них — функции для ввода с клавиатуры и вывода на экран, функции работы с файлами, управления памятью и процессами и другие. Информацию о номерах функций и прерываний, входных и выходных регистрах, а также описание действия функций можно найти в справочниках по MS-DOS.
В лабораторной работе 1 нами вызывались две функции: 9 — вывод ASCII$-строки на экран, и 4Ch — завершение работы программы. Функция 4Ch представляет собой исключение из правила: по окончании ее работы управление возвращается не вызвавшей программе, а родительскому процессу, запустившему программу (например, командному интерпретатору).
Вывод на экран. В DOS имеются стандартные функции вывода символьных данных: 2, 6, 9 и 40h. Ниже приводится их описание:
№ в AH | Описание | Вход | Выход |
2h | Вывод символа в STDOUT | DL = ASCII-код символа | - |
6h | Вывод символа в STDOUT | DL = ASCII-код символа (кроме 0FFh) | - |
9h | Вывод ASCII$-строки в STDOUT | DS:DX ® ASCII$-строку | - |
40h | Вывод ASCIIZ-строки на устройство или в файл | DS:DX ® ASCIIZ-строку; CX = длина строки в байтах; BX = № устройства/файла (1 для STDOUT) | CF = 0 при отсут-ствии ошибок; AX = число записанных байт |
Стандартным устройством вывода STDOUT в большинстве случаев является экран, однако можно перенаправлять вывод, то есть в качестве STDOUT использовать другое устройство или файл (например, команда tasm > options.lst перенаправит выводимый ассемблером список опций запуска в файл options.lst).
Циклы. Циклы в программах на ассемблере реализуются с помощью команд передачи управления JMP (безусловный переход), Jxx (условный переход) и LOOP ("петля").
С помощью команды JMP можно осуществлять переходы назад (так могут создаваться бесконечные циклы):
metka:
... ; (тело цикла)
jmp metka ; переход назад
или переходы вперед (обход определенного участка программы):
jmp metka ; переход вперед
...
metka:
Часто в тело цикла помещают команду условного перехода для обеспечения возможности выхода из цикла (или предусматривают возможность прерывания выполнения тела цикла по нажатию Ctrl-C или Ctrl-Break).
Команд условного перехода Jxx несколько (вместо xx указывается символ или набор символов, определяющих условие перехода). Как и в команде JMP, в качестве операнда указывается метка перехода, и эта метка может указываться как до команды перехода (переход назад), так и после (переход вперед).
Большинство из команд условных переходов передают управление на указанную метку в зависимости от состояния флагов процессора. Например, команда JZ metka передает управление на метку metka, если установлен флаг нуля (Jump if Zero, ZF = 1), JC — если установлен флаг переноса (Jump if Carry, CF = 1), а JS — если установлен флаг знака (Jump if Sign, SF = 1) и т. д. Если же соответствующий флаг сброшен, управление передается на следующую после Jxx команду. Также имеются команды, передающие управление на указанную метку, если соответствующий флаг сброшен (JNZ — Jump if Not Zero, ZF = 0; JNC — Jump if No Carry, CF = 0 и т. д.).
Чтобы пользоваться такими командами, необходимо знать, в каком состоянии может находиться определенный флаг и какие команды влияют на его состояние. Часто применяют схему использования команд условного перехода, при которой нет необходимости следить за флагами. Вот эта схема в виде фрагмента кода и блок-схемы:
metka:
...
cmp операнд1, операнд2
jxx metka
Команда CMP (Compare) производит сравнение операндов (с помощью вычитания второго из первого) и в соответствии с результатом сравнения формирует флаги (так же, как и команда обычного вычитания SUB). При этом в мнемоническом обозначении команд перехода указывается не проверяемый флаг, а результат сравнения. Например, команда JE передает управление на метку, если сравниваемые операнды были равны (Jump if Equal), а команда JNE – если не равны (Jump if Not Equal). (Если сравниваемые командой CMP операнды равны, то результат вычитания одного операнда из первого даст нулевой результат и установится флаг нуля ZF. Команда JE проверит этот флаг и передаст управление на метку точно так же, как и команда JZ. На самом деле JZ и JE — разные обозначения одной машинной команды процессора, созданные для удобства программирования).
Кроме команд JE (JNE) часто приходится пользоваться командами JA (Jump if Above — переход, если выше), JB (Jump if Below — переход, если ниже), JG (Jump if Greater — переход, если больше), JL (Jump if Less — переход, если меньше) и их антиподами JNA, JNB, JNG и JNL соответственно. Понятия "выше" и "ниже" относятся к сравнению беззнаковых операндов, а "больше" и "меньше" — знаковых (в дополнительном коде).
Цикл с предусловием организуется указанием команды Jxx в начале JMP-цикла, с постусловием — в конце (в любом случае до метки начала цикла должна быть проинициализирована переменная цикла).
; Цикл с предусловием
metka:
jxx exit
... ; (тело цикла)
jmp metka
exit:
; Цикл с постусловием
metka:
... ; (тело цикла)
jxx exit
jmp metka
exit:
Цикл, организованный только командой Jxx — всегда цикл с постусловием. Этот вариант цикла проще, чем организованный с помощью двух команд перехода.
Для образования цикла команд условного перехода часто нет необходимости вводить отдельную переменную для счетчика цикла, так как уже имеется какая-либо переменная (или даже несколько), циклически меняющая свое значение. Выход из цикла можно осуществить по достижении этой переменной определенного значения. Иначе обстоит дело с циклами, образованными при помощи команды LOOP. Эта команда специально предназначена для организации циклов и всегда использует регистр CX в качестве счетчика цикла.
В качестве операнда команды LOOP также указывается метка перехода. Команда LOOP уменьшает значение регистра CX на 1 и затем сравнивает его с нулем. Если значение СХ не равно 0, LOOP передает управление на указанную метку, если равно — управление передается на следующую за LOOP команду.
Перед началом цикла необходимо заполнить регистр СХ начальным значением N (пример ниже). При этом тело цикл будет выполнено N раз, а команда LOOP передаст управление на метку (N–1) раз.
; Цикл, повторяющийся N раз
mov cx, N
metka:
... ; (тело цикла)
loop metka
В качестве иллюстрации рассмотрим текст программы вывода на экран строки ASCII-символов с кодами от 32 до 255 (коды 0 - 31 часто используются как управляющие). Для заполнения области памяти используем LOOP-цикл, а для вывода полученной последовательности на экран – функцию вывода 40h int 21h. Использованию функции 9 в данном случае препятствует наличие в строке символа '$' (код 36), который интерпретируется функцией как признак конца строки.
; Листинг 2. Вывод строки ASCII-символов на экран
oursg segment
assume cs:oursg, ds:oursg
symb db 224 dup('*') ; резервируем место (строку) в памяти
begin:
mov ax, oursg ; сегментный адрес данных
mov ds, ax ; засылаем в DS
; Заполнение строки в памяти символами
mov cx, 224 ; число повторений цикла (256-32)
mov al, 32 ; начинаем с пробела (32)
mov si, 0 ; индекс внутри отведенной строки памяти
m: mov [symb+si], al ; пересылаем символ из AL в очередную позицию
; отведенной строки, затирая звездочку
inc al ; увеличиваем AL (код символа) на 1
inc si ; и индекс нашей строки (следующая позиция)
loop m ; повтор
; Вывод строки-результата на экран
mov ah, 40h ; номер функции DOS вывода строки
mov cx, 224 ; длина выводимой строки (в байтах)
mov bx, 1 ; 1 - вывод на экран
mov dx, offset symb ; относительный адрес выводимой строки
int 21h ; вызов DOS
; Завершение программы
mov ax, 4C00h ; AH = 4Ch, AL = 0 (код выхода)
int 21h
oursg ends
end begin
Для указания очередной позиции строки в памяти использовалась индексная адресация с регистром SI (можно было бы также использовать DI или BX). Указанный адрес начала строки (symb) складывается с содержимым регистра SI (индексирование), результат рассматривается как относительный адрес (offset), который в совокупности с сегментным адресом (содержимое регистра DS) дает полный адрес необходимой ячейки.
Другой возможный вариант — использование косвенной адресации без смещения, когда в регистр SI (DI или BX) помещается адрес начала строки, который затем так же в цикле увеличивается на 1:
mov [si], al ; засылаем символ в строку
inc si
(Команда INC производит увеличение операнда на 1. Для уменьшения операнда на 1 служит команда DEC).
Задание
Зарезервировать в памяти строку, заполнить ее в цикле ASCII-символами в диапазоне (32, …, 254) с указанным шагом, а затем выдать эту строку на экран при помощи функции 40h DOS (int 21h). В таблице вариантов указаны а) порядок следования кодов символов (от меньших к большим или наоборот, изменяющиеся на 1, 2 или 3), б) порядок заполнения строки (прямой — от младших байтов к старшим, или обратный — от старших к младшим), в) способ организации цикла (командой Jxx или LOOP, с пост- или предусловием). В протокол работы включить блок-схему программы.
Варианты:
№ вар. | последовательность | порядок заполнения | цикл |
1. | обратная с шагом 1 (254, 253, ..., 32) | прямой | Jxx с предусловием |
2. | прямая с шагом 1 (32, 33, ..., 254) | обратный | Jxx с постусловием |
3. | обратная с шагом 2 (254, 252, ..., 32) | прямой | LOOP |
4. | прямая с шагом 2 (32, 34, ..., 254) | обратный | Jxx с предусловием |
5. | обратная с шагом 3 (254, 251, ..., 32) | прямой | Jxx с постусловием |
6. | прямая с шагом 3 (32, 35, ..., 254) | обратный | LOOP |
7. | обратная с шагом 1 (254, 253, ..., 32) | обратный | Jxx с постусловием |
8. | прямая с шагом 1 (32, 33, ..., 254) | прямой | Jxx с предусловием |
9. | обратная с шагом 2 (254, 252, ..., 32) | обратный | LOOP |
10. | прямая с шагом 2 (32, 34, ..., 254) | прямой | Jxx с постусловием |
11. | обратная с шагом 3 (254, 251, ..., 32) | обратный | Jxx с предусловием |
12. | прямая с шагом 3 (32, 35, ..., 254) | прямой | LOOP |
13. | обратная с шагом 4 (254, 250, ..., 34) | обратный | Jxx с постусловием |
14. | прямая с шагом 4 (34, 38, ..., 254) | прямой | Jxx с предусловием |
Лабораторная работа №3
Дата добавления: 2018-04-05; просмотров: 825; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!