Жанр: Учеба

Ассемблер и программирование для IBM PC

сторінка №5


заставить ассемблер сделать прогон листа на конкретной строке, например, в
конце сегмента. Для этого необходимо записать директиву 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, AT выражение и MEMORY. Сегмент стека определяется следующим
образом:
имя SEGMENT PARA STACK

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

имя SEGMENT PARA STACK 'Stack'

Фрагмент программы на рис.3.1. в следующем разделе иллюстрирует
директиву SEGMENT и ее различные опции.

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

Имя процедуры должно обязательно присутствовать, быть уникальным и
удовлетворять соглашениям по именам в ассемблере. Операнд FAR указывает
загрузчику DOS, что начало данной процедуры является точкой входа для
выполнения программы.
Директива ENDP определяет конец процедуры и имеет имя, аналогичное
имени в директиве PROC. Команда RET завершает выполнение программы и в
данном случае возвращает управление в DOS.
Сегмент может содержать несколько процедур (см. гл.7).

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

Директива Операнд
ASSUME SS:имя_стека,DS:имя_с_данных,CS:имя_с_кода

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

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

Директива Операнд
END [имя_процедуры]

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

ПАМЯТЬ И РЕГИСТРЫ
________________________________________________________________

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

MOV AX,BX ;Переслать содержимое BX в регистр AX
MOV AX,WORDA ;Переслать содержимое WORDA в регистр AX
MOV AX,[BX] ;Переслать содержимое памяти по адресу
; в регистре BX в регистр AX
MOV AX,25 ;Переслать значение 25 в регистр AX
MOV AX,[25] ;Переслать содержимое по смещению 25

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

ИНИЦИАЛИЗАЦИЯ ПРОГРАММЫ
________________________________________________________________

Существует два основных типа загрузочных программ: EXE и COM.
Рассмотрим требования к EXE-программам, а COM-программы будут представлены
в гл.6. DOS имеет четыре требования для инициализации ассемблерной
EXE-программы: 1) указать ассемблеру, какие сегментные регистры должны
соответствовать сегментам, 2) сохранить в стеке адрес, находящийся в
регистре DS, когда программа начнет выполнение, 3) записать в стек нулевой
адрес и 4) загрузить в регистр DS адрес сегмента данных.
Выход из программы и возврат в DOS сводится к использованию команды
RET. Рис.3.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
очищает регистр AX, вычитая его из этого же регистра AX, а команда
PUSH заносит это значение в стек.
4. Загрузчик DOS устанавливает правильные адреса стека в
регистре SS и сегмента кодов в регистре CS. Поскольку программа
загрузчика использует регистр DS для других целей, необходимо
инициализировать регистр DS двумя командами MOV, как показано на
рис.3.1. В следующем разделе этой главы "Исходная программа. Пример
II" детально поясняется инициализация регистра DS.
5. Команда RET обеспечивает выход из пользовательской программы
и возврат в DOS, используя для этого адрес, записанный в стек в
начале программы командой PUSH DS. Другим обычно используемым выходом
является команда INT 20H.

__________________________________________________________________________

CODESG SEGMENT PARA 'CODE'
BEGIN PROC FAR
1. ASSUME CS:CODESG,DS:DATASG,SS:STACKG
2. PUSH DS ;Записать DS в стек
3. SUB AX,AX ;Установить ноль в AX
PUSH AX ;Записать ноль в стек
4. MOV AX,DATASG ;Занести адрес
MOV DS,AX ; DATASG в DS
5. RET ;Возврат в DOS
BEGIN ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________

Рис.3.1. Инициализация EXE-программы.

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

ПРИМЕР ИСХОДНОЙ ПРОГРАММЫ
________________________________________________________________

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

__________________________________________________________________________

page 60,132
TITLE EXASM1 (EXE) Пример регистровых операций
;------------------------------------------------
STACKSG SEGMENT PARA SACK 'Stack'
DB 12 DUP('STACKSEG')
STACKSG ENDS
;------------------------------------------------
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME SS:STACKSG,CS:CODESG,DS:NOTHING
PUSH DS ;Записать DS в стек
SUB AX,AX ;Записать ноль
PUSH AX ; в стек

