Жанр: Учеба
Ассемблер и программирование для IBM PC
...онке находится шест.адреса команд и данных.
Сегмент стека начинается с относительного адреса 0000. В
действительности он загружается в память в соответствии с адресом в
регистре SS и нулевым смещением относительно этого адреса. Директива
SEGMENT устанавливает 16-кратный адрес и указывает ассемблеру, что это
есть начало стека. Сама директива не генерирует машинный код. Команда DB,
также находится по адресу 0000, содержит 12 копий слова 'STACKSEG';
машинный код представлен шест.0C (десятичное 12) и шест. представлением
ASCII символов. (В дальнейшем можно использовать отладчик для просмотра
результатов в памяти). Сегмент стека заканчивается по адресу шест.0060,
который эквивалентен десятичному значению 96 (12х8).
Сегмент кода также начинается с относительного адреса 0000. Он
загружается в память в соответствии с адресом в регистре CS и нулевым
смещением относительно этого адреса. Поскольку ASSUME является директивой
ассемблеру, то первая команда, которая генерирует действительный машинный
код есть PUSH DS - однобайтовая команда (1E), находящаяся на нулевом
смещении. Следующая команда SUB AX,AX генерирует двухбайтовый машинный код
(2B C0), начинающийся с относительного адреса 0001. Пробел между байтами
только для удобочитаемости. В данном примере встречаются одно-, двух- и
трехбайтовые команды.
Последняя команда END содержит операнд BEGIN, который имеет отношение
к имени команды PROC по смещению 0000. Это есть адрес сегмента кодов, с
которого начинается выполнение после загрузки программы.
Листинг ассемблирования программы EXASM1.LST, имеет по директиве PAGE
ширину 132 символа и может быть распечатан. Многие принтеры могут печатать
текст сжатым шрифтом. Включите ваш принтер и введите команду
MODE LPT1:132,6
Таблица идентификаторов
-------------------------
За листингом ассемблирования программы следует таблица
идентификаторов. Первая часть таблицы содержит определенные в программе
сегменты и группы вместе с их размером в байтах, выравниванием и классом.
Вторая часть содержит идентификаторы - имена полей данных в сегменте
данных (в нашем примере их нет) и метки, назначенные командам в сегменте
кодов (одна в нашем примере). Для того, чтобы ассемблер не создавал эту
таблицу, следует указать параметр /N вслед за командой MASM, т.е. MASM/N.
Двухпроходный ассемблер
-------------------------
В процессе трансляции исходной программы ассемблер делает два
просмотра исходного текста, или два прохода. Одной из основных причин
этого являются ссылки вперед, что происходит в том случае, когда в
некоторой команде кодируется метка, значение которой еще не определено
ассемблером.
В первом проходе ассемблер просматривает всю исходную программу и
строит таблицу идентификаторов, используемых в программе, т.е. имен полей
данных и меток программы и их относительных адресов в программе. В первом
проходе подчитывается объем объектного кода, но сам объектный код не
генерируется.
Во втором проходе ассемблер использует таблицу идентификаторов,
построенную в первом проходе. Так как теперь уже известны длины и
относительные адреса всех полей данных и команд, то ассемблер может
сгенерировать объектный код для каждой команды. Ассемблер создает, если
требуется, файлы: OBJ, LST и CRF.
КОМПАНОВКА ПРОГРАММЫ
________________________________________________________________
Если в результате ассемблирования не обнаружено ошибок, то следующий
шаг - компановка объектного модуля. Файл EXASM1.OBJ содержит только
машинный код в шестнадцатеричной форме. Так как программа может
загружаться почти в любое место памяти для выполнения, то ассемблер может
не определить все машинные адреса. Кроме того, могут использоваться другие
(под) программы для объединения с основной. Назначением программы LINK
является завершение определения адресных ссылок и объединение (если
требуется) нескольких программ.
Для компановки ассемблированной программы с дискеты, вставьте дискету
DOS в дисковод A, а дискету с программой в дисковод B. Пользователи
винчестерского диска могут загрузить компоновщик LINK прямо с дисковода C.
Введите команду LINK и нажмите клавишу Return. После загрузки в память,
компоновщик выдает несколько запросов (аналогично MASM), на которые
необходимо ответить:
Запрос компоновщика Ответ Действие
Object Modules [.OBJ]: B:EXASM1 Компонует EXASM1.OBJ
Run file [EXASM1.EXE]: B: Создает EXASM1.EXE
List file [NUL.MAP]: CON Создает EXASM1.MAP
Libraries [.LIB]: [Return] По умолчанию
Первый запрос - запрос имен объектных модулей для компановки, тип OBJ
можно опустить.
Второй запрос - запрос имени исполнимого модуля (файла), (по
умолчанию A:EXASM1.EXE). Ответ B: требует, чтобы компоновщик создал файл
на дисководе В. Практика сохранения одного имени (при разных типах) файла
упрощает работу с программами.
Третий запрос предполагает, что LINK выбирает значение по умолчанию -
NUL.MAP (т.е. MAP отсутствует). MAP-файл содержит таблицу имен и размеров
сегментов и ошибки, которые обнаружит LINK. Типичной ошибкой является
неправильное определение сегмента стека. Ответ CON предполагает, что
таблица будет выведена на экран, вместо записи ее на диск. Это позволяет
сэкономить место в дисковой памяти и сразу просмотреть таблицу
непосредственно на экране. В нашем примере MAP-файл содержит следующую
информацию:
Start Stop Length Name
00000H 00015H 0016H CODESG
00020H 0007FH 0060H STACKSG
Для ответа на четвертый запрос - нажмите Return, что укажет
компоновщику LINK принять остальные параметры по умолчанию. Описание
библиотечных средств можно найти в руководстве по DOS.
На данном этапе единственной возможной ошибкой может быть указание
неправильных имен файлов. Исправить это можно только перезапуском
программы LINK. В прил.4 перечислен ряд режимов компоновщика LINK.
ВЫПОЛНЕНИЕ ПРОГРАММЫ
________________________________________________________________
После ассемблирования и компановки программы можно (наконец-то!)
выполнить ее. На рис.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 для просмотра содержимого регистров и выполните программу с
помощью команды 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-файл для выполнения.
В следующем разделе представлено определение данных в сегменте
данных. Позже будет описана таблица перекрестных ссылок.
ПРИМЕР ИСХОДНОЙ ПРОГРАММЫ
________________________________________________________________
Особенность программы, приведенной на рис.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
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 - определить слово),
описывающая 32 слова, в которых генерируется неопределенное значение
обозначенное знаком вопроса (?). Определение размера стека в 32 слова
является наиболее реальным, так как в больших программах может
потребоваться много "прерываний" для ввода-вывода и вызовов подпрограмм -
все они используют стек. Определение стека дублированием константы
'STACKSEG' в примере на рис.3.2 необходимо лишь для удобства при работе с
отладчиком DEBUG.
З а м е ч а н и е: Определяйте размер стека не менее 32 слов. При
малых размерах стека ни ассемблер, ни компоновщик не смогут определить
этого и выполнение программы может разрушиться самым непредсказуемым
образом.
В примере на рис.4.3 определен сегмент данных DATASG, начинающийся по
относительному адресу 0000. Этот сегмент содержит три значения в формате
DW. Поле FLDA определяет слово (два байта), содержащее десятичное значение
250, которое ассемблер транслирует в шест.00FA (см. на рисунке слева).
Поле FLDB определяет слово с десятичным значением 125, которое
транслируется в шест.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
Четыре дефиса говорят о том, что ассемблер не может определить адрес
DATASG; он определяется лишь когда объектная программа будет скомпонована
и загружена для выполнения. Поскольку загрузчик может расположить
программу в любом месте памяти, ассемблер оставляет данный адрес открытым
и показывает это символом R; компоновщик должен будет подставить в это
место действительный адрес.
Вторая команда MOV пересылает содержимое регистра AX в регистр DS.
Таким образом, данная программа имеет директиву ASSUME, которая соотносит
регистр DS с сегментом данных, и команды, инициализирующие регистр DS
относительным адресом DATASG.
Могут возникнуть два вопроса по поводу этой программы. Во-первых,
почему не использовать одну команду для инициализации регистра DS,
например
MOV DS,DATASG ?
Дело в том, что не существует команд для непосредственной пересылки
данных из памяти в регистр DS. Следовательно, для инициализации DS
необходимо кодировать две команды.
Во-вторых, почему программа инициализирует регистр DS, а регистры SS
и CS нет? Оказывается, регистры SS и CS инициализируются автоматически при
загрузке программы для выполнения, а ответственность за инициализацию
регистра DS и, если требуется ES, лежит полностью на самой программе.
Пока все эти требования могут показаться весьма туманными, но сейчас
нет необходимости понимать их. Все последующие программы используют
аналогичную стандартную инициализацию стека и сегмента данных. Поэтому
можно просто копировать данные коды для каждой новой программы.
Действительно, вы можете сохранить на диске стандартную часть программы и
для каждой новой программы копировать эту часть с новым именем, и,
используя затем редактор, записать дополнительные команды.
В качестве упражнения, создайте с помощью вашего редактора программу,
приведенную на рис.4.3, выполните ее ассемблирование и компоновку. Затем с
помощью отладчика DEBUG просмотрите сегмент кодов, сегмент данных,
регистры и проделайте пошаговое выполнение программы.
ФАЙЛ ПЕРЕКРЕСТНЫХ ССЫЛОК
________________________________________________________________
В процессе трансляции ассемблер создает таблицу идентификаторов
(CRF), которая может быть представлена в виде листинга перекрестных ссылок
на метки, идентификаторы и переменные в программе. Для получения данного
фала, необходимо на четвертый запрос ассемблера, ответить B:, полагая, что
файл должен быть создан на диске B:
cross-reference [NUL.CRF]:B: [Return]
Далее необходимо преобразовать полученный CRF-файл в отсортированную
таблицу перекрестных ссылок. Для этого на ассемблерном диске имеется
соответствующая программа. После успешного ассемблирования введите команду
CREF. На экране появится два запроса:
Cref filename [.CRF]:
List filename [cross-ref.REF]:
На первый запрос введите имя CRF-файла, т.е. B:EXASM1. На второй
запрос можно ввести только номер дисковода и получить имя по умолчанию.
Такой выбор приведет к записи CRF в файл перекрестных ссылок по имени
EXASM1.REF на дисководе B.
Для распечатки файла перекрестных ссылок используйте команду DOS
PRINT. В приложении 4 приведен ряд режимов программы CREF.
__________________________________________________________________________
EXASM2 (EXE) Операции пересылки и сложения
Symbol Cross Reference (# is definition) Cref-1
BEGIN. . . . . . . . . . . . 18# 30 32
CODE . . . . . . . . . . . . 17
CODESG . . . . . . . . . . . 17# 19 31
DATA . . . . . . . . . . . . 11
DATASG . . . . . . . . . . . 11# 15 19 23
FLDA . . . . . . . . . . . . 12# 26
FLDB . . . . . . . . . . . . 13# 27
FLDC . . . . . . . . . . . . 14# 28
STACK. . . . . . . . . . . . 4
STACKSG. . . . . . . . . . . 4# 9 19
10 Symbols
__________________________________________________________________________
Рис.4.4. Таблица перекрестных ссылок.
На рис.4.4 показана таблица перекрестных ссылок для программы,
приведенной на рис.4.3. Все идентификаторы в таблице представлены в
алфавитном порядке и для каждого из них указаны номера строк в исходной
программе, где они определены и имеют ссылки. Имена сегментов и элементов
данных представлены в алфавитном порядке. Первое число справа в формате n#
указывает на номер строки в LST-файле, где определен соответствующий
идентификатор. Еще правее находятся числа, указывающие на номера строк,
где имеются ссылки на этот идентификатор. Например, CODESG определен в
строке 17 и имеет ссылки на строках 19 и 32.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ
________________________________________________________________
- Ассемблер преобразует исходную программу в OBJ-файл, а компоновщик
- OBJ-файл в загрузочный EXE-файл.
- Внимательно проверяйте запросы и ответы на них для программ (M)ASM,
LINK и CREF прежде чем нажать клавишу Return. Будьте особенно внимательны
при указании дисковода.
- Программа CREF создает распечатку перекрестных ссылок.
- Удаляйте ненужные файлы с вашего диска. Регулярно пользуйтесь
программой CHKDSK для проверки свободного места на диске. Кроме того
периодически создавайте резервные копии вашей программы, храните резервную
дискету и копируйте ее заново для последующего программирования.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ
________________________________________________________________
4.1. Введите команду MASM и ответьте на запросы для ассемблирования
программы по имени TEMPY.ASM с получением файлов LST, OBJ и CRF, полагая,
что дискета с программой находится на дисководе B.
4.2. Введите команды для программы TEMPY (из вопроса 4.1) а) для
выполнения через отладчик DEBUG, б) для непосредственного выполнения из
DOS.
4.3. Объясните назначение каждого из следующих файлов: а) file.BAK,
б) file.ASM, в) file.LST, г) file.CRF, д) file.OBJ, е) file.EXE, ж)
file.MAP.
4.4. Напишите две команды для инициализации регистра DS, полагая, что
имя сегмента данных - DATSEG.
4.5. Составьте ассемблерную программу для:
- пересылки шест.30 (непосредственное значение) в регистр AL;
- сдвига содержимого регистра AL на один бит влево (команда SHL)
- пересылки шест.18 (непосредственное значение) в регистр BL;
- умножения регистра AL на BL (команда MUL BL).
Не забывайте команду RET. В программе нет необходимости определять и
инициализировать сегмент данных. Не забывайте также копировать стандартную
часть программы (основу программы) и использовать редактор для ее
развития. Выполните ассемблирование и компоновку. Используя отладчик
DEBUG, проверьте сегмент кодов, регистры и проделайте пошаговое выполнение
(трассировку) программы.
4.6. Модифицируйте программу из вопроса 4.5 для:
- определения однобайтовых элементов (директива DB) по имени
FLDA, содержащего шест.28, и по имени FLDB, содержащего шест.14;
- определения двухбайтового элемента (директива DW) по имени
FLDC, не имеющего значения;
- пересылки содержимого поля FLDA в регистр AL и сдвига на один
бит;
- умножения содержимого регистра AL на значение в поле FLDB (MUL
FLDB);
- пересылки результата из регистра AX в поле FLDC.
Для данной программы необходим сегмент данных. Выполните
ассемблирование, компоновку программы и тестирование с помощью отладчика
DEBUG.
__________________________________________________________________________
Ц е л ь: Показать методам определения констант и рабочих полей в
ассемблерной программе.
ВВЕДЕНИЕ
________________________________________________________________
Сегмент данных предназначен для определения констант, рабочих полей и
областей для ввода-вывода. В соответствии с имеющимися директивами в
ассемблере разрешено определение данных различной длины: например,
директива DB определяет байт, а директива DW определяет слово. Элемент
данных может содержать непосредственное значение или константу,
определенную как символьная строка или как числовое значение.
Другим способом определения константы является непосредственное
значение, т.е. указанное прямо в ассемблерной команде, например:
MOV AL,20H
В этом случае шестнадцатеричное число 20 становится частью машинного
объектного кода. Непосредственное значение ограничено одним байтом или
одним словом, но там, где оно может быть применено, оно является более
эффективным, чем использование константы.
ДИРЕКТИВЫ ОПРЕДЕЛЕНИЯ ДАННЫХ
________________________________________________________________
Ассемблер обеспечивает два способа определения данных: во-первых,
через указание длины данных и, во-вторых, по их содержимому. Рассмотрим
основной формат определения данных:
[имя] Dn выражение
Имя элемента данных не обязательно (это указывается квадратными
скобками), но если в программе имеются ссылки на некоторый элемент,
то это делается посредством имени. Правила написания имен приведены в
разделе "Формат кодирования" в главе 3.
Для определения элементов данных имеются следующие директивы: DB
(байт), DW (слово), DD (двойное слово), DQ (учетверенное слово) и DT
(десять байт).
Выражение может содержать константу, например:
FLD1 DB 25
или знак вопроса для неопределенного значения, например
FLDB DB ?
Выражение может содержать несколько констант, разделенных запятыми и
ограниченными только длиной строки:
FLD3 DB 11, 12, 13, 14, 15, 16, ...
Ассемблер определяет эти константы в виде последовательности смежных байт.
Ссылка по имени FLD3 указывает на первую константу, 11, по FLD3+1 - на
вторую, 12. (FLD3 можно представить как FLD3+0). Например команда
MOV AL,FLD3+3
загружает в регистр AL значение 14 (шест. 0E). Выражение допускает также
повторение константы в следующем формате:
[имя] Dn число-повторений DUP (выражение) ...
Следующие три примера иллюстрируют повторение:
DW 10 DUP(?) ;Десять неопределенных слов
DB 5 DUP(14) ;Пять байт, содержащих шест.14
DB 3 DUP(4 DUP(8));Двенадцать восьмерок
В третьем примере сначала генерируется четыре копии десятичной 8
(8888), и затем это значение повторяется три раза, давая в результате
двенадцать восьмерок.
Выражение может содержать символьную строку или числовую константу.
Символьные строки
-------------------
Символьная строка используются для описания данных, таких как,
например, имена людей или заголовки страниц. Содержимое строки отмечается
одиночными кавычками, например, 'PC' или двойными кавычками - "PC".
Ассемблер переводит символьные строки в объектный код в обычном формате
ASCII.
Символьная строка опред
...Поділитися у соцмережах