MOV DL,'*'



Ассемблер для IBM PC. Глава 20 23


MOV AH,02
INT 21H

ДИРЕКТИВА LOCAL
------------------------------------------------------------

В некоторых макрокомандах требуется определять элементы
данных или метки команд. При использовании такой
макрокоманды в программе более одного раза происходит также
неоднократное определение одинаковых полей данных или меток.
В результате ассемблер выдаст сообщения об ошибке из-за
дублирования имен. Для обеспечения уникальности генерируемых
в каждом макрорасширении имен используется директива LOCAL,
которая кодируется непосредственно после директивы MACRO,
даже перед комментариями. Общий формат имеет следующий вид:

LOCAL dummy-1,dummy-2,... ;Формальные параметры

Рис.20.4. иллюстрирует использование директивы LOCAL. В
приведенной на этом рисунке программе выполняется деление
вычитанием; делитель вычитается из делимого и частное
увеличивается на 1 до тех пор, пока делимое больше делителя.
Для данного алгоритма необходимы две метки: COMP - адрес
цикла, OUT - адрес выхода из цикла по завершению. Обе метки
COMP и OUT определены как LOCAL и могут иметь любые
правильные ассемблерные имена.
В макрорасширении для COMP генерируется метка ??0000, а
для OUT - ??0001. Если макрокоманда DIVIDE будет использова
на в этой программе еще один раз, то в следующем макрорасши
рении будут сгенерированы метки ??0002 и ??0003 соответствен
но. Таким образом, с помощью директивы LOCAL обеспечивается
уникальность меток в макрорасширениях в одной программе.

------------------------------------------------------------
------------------------------------------------------------
Рис.20.4. Использование директивы LOCAL.

ИСПОЛЬЗОВАНИЕ БИБЛИОТЕК МАКРООПРЕДЕЛЕНИЙ
------------------------------------------------------------

Определение таких макрокоманд, как INIT1 и INIT2 и
одноразовое их использование в программе кажется
бессмысленным. Лучшим подходом здесь является каталогизация
собственных макрокоманд в библиотеке на магнитном диске,
используя любое описательное имя, например, MACRO.LIB:

INIT MACRO CSNAME,DSNAME,SSNAME
.
.
ENDM
PROMPT MACRO MESSGE
.
.



Ассемблер для IBM PC. Глава 20 24


ENDM

Теперь для использования любой из каталогизированных
макрокоманд вместо MACRO определения в начале программы
следует применять директиву INCLUDE:

INCLUDE C:MACRO.LIB
.
.
INIT CSEG,DATA,STACK

В этом случае ассемблер обращается к файлу MACRO.LIB (в
нашем примере) на дисководе C и включает в программу оба
макроопределения INIT и PROMPT. Хотя в нашем примере
требуется только INIT. Ассемблерный листинг будет содержать
копию макроопределения, отмеченного символом C в 30 колонке
LST-файла. Следом за макрокомандой идет ее расширение с
объектным кодом и с символом плюс (+) в 31 колонке.
Так как транслятор с ассемблера является двухпроходовым,
то для обеспечения обработки директивы INCLUDE только в
первом проходе (а не в обоих) можно использовать следующую
конструкцию:

IF1
INCLUDE C:MACRO.LIB
ENDIF

IF1 и ENDIF являются условными директивами. Директива IF1
указывает ассемблеру на необходимость доступа к библиотеке
только в первом проходе трансляции. Директива ENDIF
заверша ет IF-логику. Таким образом, копия макроопределений
не появится в листинге - будет сэкономлено и время и
память.
Программа на рис.20.5 содержит рассмотренные выше директи
вы IF1, INCLUDE и ENDIF, хотя в LST-файл ассемблер выводит
только директиву ENDIF. Обе макрокоманды в кодовом сегменте
INIT и PROMPT закаталогизированы в файле MACRO.LIB, т.е.
просто записаны друг за другом на дисковый файл по имени
MACRO.LIB с помощью текстового редактора.
Расположение директивы INCLUDE не критично, но она должна
появиться ранее любой макрокоманды из включаемой библиотеки.

------------------------------------------------------------
------------------------------------------------------------
Рис.20.5. Использование библиотеки макроопределений.

