Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SP_Lab_1.doc
Скачиваний:
3
Добавлен:
18.08.2019
Размер:
361.47 Кб
Скачать

Лабораторная работа №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$-строками.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]