Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Длина непосредственных операндов



Формат кодирования

Основной формат кодирования команд на языке ассемблера имеет следующий вид:

 

[метка] команда [операнд(ы)]

 

Метка (если имеется), команда и операнд (если имеется) разделяются по крайней мере одним пробелом или символом табуляции. Максимальная длина строки – 132 символа. Примеры кодирования:

Метка Команда Операнд  
COUNT DB ; Имя, команда, один операнд
  MOV AX, 0 ; Команда, два операнда

Метки

Метка в языке Ассемблер может содержать следующие символы:

 

Буквы от A до Z и от a до z;

Цифры от 0 до 9;

Специальные символы знак вопроса (? );

точка (.) (только первый символ);

знак «коммерческое эт» (@);

подчеркивание ( _ );

доллар ($).

 

Первым символом в метке должна быть буква или специальный символ. Ассемблер не делает различия между заглавными и строчными буквами. Максимальная длина метки – 31 символ. Примеры меток: COUNT, PAGE25, $E10. Рекомендуется использовать описательные и смысловые метки. Все имена регистров, например, AX, DI или AL, являются зарезервированными и используются только для указания соответствующих регистров. Например, в команде

ADD AX, BX

ассемблер автоматически знает, что AX и BX относятся к регистрам. Однако в команде

MOV REGSAVE, AX

ассемблер воспримет имя REGSAVE только в том случае, если оно будет определено в сегменте данных.

Команда

Мнемоническая команда указывает ассемблеру, какое действие должен выполнить данный оператор. В сегменте данных команда определяет поле, рабочую область или константу. В сегменте кода команда определяет действие, например пересылка MOV или сложение ADD.

Операнд

Если команда специфицирует выполняемое действие, то операнд определяет начальное значение данных или элементы, над которыми выполняется действие по команде. Байт CNTR определен в сегменте данных и имеет нулевое значение в следующем примере:

CNTR DB 0; Определить байт с нулевым значением.

Команда может иметь один или два операнда или вообще быть без операндов. Рассмотрим следующие три примера:

Команда Операнд Комментарий

RET; Нет операндов.

INC CX; Увеличить CX (один операнд).

ADD AX, 12; Прибавить 12 к AX (два операнда).

Метка, команда и операнд не обязательно должны начинаться с какой-либо определенной позиции в строке. Однако рекомендуется записывать их в колонку для большего удобства при чтении программы.

Директивы ассемблера

Ассемблер имеет ряд операторов, которые позволяют управлять процессом ассемблирования и формирования листинга. Эти операторы называются псевдокомандами или директивами. Они действуют только в процессе ассемблирования программы и не генерируют машинных кодов.

 

 

Директивы управления листингом: PAGE и TITLE

Ассемблер содержит ряд директив, управляющих форматом печати (или листинга). Директивы PAGE и TITLE можно использовать в любой программе.

Директива PAGE

В начале программы нужно указать количество строк, распечатываемых на одной странице, и максимальное количество символов на одной строке. Для этой цели служит директива PAGE. Данной директивой устанавливается формат 60 строк на страницу и 132 символа в строке:

PAGE 60, 132

Количество строк на странице может быть в пределах от 10 до 255, а символов в строке – от 60 до 132. По умолчанию в ассемблере установлено PAGE 66, 80.

Предположим, что счетчик строк установлен на 60. В этом случае ассемблер, распечатав 60 строк, выполняет прогон листа на начало следующей страницы и увеличивает номер страницы на единицу. Кроме того, можно заставить ассемблер сделать прогон листа на конкретной строке, например в конце сегмента. Для этого необходимо записать директиву PAGE без операндов. Ассемблер автоматически сделает прогон листа при обработке директивы PAGE.

Директива TITLE

Для того чтобы вверху каждой страницы листинга печатался заголовок (титул) программы, используется директива TITLE в следующем формате:

TITLE текст

В качестве текста рекомендуется использовать имя программы, под которым она находится в каталоге на диске. Например, если программа называется ASMSORT, то можно использовать это имя и в описательном комментарии общей длиной до 60 символов:

TITLE ASMSORT – ассемблерная программа сортировки имен.

В ассемблере также имеется директива подзаголовка SUBTTL, которая может оказаться полезной для очень больших программ, содержащих много подпрограмм.

Директива SEGMENT

Любые ассемблерные программы содержат по крайней мере один сегмент – сегмент кода. В некоторых программах используются сегмент для стековой памяти и сегмент данных для определения данных. Ассемблерная директива для описания сегмента SEGMENT имеет следующий формат:

Имя Директива Операнд

имя SEGMENT [параметры]

.

.

имя ENDS