MOV AX,0123H ;Записать шест.0123 в AX
ADD AX,0025H ;Прибавить шест.25 к AX
MOV BX,AX ;Переслать AX в BX
ADD BX,AX ;Прибавить BX к AX
MOV CX,BX ;Переслать BX в CX
SUB CX,AX ;Вычесть AX из CX
SUB AX,AX ;Очистить AX
NOP
RET ;Возврат в DOS
BEGIN ENDP ;Конец процедуры

CODESG ENDS ;Конец сегмента
END BEGIN ;Конец программы
__________________________________________________________________________

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

STACKSG содержит один элемент DB (определить байт), который
определяет 12 копий слова 'STACKSEG'. В последующих программах стек не
определяется таким способом, но при использовании отладчика для просмотра
ассемблированной программы на экране, данное определение помогает
локализовать стек.
CODESG содержит выполняемые команды программы, хотя первая директива
ASSUME не генерирует кода. Директива ASSUME назначает регистр SS для
STACKSG и регистр CS для CODESG. В действительности, эта директива
сообщает ассемблеру, что для адресации в STACKSG необходимо использовать
адрес в регистре SS и для адресации в CODESG - адрес в регистре CS.
Системный загрузчик при загрузке программы с диска в память для выполнения
устанавливает действительные адреса в регистрах SS и CS. Программа не
имеет сегмента данных, так как в ней нет определения данных и,
соответственно, в ASSUME нет необходимости ассигновать регистр DS.
Команды, следующие за ASSUME - PUSH, SUB и PUSH выполняют стандартные
действия для инициализации стека текущим адресом в регистре DS и нулевым
адресом. Поскольку, обычно, программа выполняется из DOS, то эти команды
обеспечивают возврат в DOS после завершения программы. (Можно также
выполнить программу из отладчика, хотя это особый случай).
Последующие команды выполняют те же действия, что показаны на рис.2.1
в предыдущей главе, когда рассматривался отладчик.

ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ
________________________________________________________________

- Не забывайте ставить символ "точка с запятой" перед комментариями.

- Завершайте каждый сегмент директивой ENDS, каждую процедуру -
директивой ENDP, а программу - директивой END.

- В директиве ASSUME устанавливайте соответствия между сегментными
регистрами и именами сегментов.

- Для EXE-программ (но не для COM-программ, см. гл.6) обеспечивайте
не менее 32 слов для стека, соблюдайте соглашения по инициализации стека
командами PUSH, SUB и PUSH и заносите в регистр DS адрес сегмента данных.

ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ
________________________________________________________________

3.1. Какие команды заставляют ассемблер печатать заголовок в начале
каждой страницы листинга и делать прогон листа?

3.2. Какие из следующих имен неправильны: а) PC_AT, б) $50, в) @$_Z,
г) 34B7, д) AX?

3.3. Какое назначение каждого из трех сегментов, описанных в этой
главе?

3.4. Что конкретно подразумевает директива END, если она завершает а)
программу, б) процедуру, в) сегмент?

3.5. Укажите различия между директивой и командой.

3.6. Укажите различия в назначении RET и END.

3.7. Для сегментов кода, данных и стека даны имена CDSEG, DATSEG и
STKSEG соответственно. Сформируйте директиву ASSUME.


3.8. Напишите три команды для инициализации стека адресом в DS и
нулевым адресом.

ГЛАВА 4 Ассемблирование и выполнение программ


__________________________________________________________________________

Ц е л ь: показать процессы ассемблирования, компановки и выполнения
программ.

ВВЕДЕНИЕ
________________________________________________________________

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

ВВОД ПРОГРАММЫ
________________________________________________________________

На рис.3.2 был показан только исходный текст программы,
предназначенный для ввода с помощью текстового редактора. Теперь можно
использовать DOS EDLIN или другой текстовый редактор для ввода этой
программы. Если вы никогда не пользовались программой EDLIN, то именно
сейчас необходимо выполнить ряд упражнений из руководства по DOS. Для
запуска программы EDLIN вставьте дискету DOS в дисковод A и
форматизованную дискету в дисковод B. Чтобы убедиться в наличии на дискете
свободного места для исходного текста, введите CHKDSK B:. Для винчестера
во всех следующих примерах следует использовать C: вместо B:. Для ввода
исходной программы EXASM1, наберите команду

EDLIN В:EXASM1.ASM [Return]