Директива очистки

Директива INCLUDE указывает ассемблеру на включение всех
макроопределений из специфицированной библиотеки. Например,
библиотека содержит макросы INIT, PROMPT и DIVIDE, хотя





Ассемблер для IBM PC. Глава 20 25


программе требуется только INIT. Директива PURGE позволяет
"удалить" нежелательные макросы PROMPT и DIVIDE в текущем
ассемблировании:

IF1
INCLUDE MACRO.LIB ;Включить всю библиотеку
ENDIF
PURGE PROMRT,DIYIDE ;Удалить ненужные макросы
...
INIT CSEG,DATA,STACK ;Использование оставшейся
; макрокоманды

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

КОНКАТЕНАЦИЯ (&)
------------------------------------------------------------

Символ амперсанд (&) указывает ассемблеру на сцепление
(конкатенацию) текста или символов. Следующая макрокоманда
MOVE генерирует команду MOVSB или MOVSW:

MOVE MACRO TAG
REP MOVS&TAG
ENDM

Теперь можно кодировать макрокоманду в виде MOVE B или MOVE
W. В результате макрорасширения ассемблер сцепит параметр с
командой MOVS и получит REP MOVSB или REP MOVSW. Данный
пример весьма тривиален и служит лишь для иллюстрации.

ДИРЕКТИВЫ ПОВТОРЕНИЯ: REPT, IRP, IRPC
------------------------------------------------------------

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

REPT: Повторение

Операция REPT приводит к повторению блока операторов до
директивы ENDM в соответствии с числом повторений, указанным
в выражении:
REPT выражение

В следующем примере происходит начальная инициализация
значения N=0 и затем повторяется генерация DB N пять раз:

N = 0



Ассемблер для IBM PC. Глава 20 26


REPT 5
N = N + 1
DB N
ENDM

В результате будут сгенерированы пять операторов DB от DB 1
до DB 5. Директива REPT может использоваться таким образом
для определения таблицы или части таблицы. Другим примером
может служить генерация пяти команд MOVSB, что эквивалентно
REP MOVSB при содержимом CX равном 05:

REPT 5
MOVSB
ENDM

IRP: Неопределенное повторение

Операция IRP приводит к повторению блока команд до
директивы ENDM. Основной формат:

IRP dummy,<arguments>

Аргументы, содержащиеся в угловых скобках, представляют
собой любое число правильных символов, строк, числовых или
арифметических констант. Ассемблер генерирует блок кода для
каждого аргумента. В следующем примере ассемблер генерирует
DB 3, DB 9, DB 17, DB 25 и DB 28:

IRP N,<3, 9, 17, 25, 28>
DB N
ENDM

IRPC: Неопределенное повторение символа

Операция IRPC приводит к повторению блока операторов до
директивы ENDM. Основной формат:

IRPC dummy,string

Ассемблер генерирует блок кода для каждого символа в строке
"string". В следующем примере ассемблер генерирует DW 3, DW
4 ... DW 8:

IRPC N,345678
DW N
ENDM

УСЛОВНЫЕ ДИРЕКТИВЫ
------------------------------------------------------------

Ассемблер поддерживает ряд условных директив. Ранее нам
уже приходилось использовать директиву IF1 для включения
библиотеки только в первом проходе ассемблирования. Условные



Ассемблер для IBM PC. Глава 20 27


директивы наиболее полезны внутри макроопределений, но не
ограничены только этим применением. Каждая директива IF
должна иметь спаренную с ней директиву ENDIF для завершения
IF-логики и возможную директиву ELSE для альтернативного
действия:

IFxx (условие)
. }
. } Условный
ELSE (не обязательное действие) }
. } блок
. }
ENDIF (конец IF-логики)

Отсутствие директивы ENDIF вызывает сообщение обошибке:
"Undeterminated conditional" (незавершенный условный блок).
Если проверяемое условие истино, то ассемблер выполняет
условный блок до директивы ELSE или при отсутствии ELSE - до
директивы ENDIF. Если условие ложно, то ассемблер выполняет
условный блок после директивы ELSE, а при отсутствии ELSE
вообще обходит условный блок.
Ниже перечислены различные условные директивы:

IF выражение Если выражение не равно нулю,
ассемблер обрабатывает операторы в
условном блоке.
IFE выражение Если выражение равно нулю, ассемблер
обрабатывает операторы в условном
блоке.
IF1 (нет выражения) Если осуществляется первый проход
ассемблирования, то обрабатываются
операторы в условном блоке.
IF2 (нет выражения) Если осуществляется второй проход
ассемблирования, то обрабатываются
операторы в условном блоке.
IFDEF идентификатор Если идентификатор определен в
программе или объявлен как EXTRN, то
ассемблер обрабатывает операторы в
условном блоке.
IFNDEF идентификатор Если идентификатор не определен в
программе или не объявлен как EXTRN,
то ассемблер обрабатывает операторы в
условном блоке.
IFB <аргумент> Если аргументом является пробел,
ассемблер обрабатывает операторы в
условном блоке. Аргумент должен быть в
угловых скобках.
IFNB <аргумент> Если аргументом является не пробел, то
ассемблер обрабатывает операторы в
условном блоке. Аргумент должен быть в
угловых скобках.





Ассемблер для IBM PC. Глава 20 28


IFIDN <арг-1>,<арг-2> Если строка первого аргумента
идентична строке второго аргумента, то
ассемблер обрабатывает операторы в
условном блоке. Аргументы должны быть
в угловых скобках.
IFDIF<арг-1>,<арг-2> Если строка первого аргумента
отличается от строки второго
аргумента, то ассемблер обрабатывает
операторы в условном блоке. Аргументы
должны быть в угловых скобках.

Ниже приведен простой пример директивы IFNB (если не
пробел). Для DOS INT 21H все запросы требуют занесения
номера функции в регистр AH, в то время как лишь некоторые
из них используют значение в регистре DX. Следующее
макроопределение учитывает эту особенность:

DOS21 MACRO DOSFUNC,DXADDRES
MOV AN,DOSFUNC
IFNB <DXADDRES>
MOV DX,OFFSET DXADDRES
ENDIF
INT 21H
ENDM

Использование DOS21 для простого ввода с клавиатуры
требует установки значения 01 в регистр AH:

DOS21 01

Ассемблер генерирует в результате команды MOV AH,01 и INT
21H. Для ввода символьной строки требуется занести в регистр
AH значение 0AH, а в регистр DX - адрес области ввода:

DOS21 0AH,IPFIELD

Ассемблер генерирует в результате обе команды MOV и INT 21H.

ДИРЕКТИВА ВЫХОДА ИЗ МАКРОСА EXITM.
------------------------------------------------------------

Макроопределение может содержать условные дерективы,
которые проверяют важные условия. Если условие истинно, то
ассемблер должен прекратить дальнейшее макрорасширение. Для
этой цели служит директива EXITM:

IFxx [условие]
.
. (неправильное условие)
.
EXITM
.
.



Ассемблер для IBM PC. Глава 20 29


ENDIF

Как только ассемблер попадает в процессе генерации макро
расширения на директиву EXITM, дальнейшое расширение
прекращается и обработка продолжается после директивы ENDM.
Можно использовать EXITM для прекращения повторений по
директивам REPT, IRP и IRPC даже если они находятся внутри
макроопределения.

МАКРОКОМАНДЫ, ИСПОЛЬЗУЮЩИЕ IF И IFNDEF УСЛОВИЯ
------------------------------------------------------------

Программа на рис.20.6 содержит макроопределение DIVIDE,
которая генерирует подпрограмму для выполнения деления
вычитанием. Макрокоманда должна кодироваться с параметрами в
следующей последовательности: делимое, делитель, частное.
Макрокоманда содержит директиву IFNDEF для проверки наличия
параметров. Для любого неопределенного элемента макрокоманда
увеличивает счетчик CNTR. Этот счетчик может иметь любое
корректное имя и предназначен для временного использования в
макроопределении. После проверки всех трех параметров,
макрокоманда проверяет CNTR:

IF CNTR
; Макрорасширение прекращено
EXITM