Имя сегмента должно обязательно присутствовать, быть уникальным и соответствовать соглашениям для имен в ассемблере. Директива ENDS означает конец сегмента. Директивы SEGMENT и ENDS должны иметь одинаковые имена. Директива SEGMENT может содержать три типа параметров: выравнивание, объединение и класс.

1. Выравнивание. Данный параметр определяет границу начала сегмента. Обычным значением является PARA, по которому сегмент устанавливается на границу параграфа. В этом случае начальный адрес кратен 16, т. е. имеет шестнадцатеричный адрес nnn0. В случае отсутствия этого операнда ассемблер принимает по умолчанию PARA.

2. Объединение. Этот элемент определяет, объединяется ли данный сегмент с другими сегментами в процессе компоновки после ассемблирования. Возможны следующие типы объединений: STACK, COMMON, PUBLIC, АТ-выражение и MEMORY. Сегмент стека определяется следующим образом:

имя SEGMENT PARA STACK

Если отдельно ассемблированные программы должны объединяться компоновщиком, то можно использовать типы объединений PUBLIC, COMMON и MEMORY. В случае, если программа не должна объединяться с другими программами, то указание этих типов должно быть опущено.

3. Класс . Данный элемент, заключенный в апострофы, используется для группирования относительных сегментов при компоновке:

имя SEGMENT PARA STACK ‘Stack’

Директива PROC

Сегмент кода содержит выполняемые команды программы. Кроме того, этот сегмент также включает в себя одну или несколько процедур, определенных директивой PROC. Сегмент, содержащий только одну процедуру, имеет следующий вид:

имя _ сегмента SEGMENT PARA

имя _ процедуры PROC FAR Сегмент

. кода

. с

. одной

RET процедурой.

имя _ процедуры ENDP

имя – сегмента ENDS

Имя процедуры должно обязательно присутствовать, быть уникальным и удовлетворять соглашениям по именам в ассемблере. Операнд FAR указывает загрузчику DOS, что начало данной процедуры является точкой входа для выполнения программы.

Директива ENDP определяет конец процедуры и имеет имя, аналогичное имени в директиве PROC. Команда RET завершает выполнение программы и в данном случае возвращает управление в DOS. Сегмент может содержать несколько процедур.

Директива ASSUME

Процессор использует регистр SS для вычисления физического адреса адресации вершины стека, регистр DS для адресации сегмента данных, регистр ES для адресации дополнительного сегмента данных и регистр CS для адресации сегмента кода. Ассемблеру необходимо сообщить назначение каждого сегмента. Для этого служит директива ASSUME, кодируемая в сегменте кода следующим образом:

Директива Операнд

ASSUME SS: им _ cтeк, DS: им _ дaн, CS: им _ кoд

Например, SS: им _ cтeк указывает, что ассемблер должен ассоциировать имя сегмента стека с регистром SS. Операнды могут записываться в любой последовательности. Регистр ES также может присутствовать среди операндов. Если программа не использует регистр ES, то его можно опустить или указать ES: NOTHING.

Директива END

Как уже показано, директива ENDS завершает сегмент, а директива ENDP завершает процедуру. Директива END в свою очередь полностью завершает всю программу:

Директива Операнд

END [имя _ процедуры]

Операнд может быть опущен, если программа не предназначена для выполнения, например если ассемблируются только определения данных, или эта программа должна быть скомпонована с другим (главным) модулем. Для обычной программы с одним модулем операнд содержит имя, указанное в директиве PROC, которое было обозначено как FAR.

Память и регистры

Рассмотрим особенности использования в командах имен, имен в квадратных скобках и чисел. В следующих примерах положим, что WORDA определяет слово в памяти:

MOV АХ, ВХ; Переслать содержимое ВХ в регистр АХ.

MOV АХ, WORDA; Переслать WORDA в регистр АХ.

MOV АХ, [ВХ]; Переслать содержимое памяти по

; адресу в регистре ВХ, в регистр АХ.

MOV АХ, 25; Переслать значение 25 в регистр АХ.

MOV АХ, [25]; Переслать содержимое по смещению 25.

Инициализация программы

Существует два основных типа загрузочных программ: ЕХЕ и СОМ. Рассмотрим требования к ЕХЕ-программам. Для инициализации ассемблерной ЕХЕ-программы в системе DOS необходимо:

1) указать ассемблеру, какие сегментные регистры должны соответствовать сегментам;

2) сохранить в стеке адрес, находящийся в регистре DS, когда программа начнет выполнение;

3) записать в стек нулевой адрес;

4) загрузить в регистр DS адрес сегмента данных.

Выход из программы и возврат в DOS сводится к использованию команды RET. На рис. 1.1а проиллюстрированы требования к инициализации и выходу из программы.