В результате DOS загрузит EDLIN в памяти и появится сообщение "New
file" и приглашение "*-". Введите команду I для ввода строк, и затем
наберите каждую ассемблерную команду так, как они изображены на рис.3.2.
Хотя число пробелов в тексте для ассемблера не существенно, старайтесь
записывать метки, команды, операнды и комментарии, выровненными в колонки,
программа будет более удобочитаемая. Для этого в EDLIN используется
табуляция через каждые восемь позиций.
После ввода программы убедитесь в ее правильности. Затем наберите E
(и Return) для завершения EDLIN. Можно проверить наличие программы в
каталоге на диске, введите

DIR B: (для всех файлов)
или DIR B:EXASM1.ASM (для одного файла)

Если предполагается ввод исходного текста большего объема, то лучшим
применением будет полноэкранный редактор. Для получения распечатки
программы включите принтер и установите в него бумагу. Вызовите программу
PRINT (для DOS 2.0 и старше). DOS загрузит программу в память и
распечатает текст на принтере:

PRINT B:EXASM1.ASM [Return]

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

ПОДГОТОВКА ПРОГРАММЫ ДЛЯ ВЫПОЛНЕНИЯ
________________________________________________________________

После ввода на диск исходной программы под именем EXASM1.ASM
необходимо проделать два основных шага, прежде чем программу можно будет
выполнить. Сначала необходимо ассемблировать программу, а затем выполнить
компоновку. Программисты на языке бейсик могут выполнить программу сразу
после ввода исходного текста, в то время как для ассемблера и компилярных
языков нужны шаги трансляции и компоновки.
Шаг ассемблирования включает в себя трансляцию исходного кода в
машинный объектный код и генерацию OBJ-модуля. Вы уже встречали примеры
машинного кода в гл.2 и примеры исxодного текста в этой главе.
OBJ-модуль уже более приближен к исполнительной форме, но еще не
готов к выполнению. Шаг компановки включает преобразование OBJ-модуля в
EXE (исполнимый) модуль, содержащий машинный код. Программа LINK,
находящаяся на диске DOS, выполняет следующее:

1. Завершает формирование в OBJ-модуле адресов, которые остались
неопределенными после ассемблирования. Во многих следующих программах
такие адреса ассемблер отмечает как ----R.
2. Компонует, если необходимо, более одного отдельно
ассемблированного модуля в одну загрузочную (выполнимую) программу;
возможно две или более ассемблерных программ или ассемблерную
программу с программами, написанными на языках высокого уровня, таких
как Паскаль или Бейсик.
3. Инициализирует EXE-модуль командами загрузки для выполнения.

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

АССЕМБЛИРОВАНИЕ ПРОГРАММЫ
________________________________________________________________

Для того, чтобы выполнить исходную ассемблерную программу, необходимо
прежде провести ее ассемблирование и затем компоновку. На дискете с
ассемблерным пакетом имеются две версии ассемблера. ASM.EXE - сокращенная
версия с отсутствием некоторых незначительных возможностей и MASM.EXE -
полная версия. Если размеры памяти позволяют, то используйте версию MASM
(подробности см. в соответствующем руководстве по ассемблеру).
Для ассемблирования, вставьте ассемблерную дискету в дисковод A, а
дискету с исходной программой в дисковод B. Кто имеет винчестер могут
использовать в следующих примерах C вместо A и B. Простейший вариант
вызова программы это ввод команды MASM (или ASM), что приведет к загрузке
программы ассемблера с диска в память. На экране появится:

source filename [.ASM]:
object filename [filename.OBJ]:
source listing [NUL.LST]:
cross-reference [NUL.CRF]:

Курсор при этом расположится в конце первой строки, где необходимо
указать имя файла. Введите номер дисковода (если он не определен
умолчанием) и имя файла в следующем виде: B:EXASM1. Не следует набирать
тип файла ASM, так как ассемблер подразумевает это.
Во-втором запросе предполагается аналогичное имя файла (но можно его
заменить). Если необходимо, введите номер дисковода B:.
Третий запрос предполагает, что листинг ассемблирования программы не
требуется. Для получения листинга на дисководе B наберите B: и нажмите
Return.
Последний запрос предполагает, что листинг перекрестных ссылок не
требуется. Для получения листинга на дисководе B, наберите B: и нажмите
Return.
Если вы хотите оставить значения по умолчанию, то в трех последних
запросах просто нажмите Return. Ниже приведен пример запросов и ответов, в
результате которых ассемблер должен создать OBJ, LST и CRF-файлы. Введите
ответы так, как показано, за исключением того, что номер дисковода может
быть иной.

