- •1. Требования языка ассемблера
- •1.1. Комментарии в программах на Ассемблере
- •1.2. Формат кодирования
- •1.3. Директивы ассемблера
- •Title текст
- •Директива segment
- •Директива assume
- •1.4. Память и регистры
- •1.5. Инициализация программы
- •1.6. Пример исходной программы
- •2. Определение данных
- •2.1. Директивы определения данных
- •2.2. Непосредственные операнды
- •Длина непосредственных операндов
- •3. Ассемблирование и выполнение программы
- •3.1. Ввод программы
- •3.2. Подготовка программы для выполнения
- •3.3. Ассемблирование программы
- •3.4. Выполнение программы
- •3.5. Пример исходной программы
- •4. Отладчик turbo debugger
- •4.1. Навигация по диалоговым блокам
- •4.2. Активные клавиши
- •Изучение языка ассемблера для персональных компьютеров
- •Изучение стандартных функций прерывания dos
- •Функции для работы с клавиатурой
- •Функции для работы с экраном
- •Функции для работы с файлами
3.4. Выполнение программы
После ассемблирования и компоновки программы можно ее выполнить. На рис. 3.2 приведена схема команд и шагов для ассемблирования, компоновки и выполнения программы EXASM1. Если ЕХЕ-файл находится на диске C, то выполнить ее можно командой:
C:\EXASM1.EXE или C:\EXASM1
DOS предполагает, что файл имеет тип ЕХЕ (или СОМ), и загружает файл для выполнения. Но так как наша программа не вырабатывает видимых результатов, выполним ее трассировкой под отладчиком DEBUG или TURBO DEBUG.
Рис. 3.2. Схема ассемблирования, компоновки и выполнения программы
3.5. Пример исходной программы
Особенность программы, приведенной на рис. 3.1, состоит в том, что она не содержит определения данных. Обычно все программы имеют определенные константы, рабочие поля для арифметических вычислений и области для операций ввода-вывода.
На рис. 3.3 приводится программа, написанная на языке Ассемблер и для краткости уже ассемблированная. Эта программа знакомит с несколькими новыми особенностями.
1 page 60,132
2 TITLE EXASM2 ( EXE ) Операции пересылки и сложения.
3 ;-------------------------------------------------------------------------------------------
4 0000 STACKSG SEGMENT PARA STACK ‘Stack’
5 0000 20 [ DW 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 215
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:NOTHING
20 0000 1E PUSH DS ; 3аписать DS в стек.
21 0001 2B C0 SUB AX,AX ; 3аписать в стек.
22 0003 50 PUSH AX ; Нулевой адрес.
Рис. 3.3. Листинг ассемблирования программы с сегментом данных
23 0004 B8 ---- R MOV АХ,DATASG ; Поместить адрес.
24 0007 8E D8 MOV DS,AX ; DATASG в регистр 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:
Name Size Align Combine Class
CODESG....................................0014 PARA NONE ‘CODE’
DATASG....................................0006 PARA NONE ‘DATA’
STACKSG..................................0040 PARA STACK ‘STACK’
Symbols:
Name 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
Рис. 3.3. Окончание
Сегмент стека содержит директиву DW (Define Word), описывающую 32 слова, в которых генерируется неопределенное значение, обозначенное знаком вопроса (?). Определение размера стека в 32 слова является наиболее реальным, так как в больших программах может потребоваться много «прерываний» для ввода-вывода и вызова подпрограмм – все они используют стек. Определение стека дублированием константы ‘STACKSEG’ в примере на рис. 1.2 необходимо лишь для удобства при работе с отладчиком DEBUG.
3амечание. Определяйте размер стека не менее, чем в 32 слова. При малых размерах стека ни ассемблер, ни компоновщик не смогут определить этого, и выполнение программы может разрушиться самым непредсказуемым образом.
На рис. 3.3 определен сегмент данных DATASG, начинающийся по относительному адресу 0000. Этот сегмент содержит три значения в формате DW. Поле FLDA определяет слово (два байта), содержащее десятичное значение 250, которое ассемблер транслирует в шестнадцатеричное 00FA (см. на рис. 3.3 слева).
Поле FLDB определяет слово с десятичным значением 125, которое транслируется в шестнадцатеричное 007D. Действительные значения этих двух констант в памяти FA00 и 7D00 соответственно, что можно проверить с помощью отладчика DEBUG.
Поле FLDC определяет слово с неизвестным значением, обозначенным знаком вопроса (?).
Сегмент кода в данном примере имеет имя CODESG и отличается новыми особенностями, связанными с сегментом данных. Во-первых, директива ASSUME указывает на определение DATASG через регистр DS. Данной программе не требуется регистр ES, но некоторые программисты описывают его для стандартизации. Во-вторых, после команд PUSH, SUB и PUSH, которые инициализируют стек, следуют две команды, обеспечивающие адресацию сегмента данных:
0004 В8 ---- R MOV AX,DATASG
0007 8Е D8 MOV DS,AX
Первая команда MOV загружает сегмент DATASG в регистр AX. На самом деле, поместить в регистр AX весь сегмент 64 Кб нельзя, поэтому команда загружает лишь начальный адрес сегмента DATASG.
Обратите внимание на машинный код слева:
В8 ---- R
Четыре дефиса говорят о том, что ассемблер не может определить адрес DATASG, он определяется лишь тогда, когда объектная программа будет скомпонована и загружена для выполнения. Поскольку загрузчик может расположить программу в любом месте памяти, ассемблер оставляет данный адрес открытым и показывает это символом R. Компоновщик должен будет подставить в это место действительный адрес.
Вторая команда MOV пересылает содержимое регистра АХ в регистр DS. Таким образом, данная программа имеет директиву ASSUME, которая соотносит регистр DS с сегментом данных, и команды, инициализирующие регистр DS относительным адресом DATASG.
Могут возникнуть два вопроса по поводу этой программы. Во-первых, почему не использовать одну команду для инициализации регистра DS, например:
MOV DS,DATASG ?
Дело в том, что не существует команд для непосредственной пересылки данных из памяти в регистр DS. Следовательно, для инициализации DS необходимо кодировать две команды. Во-вторых, почему программа инициализирует регистр DS, а регистры SS и CS нет? Оказывается, регистры SS и CS инициализируются автоматически при загрузке программы для выполнения, а ответственность за инициализацию регистра DS и, если требуется, ES лежит полностью на самой программе.
Пока все эти требования могут показаться весьма туманными, но сейчас не нужно понимать их. Все последующие программы используют аналогичную стандартную инициализацию стека и сегмента данных. Поэтому можно просто копировать данные коды для каждой новой программы. Действительно, вы можете сохранить на диске стандартную часть программы, а для каждой новой программы копировать эту часть с новым именем и, используя редактор, записать дополнительные команды.
В качестве упражнения создайте с помощью вашего редактора программу, приведенную на рис. 3.3, выполните ее ассемблирование и компоновку. Затем с помощью отладчика TURBO DEBUGGER просмотрите сегмент кодов, сегмент данных, регистры и проделайте пошаговое выполнение программы.