CODESG SEGMENT PARA ‘CODE’

BEGIN PROC FAR

ASSUME CS: CODESG, DS: DATASG, SS: STACKG

PUSH DS; Записать DS в стек.

XOR AX, AX; Установить ноль в AX.

PUSH AX; 3аписать ноль в стек.

MOV AX, DATASG; Занести адрес.

MOV DS, AX; DATASG в DS.

.

.

.

RET; Возврат в DOS.

BEGIN ENDP

CODESG ENDS

END BEGIN

Рис. 1.1а. Инициализация ЕХЕ-программы

Иногда для выхода в DOS используют стандартное прерывание, которое поддерживается системой DOS. Это прерывание можно использовать в любой точки программы. При этом нет необходимости в записи в стек адреса возврата.

Программа выглядит следующим образом:

CODESG SEGMENT PARA ‘CODE’

BEGIN PROC FAR

ASSUME CS: CODESG, DS: DATASG, SS: STACKG

MOV AX, DATASG; Занести адрес.

MOV DS, AX; DATASG в DS.

.

.

.

MOV AX, 4C00H

INT 21H; Возврат в DOS.

BEGIN ENDP

CODESG ENDS

END BEGIN

Рис. 1.1б. Инициализация ЕХЕ-программы

1. ASSUME – это ассемблерная директива, которая устанавливает для ассемблера соответствие между конкретными сегментами и сегментными регистрами. В данном случае CODESG соответствует CS, DATASG-DS и STACKSG-SS. Сегменты DATASG и STACKSG не определены в этом примере, но они могли быть представлены следующим образом:

STACKSG SEGMENT PARA STACK Stack ‘Stack’

DATASG SEGMENT PARA ‘Data’

Ассоциируя сегменты с сегментными регистрами, ассемблер сможет определить смещения к отдельным областям в каждом сегменте. Например, каждая команда в сегменте кодов имеет определенную длину: первая команда имеет смещение 0, и если это двухбайтовая команда, то вторая команда будет иметь смещение 2 и т. д.

2. Загрузочному модулю в памяти непосредственно предшествует 256-байтовая (100Н) область, называемая префиксом программного сегмента PSP. Программа загрузчика использует регистр DS для установки адреса начальной точки PSP. Пользовательская программа должна сохранить этот адрес, поместив его в стек. Позже команда RET возьмет этот адрес из стека для возврата в DOS.

3. В системе требуется, чтобы следующее значение в стеке являлось нулевым адресом, точнее, смещением. Для этого команда SUB очищает регистр АХ, вычитая его из этого же регистра АХ, а команда PUSH заносит это значение в стек.

4. Загрузчик DOS устанавливает правильные адреса стека в регистре SS и сегмента кодов в регистре CS. Поскольку программа загрузчика использует регистр DS для других целей, необходимо инициализировать регистр DS двумя командами MOV, как показано на рис. 1.1а и рис. 1.1б. В разделе 1.6. «Пример исходной программы» детально поясняется инициализация регистра DS.

5. Команда RET обеспечивает выход из пользовательской программы и возврат в DOS, используя для этого адрес, записанный в стек в начале программы командой PUSH DS. Другим, часто используемым способом завершения программы, является команда INT 21Н.

Каждая программа фактически имеет аналогичные шаги инициализации, так что их можно дублировать всякий раз при кодировании программ.

Пример исходной программы

На рис. 1.2 обобщены предыдущие сведения в простой исходной программе на ассемблере. Программа содержит сегмент стека STACKSG и сегмент кода CODESG.

STACKSG SEGMENT PARA STACK ‘Stack’

DB 12 DUP ( ‘STACKSEG’ )

STACKSG ENDS

CODESG SEGMENT PARA ‘Code’

BEGIN PROC FAR

ASSUME SS: STACKSG, CS: CODESG, DS: NOTHING

MOV AX, 0123H; 3аписать 0123 в АХ.

ADD AX, 0025H; Прибавить 25 к AX.

MOV BX, AX; Переслать AX в BX.

ADD BX, AX; Прибавить BX к AX.

MOV CX, BX; Переслать BX в CX.

Рис. 1.2. Пример исходной программы на ассемблере

SUB CX, AX; Вычесть AX из CX.

MOV AX, 4C00H

INT 21H; Возврат в DOS.

BEGIN ENDP; Конец процедуры.

CODESG ENDS; Конец сегмента.

END BEGIN; Конец программы.

Рис. 1.2.Окончание

Сегмент STACKSG содержит один элемент DB (определить байт), который определяет 12 копий слова ‘STACKSEG’. В последующих программах стек не определяется таким способом, но при использовании отладчика для просмотра ассемблированной программы на экране данное определение помогает локализовать стек.