Если счетчик CNTR содержит ненулевое значение, то
ассемблер генерирует комментарий и прекращает по директиве
EXITM дальнейшее макрорасширение. Заметим, что начальная
команда устанавливает в счетчике CNTR нулевое значение и,
кроме того, блоки IFNDEF могут устанавливать в CNTR
единичное значение, а не увеличивать его на 1.
Если ассемблер успешно проходит все проверки, то он
генерирует макрорасширение. В кодовом сегменте первая
макрокоманда DIVIDE содержит правильные делимое и частное и,
поэтому генерирует только комментарии. Один из способов
улучшения рассматриваемой макрокоманды - обеспечить проверку
на ненулевой делитель и на одинаковый знак делимого и
делителя; для этих целей лучше использовать коды ассемблера,
чем условные директивы.

------------------------------------------------------------
------------------------------------------------------------
Рис.20.6. Использование директив IF и IFNDEF.

МАКРОС, ИСПОЛЬЗУЮЩИЙ IFIDN-УСЛОВИЕ
------------------------------------------------------------








Ассемблер для IBM PC. Глава 20 30


Программа на рис.20.7 содержит макроопределение по имени
MOVIF, которая генерирует команды MOVSB или MOVSW в
зависимости от указанного параметра. Макрокоманду можно
кодировать с параметром B (для байта) или W (для слова) для
генерации команд MOVSB или MOVSW из MOVS.
Обратите внимание на первые два оператора в макроопределе
нии:
MOVIF MACRO TAG
IFIDN <&TAG>,<B>

Условная директива IFIDN сравнивает заданный параметр
(предположительно B или W) со строкой B. Если значения
идентичны, то ассемблер генерирует REP MOVSB. Обычное
использование амперсанда (&) - для конкатенации, но в данном
примере операнд <TAG> без амперсанда не будет работать. Если
в макрокоманде не будет указан параметр B или W, то
ассемблер сгенерирует предупреждающий комментарий и команду
MOVSB (по умолчанию).
Примеры в кодовом сегменте трижды проверяют макрокоманду
MOVIF: для параметра B, для параметра W и для неправильного
параметра. Не следует делать попыток выполнения данной
программы в том виде, как она приведена на рисунке, так как
регистры CX и DX не обеспечены правильными значениями.
Предполагается, что рассматриваемая макрокоманда не
является очень полезной и ее назначение здесь - проиллюстри
ровать условные директивы в простой форме. К данному
моменту, однако, вы имеете достаточно информации для
составления больших полезных макроопределений.

------------------------------------------------------------
------------------------------------------------------------
Рис.20.7. Использование директивы IFIDN

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

ъ Макросредства возможны только для полной версии
ассемблера (MASM).
ъ Использование макрокоманд в программах на ассемблере
дает в результате более удобочитаемые программы и более
произ водительный код.
ъ Макроопределение состоит из директивы MACRO, блока из
одного или нескольких операторов, которые генерируются
при макрорасширениях и директивы ENDM для завершения
определения.
ъ Код, который генерируется в программе по макрокоманде,
представляет собой макрорасширение.
ъ Директивы .SALL,.LALL и .XALL позволяют управлять
распечаткой комментариев и генерируемого объектного
кода в макрорасширении.
ъ Директива LOCAL позволяет использовать имена внутри
макроопределений. Директива LOCAL кодируется
непосредственно после директивы MACRO.



Ассемблер для IBM PC. Глава 20 31


ъ Использование формальных параметров в макроопределении
позволяет кодировать параметры, обеспечивающие большую
гибкость макросредств.
ъ Библиотека макроопределений дает возможность использо
вать макрокоманды для различных ассемблерных программ.
ъ Условные директивы позволяют контролировать параметры
макрокоманд.

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

20.1. Напишите необходимые директивы: а) для подавления всех
команд, которые генерирует макрокоманда и б) для
распечатки только команд, генерирующих объектный код.
20.2. Закодируйте два макроопределения для умножения: а)
MULTBY должна генерировать код для умножения байта на
байт; б) MULTWD должна генерировать код для умножения
слова на слово.
Для множителя и множимого используйте в макро
определении формальные параметры. Проверьте выполнение
макрокоманд на небольшой программе, в которой также
определены необходимые области данных.
20.3. Запишите макроопределения из вопроса 20.2 в "макро
библиотеку". Исправьте программу для включения
элементов библиотеки по директиве INCLUDE в первом
проходе ассемблирования.
20.4. Напишите макроопределение BIPRINT, использующей BIOS
INT 17H для печати. Макроопределение должно включать
проверку состояния принтера и обеспечивать печать
любых строк любой длины.
20.5. Измените макроопределение на рис.20.6 для проверки
делителя на ноль (для обхода деления).
























