- •О десский национальный морской университет
- •7.080401 "Информационные управляющие системы и технологии",
- •7.080402 "Информационные технологии проектирования"
- •Введение
- •Лабораторная работа №1 структура ехе-программы на ассемблере. Подготовка к выполнению Теоретические сведения
- •Задание
- •Лабораторная работа №2 использование служебных подпрограмм. Циклы. Формирование и вывод на экран строки ascii- символов Теоретические сведения
- •Inc al ; увеличиваем al (код символа) на 1
- •Задание
- •Лабораторная работа №3 управление курсором при выводе. Вложенные циклы. Формирование и вывод на экран таблицы символов ascii Теоретические сведения
- •Задание
- •Лабораторная работа №4 посимвольный ввод с клавиатуры. Анализ нажатия функциональных клавиш и комбинаций Теоретические сведения
- •Задание
- •Лабораторная работа №5 ввод с клавиатуры и обработка символьных строк (пароль) Теоретические сведения
- •Задание
- •Лабораторная работа №6 процедуры. Табличная трансляция. Перевод двоичных данных в символьную форму Теоретические сведения
- •Задание
- •Лабораторная работа №7 работа с файлами Теоретические сведения
- •Задание
Лабораторная работа №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$-строками.