Сегмент кода CODESG содержит выполняемые команды программы, хотя первая директива ASSUME не генерирует кода. Директива ASSUME назначает регистр SS для STACKSG и регистр CS для CODESG. В действительности эта директива сообщает ассемблеру, что для адресации в STACKSG необходимо использовать адрес в регистре SS и для адресации в CODESG – адрес в регистре CS. Системный загрузчик при загрузке программы с диска в память для выполнения устанавливает действительные адреса в регистрах SS и CS. Программа не имеет сегмента данных, так как в ней нет определения данных и соответственно в ASSUME нет необходимости ассигновать регистр DS.

ОПРЕДЕЛЕНИЕ ДАННЫХ

Сегмент данных предназначен для определения констант, рабочих полей и областей для ввода-вывода. В соответствии с имеющимися директивами в ассемблере разрешено определение данных различной длины, например, директива DB определяет байт, а директива DW определяет слово. Элемент данных может содержать непосредственное значение или константу, определенную как символьная строка или как числовое значение.

Другой способ определения константы – непосредственное значение, т. е. значение, указанное прямо в ассемблерной команде, например:

MOV AL, 20H

В этом случае шестнадцатеричное число 20 становится частью машинного объектного кода. Непосредственное значение ограничено одним байтом или одним словом, но там, где его можно применять, оно более эффективно, чем использование константы.

2.1. Директивы определения данных

Ассемблер обеспечивает два способа определения данных: во-первых, через указание длины данных; во-вторых, по их содержимому. Рассмотрим основной формат определения данных:

[имя] Dn выражение

Имя элемента данных необязательно (это указывается квадратными скобками), но если в программе имеются ссылки на некоторый элемент, то это делается посредством имени.

Для определения элементов данных имеются следующие директивы: DB (байт), DW (слово), DD (двойное слово), DQ (учетверенное слово) и DT (десять байтов). Выражение может содержать константу

А DB 25

или знак вопроса для неопределенного значения

B DB?

Выражение может содержать несколько констант, разделенных запятыми и ограниченных только длиной строки:

С DB 11, 12, 13, 14, 15, 16, ...

Ассемблер определяет эти константы в виде последовательности смежных байтов. Ссылка по имени С указывает на первую константу 11, по С+1 – на вторую константу 12. (С можно представить как С + 0). Например, команда

MOV AL, С+3

загружает в регистр AL значение 14 (0ЕН). Выражение допускает также повторение константы в следующем формате:

[имя] Dn число повторений DUP ( выражение )...

Следующие три примера иллюстрируют повторение:

DW 10 DUP (? ); Десять неопределенных слов.

DB 5 DUP ( 14 ); Пять байт, содержащих 0ЕН.

DB 3 DUP ( 4 DUP ( 8 ) ); Двенадцать восьмерок.

В третьем примере сначала генерируются четыре копии десятичной 8 (8888), затем это значение повторяется три раза, давая в результате двенадцать восьмерок. Выражение может содержать символьную строку или числовую константу.

Символьные строки

Символьная строка используется для описания таких данных, как, например, имена людей или заголовки страниц. Содержимое строки отмечается одиночными кавычками, например ‘PC’, или двойными кавычками “PC”. Ассемблер переводит символьные строки в объектный код в обычном формате ASCII.

Символьная строка определяется только директивой DB, в которой указывается более двух символов в нормальной последовательности слева направо. Директива DB представляет единственно возможный формат для определения символьных данных. На рис. 2.1 приведены некоторые примеры.

DATASG SEGMENT PARA ‘Data’

; Определение байта – DB:

A DB? ; Не инициализировано.

B DB ‘Personal Computer’; Символьная строка.

C DB 32; Десятичная константа.

D DW 20H; Шестнадцатеричная константа.

Рис. 2.1. Определение символьных строк и числовых величин

E DB 01011001B; Двоичная константа.

DATASG ENDS

END

Рис. 2.1. Окончание

Числовые константы

Числовые константы применяются для арифметических значений и для адресов памяти. Для описания числовой константы кавычки не ставятся. Ассемблер преобразует все числовые константы в шестнадцатеричные и записывает байты в объектном коде в обратной последовательности – справа налево. Ниже показаны различные числовые форматы.

Десятичный формат. Десятичный формат допускает десятичные цифры от 0 до 9 и обозначается последней буквой D, которую можно не указывать, например 125 или 125D. Несмотря на то, что ассемблер позволяет кодирование в десятичном формате, он преобразует эти значения в шестнадцатеричный объектный код. Десятичное число 125 преобразуется в 7DH.