Ассемблер для IBM PC. Глава 21 1



    ГЛАВА 21. Компановка программ


------------------------------------------------------------

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

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

ВВЕДЕНИЕ
------------------------------------------------------------

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

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

Каждая программа ассемблируется отдельно и генерирует
собственный уникальный объектный (OBJ) модуль. Программа
компановщик (LINK) затем компанует объектные модули в один
объединенный выполняемый (EXE) модуль. Обычно выполнение
начинается с основной программы, которая вызывает одну или
более подпрограмм. Подпрограммы, в свою очередь, могут
вызывать другие подпрограммы.
На рис.21.1 показаны два примера иерархической структуры
основной подпрограммы и трех подпрограмм. На рис. 21.1 (а)
основная программы вызывает подпрограммы 1, 2 и 3. На рис.
21.1 (б) основная программа вызывает подпрограммы 1 и 2, а
подпрограмма 1 вызывает подпрограмму 3.

------------------------------------------------------------
------------------------------------------------------------
Рис.21.1. Иерархия программ.

Существует много разновидностей организации подпрограмм,
но любая организация должна быть "понятна" и ассемблеру, и
компановщику, и этапу выполнения. Следует быть внимательным
к ситуациям, когда, например, под программа 1 вызывает



Ассемблер для IBM PC. Глава 21 2


подпрограмму 2, которая вызывает подпрограмму 3 и, которая в
свою очередь вызывает подпрограмму 1. Такой процесс,
известный как рекурсия, может использоваться на практике, но
при неаккуратном обращении может вызвать любопытные ошибки
при выполнении.

МЕЖСЕГМЕНТНЫЕ ВЫЗОВЫ
------------------------------------------------------------

Команды CALL в предыдущих главах использовались для
внутрисегментных вызовов, т.е. для вызовов внутри одного
сегмента. Внутрисегментный CALL может быть короткий (в
пределах от +127 до -128 байт) или длинный ( превышающий
указанные границы). В результате такой операции "старое"
значение в регистре IP запоминается в стеке, а "новый" адрес
перехода загружается в этот регистр.
Например, внутрисегментный CALL может иметь следующий
объектный код: E82000. Шест.E8 представляет собой код
операции, которая заносит 2000 в виде относительного адреса
0020 в регистр IP. Затем процессор объединяет текущий адрес
в регистре CS и относительный адрес в регистре IP для
получения адреса следующей выполняемой команды. При возврате
из процедуры команда RET восстанавливает из стека старое
значение в регистре IP и передает управление таким образом
на следующую после CALL команду.
Вызов в другой кодовый сегмент представляет собой межсег
ментный (длинный) вызов. Данная операция сначала записывает
в стек содержимое регистра CS и заносит в этот регистр адрес
другого сегмента, затем записывает в стек значение регистра
IP и заносит новый относительный адрес в этот регистр.
Таким образом в стеке запоминаются и адрес кодового сег
мента и смещение для последующего возврата из подпрограммы.
Например, межсегментный CALL может состоять из следующего
объектного кода:

9A 0002 AF04

Шест.9A представляет собой код команды межсегментного вызова
которая записывает значение 0002 в виде 0200 в регистр IP,
а значение AF04 в виде 04AF в регистр CS. Комбинация этих
адресов указывает на первую выполняемую команду в вызываемой
подпрограмме:

Кодовый сегмент 04AF0
Смещение в IP 0200
Действительный адрес 04CF0

При выходе из вызванной процедуры межсегментная команда
возврата REP восстанавливает оба адреса в регистрах CS и IP
и таким образом передает управление на следующую после CALL
команду.

АТРИБУТЫ EXTRN и PUBLIC



Ассемблер для IBM PC. Глава 21 3


------------------------------------------------------------

