После ассемблирования и компановки программы можно (наконец-то!)
выполнить ее. На рис.4.2 приведена схема команд и шагов для
ассемблирования, компановки и выполнения программы EXASM1. Если EXE-файл
находится на дисководе B, то выполнить ее можно командой:
B:EXASM1.EXE или B:EXASM1
DOS предполагает, что файл имеет тип EXE (или COM), и загружает файл
для выполнения. Но так как наша программа не вырабатывает видимых
результатов, выполним ее трассировкой под отладчиком DEBUG. Введите
DEBUG B:EXASM1.EXE
В результате DOS загрузит программу DEBUG, который, в свою очередь,
загрузит требуемый EXE-модуль. После этого отладчик выдаст дефис (-) в
качестве приглашения. Для просмотра сегмента стека введите
D SS:0
Эту область легко узнать по 12-кратному дублированию константы
STACKSEG. Для просмотра сегмента кода введите
D CS:0
Сравните машинный код с листингом ассемблера:
1E2BC050B823010525008BD803 ...
Непосредственные операнды, приведенные в листинге ассемблирования как
0123 и 0025 в памяти представлены в виде 2301 и 2500 соответственно. В
данном случае листинг ассемблирования не вполне соответствует машинному
коду. Все двухбайтовые адреса (слова) и непосредственные операнды в
машинном коде хранятся в обратном порядке.
__________________________________________________________________________
__________________________________________________________________________
Рис.4.2. Схема ассемблирования, компановки и выполнения программы.
Введите R для просмотра содержимого регистров и выполните прогpамму с
помощью команды T (трассировка). Обратите внимание на воздействие двух
команд PUSH на стек - в вершине стека теперь находится содержимое регистра
DS и нулевой адрес.
В процессе пошагового выполнения программы обратите внимание на
содержимое регистров. Когда вы дойдете до команды RET, можно ввести Q
(Quit - выход) для завершения работы отладчика.
Используя команду dir, можно проверить наличие ваших файлов на диске:
DIR B:EXASM1.*
В результате на экране появится следующие имена файлов: EXASM1.BAK
(если для корректировки EXASM1.ASM использовался редактор EDLIN),
EXASM1.ASM, EXASM1.OBJ, EXASM1.LST, EXASM1.EXE и EXASM1.CRF.
Последовательность этих файлов может быть иной в зависимости от того, что
уже находится на диске.
Очевидно, что разработка ряда программ приведет к занятию дискового
пространства. Для проверки оставшегося свободного места на диске полезно
использовать команду DOS CHKDSK. Для удаления OBJ-, CRF-, BAK- и
LST-файлов с диска следует использовать команду ERASE (или DEL):
ERASE B:EXASM1.OBJ, ...
Следует оставить (сохранить) ASM-файл для последующих изменений и
EXE-файл для выполнения.
В следующем разделе представлено определение данных в сегменте
данных. Позже будет описана таблица перекрестных cсылок.
ПРИМЕР ИСХОДНОЙ ПРОГРАММЫ
________________________________________________________________
Особенность программы, приведенной на рис.4.1, состоит в том, что она
не содержит определения данных. Обычно все программы имеют определенные
константы, рабочие поля для арифметических вычислений и области для
операций ввода-вывода.
В главе 2 (рис.2.3) была рассмотрена программа в машинных кодах, в
которой были определены два поля данных. В этой главе на рис.4.3
приводится аналогичная программа, но на этот раз написанная на языке
ассемблера и для краткости уже ассемблированная. Эта программа знакомит с
несколькими новыми особенностями.
__________________________________________________________________________
1 page 60,132
2 TITLE EXASM2 (EXE) Операции пересылки и сложения
3 ;-------------------------------------------------
4 0000 STACKSG SEGMENT PARA SACK 'Stack'
5 0000 20 [ DB 32 DUP(?)
6 ????
7 ]
8
9 0040 STACKSG ENDS
10 ;-------------------------------------------------
11 0000 DATASG SEGMENT PARA 'Data'
12 0000 00FA FLDA DW 250
13 0002 007D FLDB DW 125
14 0004 ???? FLDC DW ?
15 0006 DATASG ENDS
16 ;-------------------------------------------------
17 0000 CODESG SEGMENT PARA 'Code'
18 0000 BEGIN PROC FAR
19 ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:NO
THING
20 0000 1E PUSH DS ;Записать DS в стек
21 0001 2B C0 SUB AX,AX ;Записать в стек
22 0003 50 PUSH AX ; нулевой адрес
23 0004 B8 ---- R MOV AX,DATASG ;Поместить адрес DATASG
24 0007 8E D8 MOV DS,AX ; в регистр DS
25
26 0009 A1 0000 R MOV AX,FLDA ;Переслать 0250 в AX
27 000C 03 06 0002 R ADD AX,FLDB ;Прибавить 0125 к AX
28 0010 A3 0004 R MOV FLDC,AX ;Записать сумму в FLDC
29 0013 CB RET ;Вернуться в DOS
30 0014 BEGIN ENDP
31 0014 CODESG ENDS
32 END BEGIN
------------------------------------------------------------------------
Segments and Groups:
N a m e Size Align Combine Class
CODESG . . . . . . . . . . . . 0014 PARA NONE 'CODE'
DATASG . . . . . . . . . . . . 0006 PARA NONE 'DATA'
STACKSG. . . . . . . . . . . . 0040 PARA STACK 'STACK'
Symbols:
N a m e Type Value Attr
BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=0014
FLDA . . . . . . . . . . . . . L WORD 0000 DATASG
FLDB . . . . . . . . . . . . . L WORD 0002 DATASG
FLDC . . . . . . . . . . . . . L WORD 0004 DATASG
__________________________________________________________________________
Рис.4.3. Листинг ассемблирования программы с сегментом данных.
Сегмент стека содержит директиву DW (Define Word - определить cлово),
описывающая 32 слова, в которых генерируется неопределенное значение
обозначенное знаком вопроса (?). Определение размера стека в 32 слова
является наиболее реальным, так как в больших программах может
потребоваться много "прерываний" для ввода-вывода и вызовов подпрограмм -
все они используют стек. Определение стека дублированием константы
'STACKSEG' в примере на pис.3.2 необходимо лишь для удобства при работе с
отладчиком DEBUG.
З а м е ч а н и е: Определяйте размер стека не менее 32 слов. При
малых размерах стека ни ассемблер, ни компоновщик не смогут определить
этого и выполнение программы может разрушиться самым непредсказуемым
образом.
В примере на рис.4.3 определен сегмент данных DATASG, начинающийся по
относительному адресу 0000. Этот сегмент содержит три значения в формате
DW. Поле FLDA определяет слово (два байта), содержащее десятичное значение
250, которое ассемблер транслирует в шест.00FA (см. на рисунке слева).
Поле FLDB определяет слово с десятичным значением 125, котоpое
транслируется в шест.007D. Действительные значения этих двух констант в
памяти - FA00 и 7D00 соответственно, что можно проверить c помощью
отладчика DEBUG.
Поле FLDC определяет слово с неизвестным значением, обозначенным
знаком вопроса (?).
Сегмент кода в данном примере имеет имя CODESG и отличается новыми
особенностями, связанными с сегментом данных. Во-первых, директива ASSUME
указывает на определение DATASG через регистр DS. Данной программе не
требуется регистр ES, но некоторые программисты описывают его для
стандартизации. Во-вторых, после команд PUSH, SUB и PUSH, которые
инициализируют стек, следуют две команды, обеспечивающие адресацию
сегмента данных:
0004 B8 ---- R MOV AX,DATASG
0007 8E D8 MOV DS,AX
Первая команда MOV загружает DATASG в регистр AX. Конечно, на самом
деле команда не может загрузить сегмент в регистр - она загружает лишь
адрес сегмента DATASG. Обратите внимание на машинный код слева:
B8 ---- R
Четыре дефиса говорят о том, что ассемблер не может определить aдрес
DATASG; он определяется лишь когда объектная программа будет скомпонована
и загружена для выполнения. Поскольку загpузчик может расположить
программу в любом месте памяти, асcемблер оставляет данный адрес открытым
и показывает это символом R; компоновщик должен будет подставить в это
место действительный адрес.
Вторая команда MOV пересылает содержимое регистра AX в регистр DS.
Таким образом, данная программа имеет директиву ASSUME, которая соотносит
регистр DS с сегментом данных, и команды, инициализирующие регистр DS
относительным адресом DATASG.
Могут возникнуть два вопроса по поводу этой программы. Во-первых,
почему не использовать одну команду для инициализации регистра DS,
например
MOV DS,DATASG ?
Дело в том, что не существует команд для непосредственной переcылки
данных из памяти в регистр DS. Следовательно, для инициализации DS
необходимо кодировать две команды.
Во-вторых, почему программа инициализирует регистр DS, а регистры SS
и CS нет? Оказывается, регистры SS и CS инициализируются автоматически при
загрузке программы для выполнения, а ответственность за инициализацию
регистра DS и, если требуется ES, лежит полностью на самой программе.
Пока все эти требования могут показаться весьма туманными, но cейчас
нет необходимости понимать их. Все последующие программы используют
аналогичную стандартную инициализацию стека и сегмента данных. Поэтому
можно просто копировать данные коды для каждой новой программы.
Действительно, вы можете сохранить на диске стандартную часть программы и
для каждой новой программы копировать эту часть с новым именем, и,
используя затем редактор, записать дополнительные команды.
В качестве упражнения, создайте с помощью вашего редактора программу,
приведенную на рис.4.3, выполните ее ассемблирование и компоновку. Затем с
помощью отладчика DEBUG просмотрите сегмент кодов, сегмент данных,
регистры и проделайте пошаговое выполнение программы.
ФАЙЛ ПЕРЕКРЕСТНЫХ ССЫЛОК
________________________________________________________________
В процессе трансляции ассемблер создает таблицу идентификаторов
(CRF), которая может быть представлена в виде листинга перекрестных ссылок
на метки, идентификаторы и переменные в программе. Для получения данного
фала, необходимо на четвертый запрос ассемблера, oтветить B:, полагая, что
файл должен быть создан на диске B:
cross-reference [NUL.CRF]:B: [Return]
Далее необходимо преобразовать полученный CRF-файл в отсортиpованную
таблицу перекрестных ссылок. Для этого на ассемблерном диске имеется
соответствующая программа. После успешного ассемблирования введите команду
CREF. На экране появится два запроса:
Cref filename [.CRF]:
List filename [cross-ref.REF]:
На первый запрос введите имя CRF-файла, т.е. B:EXASM1. На второй
запрос можно ввести только номер дисковода и получить имя по умолчанию.
Такой выбор приведет к записи CRF в файл перекрестных ссылок по имени
EXASM1.REF на дисководе B.