Шестнадцатеричный формат. Шестнадцатеричный формат допускает цифры от 0 до F и обозначается в конце буквой Н. Так как ассемблер полагает, что с буквы начинаются идентификаторы, то первой цифрой шестнадцатеричной константы должна быть цифра от 0 до 9. Например, 2ЕН или 0FFFH ассемблер преобразует соответственно в 2Е и FF0F ( байты во втором случае записываются в объектный код в обратной последовательности ).

Двоичный формат. Двоичный формат допускает двоичные цифры 0 и 1 и обозначается в конце буквой В. Двоичный формат обычно используется для более четкого представления битовых значений в логических командах AND, OR, XOR и TEST. Десятичное 12, шестнадцатеричное С и двоичное 1100В генерируют один и тот же код: шестнадцатеричное 0СН или двоичное 00001100B в зависимости от того, как вы рассматриваете содержимое байта.

Восьмеричный формат. Восьмеричный формат допускает восьмеричные цифры от 0 до 7 и обозначается последней буквой Q или O, например 253Q. На сегодня восьмеричный формат используется весьма редко.

Десятичный формат с плавающей точкой. При записи символьных и числовых констант следует помнить, что, например, символьная константа, определенная как DB ‘12’, представляет символы ASCII и генерирует 3132Н, а числовая константа, определенная как DB 12, представляет двоичное число и генерирует 0СН. Все десятичные числа с плавающей точкой записываются с точкой (1.2345, 3.78Е-3, 3.0). Необходимо обратить внимание, что целые числа в вещественном формате записываются обязательно с точкой, например 123.0.

Директива определения байта (DB)

Из различных директив, определяющих элементы данных, чаще используется директива DB (определить байт). Символьное выражение в директиве DB может содержать строку символов любой длины. Обратите внимание, что константа B содержит символьную строку ‘Personal Computer’. Объектный код показывает символы кода ASCII для каждого байта.

Числовое выражение в директиве DB может содержать одну однобайтовую константу или более. Один байт выражается двумя шестнадцатеричными цифрами. Наибольшее положительное шестнадцатеричное число в одном байте – это 7F, все «большие» числа от 80 до FF представляют отрицательные значения. В десятичном счислении эти пределы выражаются числами +127 и –128.

Директива определения слова (DW)

Директива DW определяет элементы, которые имеют длину в одно слово (два байта). Символьное выражение в DW ограничено двумя символами, которые ассемблер представляет в объектном коде так, что, например, ‘PC’ становится 'СР'. Для определения символьных строк директива DW имеет ограниченное применение.

Числовое выражение в DW может содержать одну или более двухбайтовых констант. Два байта представляются четырьмя шестнадцатеричными цифрами. Наибольшее положительное шестнадцатеричное число в двух байтах – это 7FFFH все «большие» числа от 8000H до FFFFH представляют отрицательные значения. В десятичном исчислении эти пределы выражаются числами + 32767 и – 32768.

Для форматов директив DW, DD и DQ ассемблер преобразует константы в шестнадцатеричный объектный код, но записывает его в обратной последовательности. Таким образом, десятичное значение 12345 преобразуется в 3039Н, но записывается в объектном коде как 3930.

Директива определения двойного слова (DD)

Директива DD определяет элементы, которые имеют длину в два слова (четыре байта). Числовое выражение может содержать одну константу или более, каждая из которых имеет максимально четыре байта (восемь шестнадцатеричных цифр). Наибольшее положительное шестнадцатеричное число в четырех байтах – это 7FFFFFFFH все «большие» числа от 80000000H до FFFFFFFFH представляют отрицательные значения. В десятичном исчислении эти пределы выражаются числами + 2147483647 и – 2147483648.

Ассемблер преобразует все числовые константы в директиве DD в шестнадцатеричное представление, но записывает объектный код в обратной последовательности. Таким образом, десятичное значение 12345 преобразуется в 00003039Н, но записывается в объектном коде как 39300000.

Директива определения поля из четырех слов (DQ)

Директива DQ определяет элементы, имеющие длину четыре слова (восемь байтов). Числовое выражение может содержать одну или более констант, каждая из которых имеет максимум восемь байтов или 16 шестнадцатеричных цифр. Наибольшее положительное шестнадцатеричное число – это 7 и далее пятнадцать цифр F.

Ассемблер преобразует все числовые константы в директиве DQ в шестнадцатеричные представления, но записывает объектные коды в обратной последовательности, как и в директивах DD и DW.

Обработка ассемблером символьных строк в директиве DQ аналогична обработке директив DD и DW.

Директива определения десяти байтов (DТ)

