Оформление программных модулей
Общедоступные подпрограммы могут располагаться в исходных или в объектных модулях. Исходный модуль состоит из программного сегмента, содержащего описание одной или нескольких подпрограмм на языке Макроассемблера. Объектный модуль получается в результате обработки исходного модуля компоновщиком. Исходные модули могут располагаться непосредственно в тексте основной программы или храниться в отдельных файлах, в последнем случае они являются общедоступными. Объектные модули могут храниться в виде отдельных файлов, имеющих тип obj, или в библиотечных файлах, имеющих тип lib. Они подключаются к задаче только в процессе ее компоновки (сборки). В данном разделе описаны рекомендации, которых следует придерживаться при оформлении обоих типов модулей.
Пример модуля в теле задачи
На первой стадии подготовки исходного модуля производится составление, набор текста и отладка подпрограмм, поэтому модуль удобнее включить в текст основной программы в виде отдельного сегмента, а не хранить в отдельном файле. В примере В.2 показан вариант оформления дополнительного сегмента в основной программе.
Пример В.2. Сегмент с описанием подпрограмм NxtWin, SetWin, PrevWin.
subr SEGMENT word public 'subr1; начало сегмента ASSUME cs:subr, ds:@data; установка соответствия;.386; тип микропроцессора ; Далее располагается текст примера В.1, содержащий ; описание подпрограмм NxtWin, SetWin и PrevWin subr ENDS; конец сегмента
Первая директива примера В.2 открывает описание сегмента. В данном случае его параметры можно было не указывать, они приведены просто для иллюстрации. Параметр word обозначает, что сегмент располагается в памяти, начиная с четного адреса. Параметр public является признаком общедоступного сегмента. Заключенное в кавычки название сегмента передается компоновщику и становится общедоступным.
Замечание
Обратите внимание на то, что между параметрами директивы SEGMENT отсутствуют запятые!
Директива ASSUME нужна для того, чтобы Макроассемблер мог определить, что будет находиться в сегментных регистрах cs и ds при выполнении подпрограмм. Без этого невозможна компиляция команд. С регистром cs всегда связывается имя сегмента, в котором расположена директива ASSUME. С регистром ds связывается имя сегмента данных, который описан вне данного модуля. Имя, с которым ассоциируется ds, зависит от способа описания сегмента данных в основном тексте программы. В примере В.2 предполагается, что сегмент данных был описан с помощью специальной директивы .data (см. Приложение Б).
Если вы забудете указать директиву ASSUME, то при компиляции Макроассемблер может выдавать аварийные сообщения, смысл которых заключается в том, что не определен один из сегментных регистров. Чтобы лучше понять назначение директивы, уберите ее из текста и посмотрите, что из этого получится. В частности, результат зависит от версии MASM.
В примере В.2 строка, содержащая третью директиву, начинается с символа "точка с запятой". Подпрограммы Nxtwin, setwin и Prevwin составлены с использованием набора команд микропроцессора Intel 8086, поэтому в данном случае директива.386 не нужна. Однако большинство описанных в книге примеров рассчитано на возможности микропроцессора Intel 80386, и для их компиляции данная директива необходима.
Разрядность сегмента
При обработке директив описания сегментов Макроассемблер проверяет установленный тип микропроцессора и выбирает соответствующий режим выполнения команд, расположенных в сегменте (реальный или защищенный). По умолчанию установлен 16-разрядный (реальный) режим выполнения команд и набор инструкций для микропроцессора Intel 8086.
Если директива 0.386 предшествует описанию сегмента, то он будет объявлен как 32-разрядный, расположенные в нем команды будут рассчитаны на работу с 32-разрядными адресами. В реальном режиме результаты выполнения таких команд непредсказуемы.
Поэтому при создании программ или подпрограмм, предназначенных для выполнения в реальном режиме работы микропроцессора, директиву.386 надо располагать после описания сегмента. В таком случае она оказывает влияние только на набор инструкций микропроцессора.
Начиная с версии 6.0, Макроассемблер поддерживает директивы.486 и.586, разрешающие использование новых инструкций микропроцессоров Intel 486 и Pentium. Кроме того, появилась возможность выбора разрядности сегментов по умолчанию или ее явного описания с помощью ключевых слов USE16 И USE32.
В конце файла, формируемого Макроассемблером, приводится описание всех сегментов программного модуля. При компиляции обязательно укажите имя файла и затем проверьте, соответствуют ли указанная в нем разрядность сегментов той, которую вы предполагаете.
Расположение сегмента в тексте программы зависит от версии MASM, который вы используете. Если это MASM 6.0 и выше, то дополнительный сегмент может располагаться как перед основным текстом программы (перед сегментом кодов), так и после него. Но если вы работаете с MASM 5.1, то дополнительный сегмент может располагаться только перед сегментом кодов. В противном случае при каждом вызове подпрограмм, расположенных в дополнительном сегменте, MASM 5.1 выводит аварийное сообщение о необходимости предварительного описания подпрограммы.