ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



3. Сегментация программы
               Программа   на    языке    ассемблера    состоит    из
         последовательности  программных  сегментов,  заканчивающейся
         директивой  END.  Начало   каждого   сегмента   обозначается
         директивой  SEGMENT, конец - директивой ENDS.
               В  каждом  сегменте  при помощи директивы ASSUME могут
         быть определены  используемые  по  умолчанию  для  адресации
         элементов программы регистры сегмента.
               В  каждом  сегменте  могут  быть  выделены специальные
         программные  единицы  (процедуры), позволяющие  использовать
         часть  программного  кода многократно без его дублирования в
         разных частях программы. Процедуры обычно включены в систему
         адресации  сегмента.  Начало  и конец процедуры определяются
         директивами PROC и ENDP соответственно.
               Сегменты могут быть объединены  в  группу  при  помощи
         директивы GROUP.
               Директивы  ORG  и  EVEN  позволяют  управлять адресами
         размещения инструкций процессора.
               Эти директивы подробнее описаны в следующих разделах.
               
               
               
               
               
                       3.1. Директивы SEGMENT и ENDS.
               
               
               Синтаксис:
               
         имя SEGMENT [[выравнивание]] [[комбинация]] [['класс']]
               
         имя ENDS

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

                                   -  9 -
         
         
         SEGMENT  задают   информацию   для   линкера.   Они   должны
         кодироваться  в  указанной последовательности, но могут быть
         опущены в произвольной комбинации.
               
               Выравнивание  определяет   границу   адреса,   начиная
         с которой сегмент  будет  загружаться  в  память. Могут быть
         заданы следующие значения:
                 BYTE - использовать любую границу
                 WORD - граница слова (2 байта)
                 PARA - граница параграфа (16 байтов)
                 PAGE - граница страницы (256 байтов)
               Если выравнивание не указано, предполагается PARA.
               Следует помнить, что точный адрес начала  сегмента  до
         его  загрузки  в  память неизвестен. Тип выравнивания только
         накладывает на него ограничение.

               Тип  комбинации  определяет  возможность   и   способы
         объединения  программных  сегментов, имеющих одно имя. Могут
         быть указаны следующие значения:
                    
         PUBLIC   - Все сегменты с одним и тем же именем объединяются
                    в один непрерывный сегмент. Все инструкции и поля
                    данных   нового   сегмента   будут   адресоваться
                    относительно  одного  регистра  сегмента,  а  все
                    смещения будут  вычисляться  относительно  начала
                    этого сегмента.
         STACK    - Все сегменты с одним и тем же именем объединяются
                    в один непрерывный сегмент. Этот  тип  комбинации
                    отличается  от  PUBLIC  лишь тем, что адресация в
                    новом   сегменте   будет   вестись   относительно
                    регистра  SS; регистр SP при этом устанавливается
                    на конец сегмента. Такой  тип  комбинации  обычно
                    имеют   сегменты   стека.  Тип  комбинайии  STACK
                    автоматически     обеспечивает      инициализацию
                    регистров  SS  и SP, и пользователю необязательно
                    включать  в   свою   программу   инструкции   для
                    установки этих регистров.   
         COMMON   - Все  одноименные  сегменты  этого  класса   будут
                    загружаться  в  память,  начиная с одного адреса.
                    Таким  способом  можно   формировать   оверлейные
                    программы.  Длина  области  загрузки  равна длине
                    максимального по объему сегмента.  Все  адреса  в
                    этих  сегментах  вычисляются  относительно одного
                    базового адреса. Если некоторые данные  объявлены
                    в  более, чем одном, сегменте с конкретным именем
                    и типом комбинации COMMON,  данные,   объявленные
                    последними, замещают все предыдущие. 
         MEMORY   - Для Microsoft 8086 Object Linker (LINK) полностью
                    совпадает  с  типом  PUBLIC.  MASM   обеспечивает
                    отдельный тип комбинации MEMORY для совместимости
                    с  программами  LINK,   различающими   эти   типы
                    комбинации.
         AT адрес - Все метки и адресные переменные  сегмента  должны
                    быть  вычислены  относительно  указанного адреса.
                    Адрес может  быть  представлен  любым  допустимым

                                   - 10 -
         
         
                    выражением,  не содержащим ссылок вперед. Сегмент
                    с  этим  типом  комбинации  обычно  не   содержит
                    программного  кода или инициализируемых данных, а
                    включает в себя адресные значения,  фиксированные
                    для вычислительной машины (например, адрес буфера
                    экрана).
               
               Если тип комбинации не указан, сегмент  ни  с  чем  не
         объединяется  и  рассматривается  как  отдельная программная
         единица.
               
               Класс сегмента определяет порядок следования сегментов
         в  памяти.  Сегменты одного класса загружаются в память один
         после другого  до  того,  как  начнут  загружаться  сегменты
         другого класса. 
               В  качестве  класса  сегмента  может быть указан любой
         идентификатор, на который распространяются все требования  и
         ограничения  языка   ассемблера   (в   том   числе   условия
         чувствительности   к  регистру).  Поскольку  класс  сегмента
         рассматривается  как  идентификатор,  он   не   может   быть
         определен где-либо еще в программе.
               Если   класс  не  указан,  LINK  копирует  сегменты  в
         исполнительный файл в той последовательности, в которой  они
         расположены   в   объектном  файле.  Эта  последовательность

         сохраняется до тех пор, пока LINK не обнаружит 2  или  более
         сегмента одного класса, после чего LINK начинает объединение
         сегментов.   Сегменты    одного    класса    копируются    в
         последовательные блоки исполнительного файла.
               Все сегменты имеют класс. Сегменты, для которых  класс
         не указан, считаются принадлежащими к классу с пустым именем
         и копируются в последовательные блоки памяти вместе с такими
         же сегментами.
               Число   сегментов,   принадлежащих  к  одному  классу,
         неограничено, но их суммарный объем не должен превышать 64К.
               Если  на  вход  программы  LINK   подается   несколько
         объектных  файлов,  правильное кодирование классов сегментов
         вообще говоря не обеспечивает правильную  последовательность
         сегментов     в     исполнительном     файле,    т.к.    эта
         последовательность  в  этом  случае   зависит   еще   и   от
         последовательности  объектных  файлов  в  командной  строке.
         Пусть, например, LINK обрабатывает 2 объектных файла, 1-й из
         которых содержит 2 сегмента с классами CODE и STACK, а 2-й -
         один сегмент класса DATA. В  исполнительном  файле  сегменты
         всегда  будут  расположены в последовательности CODE, STACK,
         DATA.   Если,   например,   программисту  необходимо,  чтобы
         сегменты  располагались  в  последовательности  CODE,  DATA,
         STACK,   ему  следует  создать  объектный  файл,  содержащий
         фиктивные сегменты с теми же именами и теми же классами,  но
         расположенные  в  нужном  ему  порядке, и в командной строке
         запуска  LINK  указать  его  первым.   Исходная   программа,
         соответствующая   такому   объектному   файлу   может  иметь
         следующий вид:
               
         code SEGMENT PARA PUBLIC 'CODE'
         code ENDS

                                   - 11 -
         
         
         data SEGMENT PARA PUBLIC 'DATA'
         data ENDS
         stack SEGMENT PARA STACK 'STACK'
         stack ENDS
               
               Этот прием не может быть использован для  программ  на
         языках  C,  FORTRAN,  PASCAL  и BASIC, т.к. компиляторы этих
         языков следуют определенным соглашениям о порядке сегментов,
         который не следует нарушать.
               Другим    способом    управления   последовательностью
         сегментов  является  кодирование  опции  /A  MASM,   которая
         предписывает  MASM  располагать сегменты в объектном файле в
         алфавитном  порядке.  Сочетание  опции  /A  с  формированием
         последоватеьности      фиктивных     сегментов     позволяет
         реализовывать   довольно   сложные   стратегии    управления
         структурой исполнительного файла.
               В  некоторых  ранних версиях MASM опция /A включена по
         умолчанию.
               Дополнительная информация о выравнивании и объединении
         сегментов программой LINK содержится в руководстве  "Система
         програмирования  на  макроассемблере  MS-DOS. Часть 1. Пакет
         макроассемблера MS-DOS", п.п. 3.4.1 и 3.4.3.

               
               
               
               
               
                         3.2. Директивы PROC и ENDP.

               
               Директивы  PROC  и   ENDP   служат   для   определения
         процедуры. Процедура представляет собой набор  инструкций  и
         директив,  образующих  некоторую   подпрограмму   в   рамках
         какого-либо сегмента.
               Процедура имеет следующий вид:
               
         имя PROC [[расстояние]]
               ...
            предложения
               ...
         имя ENDP
               
               Директивы PROC и ENDP обозначают соответственно начало
         и конец процедуры и должны быть  помечены  одним  и  тем  же
         именем, которое считается именем процедуры.
               Необязательное расстояние может принимать значения FAR
         и NEAR. Если этот параметр опущен, предполагается NEAR.
               Имя  процедуры  имеет  атрибуты  метки  и  может  быть
         использовано как операнд в инструкциях перехода, вызовах или
         циклах. 
               Возврат из процедуры должен быть выполнен  инструкцией
         RET. При этом следует помнить, что адрес возврата выбирается
         из стека (в соответствии со значениями регистров SS  и  SP).
         Для  процедур  с  расстоянием  NEAR  адрес  возврата состоит

                                   - 12 -
         
         
         только  из  смещения  и  занимает  в  стеке  2  байта.   Для
         FAR-процедур  он  занимает  4  байта  стека,  включая в себя
         базовый адрес (содержимое регистра сегмента) и смещение.
               Допускается вложенность процедур.
               Процедуре   могут   быть  переданы  параметры.  Вообще
         говоря, передача параметров и их распознавание  в  процедуре
         возлагается  на  программиста. Но при соблюдении стандартных
         соглашений, принятых в  языках  высокого  уровня,  параметры
         процедуры  могут быть отслежены командой трассировки стека K
         SYMDEB ("Система программирования на макроассемблере MS-DOS.
         Часть 1. Пакет макроассемблера", п.4.5.28).
               Согласно стандартным соглашениям параметры размещаются
         в стеке, верх которого определяется содержимым регистров  SP
         и SS.
               Пример передачи параметров:
                 ...
               PUSH AX    ; 2-й параметр
               PUSH BX    ; 1-й параметр
               CALL addup
               ADD  SP,4  ; уничтожение параметров
                 ...
         addup PROC NEAR      ; адрес возврата для NEAR - 2 байта
               PUSH BP        ; сохранение базового указателя
               MOV  BP,SP     ; загрузка базового регистра
               MOV  BX,[BP+4] ; адрес 1-го параметра
               MOV  AX,[BP+6] ; адрес 2-го параметра
                 ...
               POP  BP
               RET
         addup ENDP
               
               Из этого примера ясно, что адрес возврата запоминается
         в верхушке стека перед параметрами (стек "растет" от больших
         адресов к малым).
               Если  бы  процедура  специфицировала  расстояние  FAR,
         адрес возврата  занял  бы  4  байта,  а  смещение  для  1-го
         параметра составило бы 6 байтов.
               
               
               
               
               
               
                           3.3. Директива ASSUME.

               
               Синтаксис:
               
               ASSUME регистр-сегмента:имя-сегмента...
               ASSUME NOTHING
               
               Директива  ASSUME  устанавливает  регистр  сегмента  в
         качестве умалчиваемого регистра сегмента для адресации меток
         и переменных в указанном сегменте  или  группе.  Последующие
         ссылки  к метке или переменной при отсутствии явных указаний

                                   - 13 -
         
         
         разрешаются относительно данного регистра сегмента.
               В  качестве  регистра  сегмента могут быть указаны CS,
         DS, SS или ES.
               В качестве имени сегмента может быть специфицировано:
               1. Имя     сегмента,    предварительно    определенное
                  директивой SEGMENT.
               2. Имя группы, предварительно определенное  директивой
                  GROUP.
               3. Ключевое слово NOTHING.
               
               Наличие ключевого слова NOTHING отменяет текущий выбор
         конкретного  регистра  сегмента  или  текущий   выбор   всех
         регистров сегмента (для второй формы директивы).
               Выбор  регистра  сегмента  по  умолчанию  в  отдельном
         предложении языка ассемблера может быть отменен  при  помощи
         оператора    переключения     сегмента     (:)     ("Система
         программирования   на   макроассемблере   MS-DOS.  Часть  2.
         Введение в язык ассемблера", п.4.2).
               
               
               
               
               
                            3.4. Директива GROUP.
               
               
               Синтаксис:
               
               имя GROUP имя-сегмента,...
               
               Директива GROUP обозначает,  что  один  или  несколько
         сегментов  с  указанными  именами  логически  объединяются в
         группу с данным именем, что позволяет адресовать все метки и
         переменные в этих сегментах относительно начала группы, а не
         начала содержащего их  сегмента.  Имя-сегмента  должно  быть
         именем   сегмента,  определенного  директивой  SEGMENT,  или
         SEG-выражением ("Система программирования на макроассемблере
         MS-DOS.  Часть  2.  Введение в язык ассемблера", п.4.2). Оно
         должно быть уникальным. 
               Директива  GROUP  не  влияет   на   порядок   загрузки
         сегментов,   который  зависит  от  классов  сегментов  и  их
         расположения в объектном файле.
               Сегменты одной группы не  обязательно  будут  занимать
         непрерывную  область  памяти.  Они  могут  быть перемешаны с
         сегментами,   не   принадлежащими   этой   группе.   Однако,
         расстояние в байтах между  первым  байтом  первого  сегмента
         группы  и  последним  байтом  последнего  сегмента группы не
         должно превышать 64К. Таким образом,  если  сегменты  группы
         расположены  последовательно,  группа  может занимать до 64К
         оперативной памяти.
               Имена групп могут использоваться  в  директиве  ASSUME
         (п.3.3)   и   в   качестве   префикса   операнда   оператора
         переключения сегмента (:).
               Имя группы может появиться только  в  одной  директиве
         GROUP  в исходном файле. Если к группе принадлежат несколько

                                   - 14 -
         
         
         сегментов в исходном файле, все их имена должны быть указаны
         в одной директиве GROUP.
               
               
               
               
               
                             3.5. Директива END.
               
               
               Синтаксис:
               
               END [[выражение]]
               
               Директива   END  обозначает  конец  модуля.  Ассемблер
         игнорирует все предложения, следующие в  исходном  файле  за
         этой директивой.
               Необязательное   выражение   определяет   точку  входа
         программы, в которую будет передано управление  при  запуске
         программы  на  счет.  Значением  этого выражения должен быть
         адрес в одном из  программных  сегментов  данного  исходного
         файла.
               Если  выражение  опущено, точка входа не определяется.
         При попытке выполнения программы с незаданной  точкой  входа
         могут возникать ошибки, поэтому директиву END без параметров
         рекомендуется  кодировать  лишь  с  сегментами,  содержащими
         только поля данных.
               В  исходном  файле  может  быть определена только одна
         точка входа.

               
               
               
               
                          3.6. Директивы ORG и EVEN.

               
               
               Директивы ORG и EVEN позволяют задавать адрес  памяти,
         начиная   с   которого   будут   располагаться   последующие
         инструкции процессора.
               
               Директива ORG имеет следующий формат:
               
               ORG выражение
               
               Значение указанного выражения присваивается  указателю
         позиции,  и  адреса  последующих  инструкций  и данных будут
         начинаться с нового значения.
               Значением  выражения  должно  быть  абсолютное  число,
         точнее, все используемые в нем имена должны быть известны на
         1-м  проходе ассемблера. В качестве элемента выражения может
         быть использован знак указателя  позиции  ($),  обозначающий
         его текущее значение.
               

                                   - 15 -
         
         
               Пример:
               
               ORG 120h
               MOV AX,BX
               
               В этом примере инструкция MOV будет начинаться с байта
         120h текущего сегмента.
               
               
               Директива EVEN имеет следующий формат:
               
               EVEN
               
               Директива  EVEN  выравнивает  следующее  за  ней  поле
         данных  или  инструкцию  по  границе  слова, т.е. по четному
         адресу. Если текущеее значение  указателя  позиции  нечетно,
         директива   увеличивает  его  значение  на  1  и  генерирует
         инструкцию  NOP  (нет  операции).  Если   текущее   значение
         указателя   позиции   уже   четно,   никаких   действий   не
         производится.
               Директива EVEN не должна использоваться в сегментах  с
         типом выравнивания BYTE.


© KOAP Open Portal 2000