Директива DT определяет элементы данных, имеющие длину десять байтов. Назначение этой директивы связано с «упакованными десятичными» числовыми значениями. По директиве DT генерируются различные константы в зависимости от версии ассемблера. Для практического применения ознакомьтесь с руководством по имеющемуся у вас ассемблеру.

Непосредственные операнды

Команда MOV АХ, 0123Н пересылает непосредственную константу 0123Н в регистр АХ. Трехбайтовый объектный код для этой команды В82301, где В8 обозначает «переслать непосредственное значение в регистр АХ», а следующие два байта содержат само значение. Многие команды имеют два операнда: первый операнд может быть регистром или адресом памяти, а второй – непосредственной константой.

Использование непосредственного операнда более эффективно, чем определение числовой константы в сегменте данных и организация ссылки на нее в операнде команды MOV, например:

Сегмент данныхАМТ1 DW 0123Н

Сегмент кодовMOV АХ, АМТ1

Непосредственные форматы

Непосредственная константа может быть шестнадцатеричной, например 0123Н; десятичной, например 291 (которую ассемблер конвертирует в 0123Н); или двоичной, например 100100011В (которая преобразуется в 0123Н).

На рис. 2.2 приведены примеры допустимых команд с непосредственными операндами. Поскольку сейчас данные примеры не предназначены для выполнения, в них опущены определение стека и инициализация сегментных регистров.

 

 

DATASG SEGMENT PARA ‘Data’

A DB?

B DW?

DATASG ENDS

CODESG SEGMENT PARA ‘Code’

BEGIN PROC FAR

ASSUME CS: CODESG, DS: DATASG

MOV BX, 275; Пересылка.

СМР AL, H; Сравнение.

ADC AL, 5; Сложение с переносом.

ADD BH, 12; Сложение.

SBB AL, 5; Вычитание с заемом.

SUB FLD1, 5; Вычитание.

RCL BL, 1; Ротация влево с переносом.

RCR АН, 1; Ротация вправо с переносом.

ROL FID2, 1; Ротация влево.

ROR AL, 1; Ротация вправо.

SAL СХ, 1; Сдвиг влево.

SAR BX, 1; Арифметический сдвиг вправо.

SHR FLD1, 1; Сдвиг вправо.

AND AL, 00101100B; Логическое «И».

OR BH, 2AH; Логическое «ИЛИ».

OR FLD1, 23H; Логическое «ИЛИ» (память).

BEGIN ENDP

CODESG ENDS

END

Рис. 2.2. Команды с непосредственными данными

Директива EQU

Директива EQU не определяет элемент данных, но определяет значение, которое можно использовать для подстановки в других командах. Предположим, что в сегменте данных закодирована следующая директива EQU:

TIMES EQU 10

Имя, в данном случае TIMES, может быть представлено любым допустимым в ассемблере именем. Теперь в какой бы команде или директиве ни использовалось слово TIMES, ассемблер подставит значение 10. Например, ассемблер преобразует директиву

A DB TIMES DUP (? )

в директиву

A DB 10 DUP (? )

Имя, связанное с некоторым значением с помощью директивы EQU, может использоваться в командах, например:

COUNTR EQU 05

...

MOV СХ, COUNTR

Ассемблер заменяет имя COUNTR в команде MOV на значение 05, создавая операнд с непосредственным значением, как если бы было закодировано.

MOV CX, 05; Ассемблер подставляет 05.

Преимущество директивы EQU заключается в том, что многие команды могут использовать значение, определенное по имени COUNTR. Если это значение должно быть изменено, то изменению подлежит лишь одна директива EQU. Естественно, что использование директивы EQU разумно только там, где подстановка имеет смысл для ассемблера.

Ввод программы

В разделе рассмотрено, как ввести в компьютер исходный ассемблерный текст программы, как осуществить ассемблирование, компоновку и выполнение программы. Кроме того, показана генерация таблицы перекрестных ссылок для целей отладки.

На рис. 1.2 был показан только исходный текст программы, предназначенный для ввода с помощью текстового редактора. Теперь можно использовать DOS EDIT или другой текстовой редактор для ввода этой программы. Для ввода исходной программы EXASM1 наберите команду

EDIT EXASM1.ASM [ Return ]

При работе в интегрированной среде NORTOT можно пользоваться встроенным редактором NCEDIT.EXE. Для вызова используется кнопка F4.

После ввода программы убедитесь в ее правильности. Можно проверить наличие программы в каталоге на диске введением

DIR EXASM1.ASM (для одного файла).

Программа EXASM.ASM еще не может быть выполнена, так как необходимо провести ее ассемблирование и компоновку. В следующем разделе показана эта же программа после ассемблирования и пояснены этапы ассемблирования и получения листинга.

Подготовка программы для выполнения