Рассмотрим основную программу (MAINPROG), которая
вызывает подпрограмму (SUBPROG) с помощью межсегментного
CALL, как показано на рис.21.2.
Команда CALL в MAINPROG должна "знать", что SUBPROG
существует вне данного сегмента (иначе ассемблер выдаст
сообщение о том, что идентификатор SUBPROG не определен). С
помощью директивы EXTRN можно указать ассемблеру, что ссылка
на SUBPROG имеет атрибут FAR, т.е.определена в другом
ассемблерном модуле. Так как сам ассемблер не имеет
возможности точно определить такие ссылки, он генерирует
"пустой" объектный код для последующего заполнения его при
компановке:

9A 0000 ---- E

Подпрограмма SUBPROG содержит директиву PUBLIC, которая
указывает ассемблеру и компановщику, что другой модуль
должен "знать" адрес SUBPROG. В последнем шаге, когда оба
модуля MAINPROG и SUBPROG будут успешно ассемблированы в
объектные модули, они могут быть скомпанованы следующим
образом:

Запрос компановщика LINK: Ответ:

Object Modules [.OBJ]: B:MAINPROG+B:SUBPROG
Run File [filespec.EXE]: B:COMBPROG (или другое имя)
List File [NUL.MAP]: CON
Libraries [.LIB]: [return]

------------------------------------------------------------
------------------------------------------------------------
Рис.21.2. Межсегментный вызов.

Компановщик устанавливает соответствия между адресами
EXTRN в одном объектном модуле с адресами PUBLIC в другом и
заносит необходимые относительные адреса. Затем он объединя
ет два объектных модуля в один выполняемый. При невозможнос
ти разрешить ссылки компановщик выдает сообщения об ошибках.
Следите за этими сообщениями прежде чем пытаться выполнить
программу.

Директива EXTRN

Директива EXTRN имеет следующий формат:

EXTRN имя:тип [, ... ]

Можно определить более одного имени (до конца строки) или
закодировать дополнительные директивы EXTRN. В другом
ассемблерном модуле соответствующее имя должно быть
определено и идентифицировано как PUBLIC. Тип элемента может



Ассемблер для IBM PC. Глава 21 4


быть ABS, BYTE, DWORD, FAR, NEAR, WORD. Имя может быть
определено через EQU и должно удовлетворять реальному
определению имени.

Директива PUBLIC

Директива PUBLIC указывает ассемблеру и компановщику, что
адрес указанного иддентификатора доступен из других программ
Директива имеет следующий формат:

PUBLIC идентификатор [, ... ]

Можно определить более одного идентификатора (до конца
строки) или закодировать дополнительные директивы PUBLIC.
Идентификаторы могут быть метками (включая PROC-метки),
переменными или числами. Неправильными идентификаторами
являются имена регистров и EQU-идентификаторы, определяющие
значения более двух байт.
Рассмотрим три различных способа компановки программ.

ПРОГРАММА: ИСПОЛЬЗОВАНИЕ ДИРЕКТИВ EXTRN и PUBLIC ДЛЯ МЕТОК
------------------------------------------------------------

Программа на рис.21.3 состоит из основной программы
CALLMUL1 и подпрограммы SUBMUL1. В основной программе
определены сегменты для стека, данных и кода. В сегменте
данных определены поля QTY и PRICE. В кодовом сегменте
регистр AX загружается значением PRICE, а регистр BX -
значением QTY, после чего происходит вызов подпрограммы.
Директива EXTRN в основной программе определяет SUBMUL как
точку входа в подпрограмму.
Подпрограмма содержит директиву PUBLIC (после ASSUME),
которая указывает компановщику, что точкой входа для выполне
ния является метка SUBMUL. Подпрограмма выполняет умножение
содержимого регистра AX (цена) на содержимое регистра BX
(количество). Результат умножения вырабатывается в регистро
вой паре DX:AX в виде шест. 002E 4000.
Так как подпрограмма не определяет каких-либо данных, то
ей не требуется сегмент данных. Если бы подпрограмма имела
сегмент данных, то только она одна использовала бы свои
данные.
Также в подпрограмме не определен стековый сегмент, так
как она использует те же стековые адреса, что и основная
программа. Таким образом, стек определенный в основной
программе является доступным и в подпрогрпмме. Для компанов