ИСПОЛЬЗОВАНИЕ СЛУЖЕБНЫХ ПОДПРОГРАММ. ЦИКЛЫ. ФОРМИРОВАНИЕ И ВЫВОД НА ЭКРАН СТРОКИ 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; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!