После ввода на диск исходной программы под именем EXASM1.ASM необходимо проделать два основных шага, прежде чем программу можно будет выполнить. Сначала необходимо ассемблировать программу, а затем выполнить компоновку. Шаг ассемблирования включает в себя трансляцию исходного кода в машинный объектный код и генерацию OBJ-модуля.

Формат OBJ-модуля уже более приближен к исполнительной форме, но еще не готов к выполнению. Шаг компоновки включает преобразование OBJ-модуля в ЕХЕ-модуль (исполнимый), содержащий машинный код. Программа LINK, находящаяся на диске DOS, осуществляет следующее:

1. Завершает формирование в OBJ-модуле адресов, которые остались неопределенными после ассемблирования. Во многих следующих программах такие адреса ассемблер отмечает как ----R.

2. Компонует, если необходимо, более одного отдельно ассемблированного модуля в одну загрузочную (выполнимую) программу. Это, возможно, две или более ассемблерных программы или ассемблерная программа и программы, написанные на языках высокого уровня, таких как ПАСКАЛЬ или БЕЙСИК.

3. Инициализирует ЕХЕ-модуль командами загрузки для выполнения.

После компоновки OBJ-модуля (одного или более) в ЕХЕ-модуль можно выполнить ЕХЕ-модуль любое число раз. Но, если необходимо внести некоторые изменения в ЕХЕ-модуль, следует скорректировать исходную программу, ассемблировать ее в другой OBJ-модуль и выполнить компоновку OBJ-модуля в новый ЕХЕ-модуль. Даже если эти шаги пока остаются непонятными, вы обнаружите, что, приобретя некоторые навыки, весь процесс подготовки ЕХЕ-модуля можно будет довести до автоматизма.

3.3. Ассемблирование программы

Для того чтобы выполнить исходную ассемблерную программу, необходимо прежде провести ее ассемблирование и затем компоновку. На диске с ассемблерным пакетом имеются две версии ассемблера: ASM.ЕХЕ – сокращенная версия с отсутствием некоторых незначительных возможностей, TASM.EXE – полная версия. Если размеры памяти позволяют, то используйте версию MASM (подробности см. в соответствующем руководстве по ассемблеру).

Простейший вариант вызова программы – ввод команды TASM, что приведет к загрузке программы ассемблера с диска в память. На экране появится:

source filename [.ASM ]:

object filename [ filename.OBJ ]:

source listing [ NUL.LST ]:

cross-reference [ NUL.CRF ]:

Курсор при этом расположится в конце первой строки, где необходимо указать имя файла. Не следует набирать тип файла ASM, так как ассемблер подразумевает это.

Во втором запросе предполагается аналогичное имя файла (но можно его заменить).

Третий запрос предполагает, что листинг ассемблирования программы не требуется.

Последний запрос предполагает, что листинг перекрестных ссылок не требуется. Для получения листинга на дисководе В наберите В: и нажмите Return.

Если вы хотите оставить значения по умолчанию, то в трех последних запросах просто нажмите клавишу Return.

Выполнить ассемблирования возможно, набрав командную строку:

TASM EXASM1.ASM или TASM EXASM1.ASM/L

При этом во втором случае сформируется файл EXASM1.LST с листингом программы, в котором будут сообщены все ошибки. Пример листинга программы на рис. 3.1.

Turbo Assembler Version 2.5 03/12/00 12: 05: 20 Page 1

exasm1.asm

 

1 0000 STACKSG SEGMENT PARA STACK 'Stack'

2 0000 0C*(53 54 41 43 4B + DB 12 DUP ( 'STACKSEG' )

3 53 45 47)

4 0060 STACKSG ENDS

5 6; ----------------------------------------------------------------------------------------

7 0000 CODESG SEGMENT PARA 'Code'

8 0000 BEGIN PROC FAR

9 ASSUME SS: STACKSG, CS: CODESG, DS: NOTHING

10 0000 B8 0123 MOV AX, 0123H

; 3аписать 0123 в АХ.

Рис.3.1. Пример листинга программы

11 0003 05 0025 ADD AX, 0025H

; Прибавить 25 к AX.

12 0006 8B D8 MOV BX, AX; Переслать AX в BX.

13 0008 03 D8 ADD BX, AX; Прибавить BX к AX.

14 000A 8B CB MOV CX, BX; Переслать BX в CX.

15 000C 2B C8 SUB CX, AX; Вычесть AX из CX.

16 000E B8 4C00 MOV AX, 4C00H

17 0011 CD 21 INT 21H; Возврат в DOS.

18 0013 BEGIN ENDP; Конец процедуры.

19 0013 CODESG ENDS; Конец сегмента.

20 END BEGIN; Конец программы.