source filename [.ASM]:B:EXASM1 [Return]
object filename [filename.OBJ]:B: [Return]
source listing [NUL.LST]:B: [Return]
cross-reference [NUL.CRF]:B: [Return]

Всегда необходимо вводить имя исходного файла и, обычно, запрашивать
OBJ-файл - это требуется для компановки программы в загрузочный файл.
Возможно потребуется указание LST-файла, особенно, если необходимо
проверить сгенерированный машинный код. CRF-файл полезен для очень больших
программ, где необходимо видеть, какие команды ссылаются на какие поля
данных. Кроме того, ассемблер генерирует в LST-файле номера строк, которые
используются в CRF-файле.
В прил.4 "Режимы ассемблирования и редактирования" перечислены режимы
(опции) для ассемблера версий 1.0 и 2.0.
Ассемблер преобразует исходные команды в машинный код и выдает на
экран сообщения о возможных ошибках. Типичными ошибками являются нарушения
ассемблерных соглашений по именам, неправильное написание команд
(например, MOVE вместо MOV), а также наличие в операндах неопределенных
имен. Программа ASM выдает только коды ошибок, которые объяснены в
руководстве по ассемблеру, в то время как программа МАSM выдает и коды
ошибок, и пояснения к ним. Всего имеется около 100 сообщений об ошибках.

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

__________________________________________________________________________

1 page 60,132
2 TITLE EXASM1 (EXE) Пример регистровых операций
3 ;-----------------------------------------------
4 0000 STACKSG SEGMENT PARA SACK 'Stack'
5 0000 0C [ DB 12 DUP('STACKSEG')
6 53 54 41 43
7 4B 53 45 47
8 ]

9


10 0060 STACKSG ENDS
11 ;-----------------------------------------------
12 0000 CODESG SEGMENT PARA 'Code'
13 0000 BEGIN PROC FAR
14 ASSUME SS:STACKSG,CS:CODESG,DS:NOTHING
15 0000 1E PUSH DS ;Записать DS в стек
16 0001 2B C0 SUB AX,AX ;Записать ноль
17 0003 50 PUSH AX ; в стек

18


19 0004 B8 0123 MOV AX,0123H ;Записать шест.0123 в AX
20 0007 05 0025 ADD AX,0025H ;Прибавить шест.25 к AX
21 000A 8B D8 MOV BX,AX ;Переслать AX в BX
22 000C 03 D8 ADD BX,AX ;Прибавить BX к AX
23 000E 8B CB MOV CX,BX ;Переслать BX в CX
24 0010 2B C8 SUB CX,AX ;Вычесть AX из CX
25 0012 2B C0 SUB AX,AX ;Очистить AX
26 0014 90 NOP
27 0015 CB RET ;Возврат в DOS
28 0016 BEGIN ENDP ;Конец процедуры

29


30 0016 CODESG ENDS ;Конец сегмента
31 END BEGIN ;Конец программы
-------------------------------------------------------------------------
Segments and Groups:
N a m e Size Align Combine Class
CODESG . . . . . . . . . . . . 0016 PARA NONE 'CODE'
STACKSG. . . . . . . . . . . . 0060 PARA STACK 'STACK'

Symbols:
N a m e Type Value Attr
BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=0016
__________________________________________________________________________

Рис.4.1. Листинг ассемблирования программы.

В начале листинга обратите внимание на реакцию ассемблера на
директивы PAGE и TITLE. Никакие директивы, включая SEGMENT, PROC, ASSUME и
END не генерируют машинных кодов.
Листинг содержит не только исходный текст, но также слева
транслированный машинный код в шестнадцатиричном формате. В самой левой
кол

Список сторінок

Поділитися у соцмережах

☏ Замовлення реклами: +3805044-68-872

© Асоціація електронних бібліотек України

☝ Усі матеріали сайту (зокрема статті, зображення, рекламні оголошення тощо) призначені лише для попереднього ознайомлення. Усі права на публікації, представлені на сайті, належать їхнім законним власникам. Просимо Вас не зберігати копії інформації.