Turbo Assembler Version 2.5 03/12/00 12: 05: 20 Page 2

Symbol Table

 

Symbol Name Type Value

 

?? DATE Text " 03/12/00"

?? FILENAME Text " exasm1 "

?? TIME Text " 12: 05: 20"

?? VERSION Number 0205

@CPU Text 0101H

@CURSEG Text CODESG

@FILENAME Text EXASM1

@WORDSIZE Text 2

BEGIN Far CODESG: 0000

 

Groups & Segments Bit Size Align Combine Class

 

CODESG 16 0013 Para none CODE

STACKSG 16 0060 Para Stack STACK

Рис. 3.1. Окончание

Ассемблер преобразует исходные команды в машинный код и выдает на экран сообщения о возможных ошибках. Типичными ошибками являются нарушения ассемблерных соглашений по именам, неправильное написание команд (например MOVE вместо MOV), а также наличие в операндах неопределенных имен.

Ассемблер делает попытки скорректировать некоторые ошибки, но в любом случае следует перезагрузить текстовый редактор, исправить исходную программу (EXASM1.ASM) и повторить ассемблирование.

Листинг содержит не только исходный текст, но также в левой части транслированный машинный код в шестнадцатеричном формате. В самой левой колонке находятся шестнадцатеричные адреса команд и данных.

Сегмент стека начинается с относительного адреса 0000. В действительности он загружается в память в соответствии с адресом в регистре SS и нулевым смещением относительно этого адреса.

Сегмент кода также начинается с относительного адреса 0000. Он загружается в память в соответствии с адресом в регистре CS и нулевым смещением относительно этого адреса. Поскольку ASSUME является директивой ассемблеру, то первая команда, генерирующая машинный код, – это MOV AX, 0123H. Последняя команда END содержит операнд BEGIN, который имеет отношение к имени команды PROC по смещению 0000. Это адрес сегмента кодов, с которого начинается выполнение после загрузки программы.

Таблица идентификаторов

За листингом ассемблирования программы следует таблица идентификаторов. Первая часть таблицы содержит определенные в программе сегменты и группы вместе с их размерами в байтах, выравниванием и классом. Вторая часть содержит идентификаторы – имена полей данных в сегменте данных (в нашем примере их нет) и метки, назначенные командам в сегменте кодов (одна в нашем примере). Для того чтобы ассемблер не создавал эту таблицу, следует указать параметр /N вслед за командой MASM, т. е. MASM/N.

 

Двухпроходный ассемблер

В процессе трансляции исходной программы ассемблер делает два просмотра исходного текста. Одной из основных причин этого являются ссылки вперед. Это происходит в том случае, когда в некоторой команде кодируется метка, значение которой еще не определено ассемблером.

В первом проходе ассемблер просматривает всю исходную программу и строит таблицу идентификаторов, используемых в программе, т. е. имен полей данных и меток программы и их относительных адресов в программе. В первом проходе подсчитывается объем объектного кода, но сам объектный код не генерируется.

Во втором проходе ассемблер использует таблицу идентификаторов, построенную в первом проходе. Так как теперь уже известны длины и относительные адреса всех полей данных и команд, то ассемблер может сгенерировать объектный код для каждой команды. Ассемблер создает, если требуется, файлы OBJ, LST и CRF.

Компоновка программы

Если в результате ассемблирования не обнаружено ошибок, то следующий шаг – компоновка объектного модуля. Файл EXASM1.OBJ содержит только машинный код в шестнадцатеричной форме. Так как программа может загружаться почти в любое место памяти для выполнения, то ассемблер может не определить все машинные адреса. Кроме того, могут использоваться другие подпрограммы для объединения с основной. Назначением программы LINK является завершение определения адресных ссылок и объединение (если требуется) нескольких программ:

TLINK EXASM.OBJ

На данном этапе единственной возможной ошибкой может быть указание неправильных имен файлов. Исправить это можно только перезапуском программы LINK.

 

Выполнение программы

После ассемблирования и компоновки программы можно ее выполнить. На рис. 3.2 приведена схема команд и шагов для ассемблирования, компоновки и выполнения программы EXASM1. Если ЕХЕ-файл находится на диске C, то выполнить ее можно командой:

C: \EXASM1.EXE или C: \EXASM1

DOS предполагает, что файл имеет тип ЕХЕ (или СОМ), и загружает файл для выполнения. Но так как наша программа не вырабатывает видимых результатов, выполним ее трассировкой под отладчиком DEBUG или TURBO DEBUG.

Рис. 3.2. Схема ассемблирования, компоновки и выполнения программы

Пример исходной программы


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-05-28; Просмотров: 960; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.198 с.)
Главная | Случайная страница | Обратная связь