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

Фиг. 3.9 иллюстрирует такие сегментные операции. В этом примере  имеется три  сегмента: DATA, BUFFER  и CODE. Имена  для них выбраны  произвольно. Их выбирает программист, а для ассемблера они не имеют  значения. Например,  вы  можете назвать  сегмент  именем  CODE, а  использовать его только для данных и наоборот. Лучше всего, конечно, называть  сегменты так, чтобы  их имена имели  какой-то смысл в  данной программе. В нашем примере  сегменты DATA и BUFFER оба имеют  внутри ячейку данных.  Вряд ли  реальная программа  будет задавать  сегмент лишь с  одной ячейкой памяти, но сейчас это  служит для  примера. Если программа  обращается  к данным во  многих участках  адресуемого в 8088 пространства,  то ей требуется много определений  сегментов. Например, программа  управления устройствами доступа IBM  PC  может обращаться к  памяти в  системной  области данных,  устанавливать векторы прерываний в  начале памяти и выполняться как  программа в  любом другом месте. Каждая из этих  областей является  сегментом и должна быть определена в программе.

Утверждение ASSUME на Фиг. 3.9 предписывает ассемблеру работать  с учетом следующей  установки сегментных регистров: регистр CS содержит начальный адрес сегмента CODE, регистр DS указывает на DATA,  а регистр ES  определяет  сегмент  BUFFER. Утверждение  ASSUME  (полагать,  считать -  прим. перев.)  означает именно  то, что  оно  предписывает  ассемблеру. Ассемблер  обрабатывает  исходный текст  программы предполагая,  что  сегментные регистры  установлены как  указано в этом утверждении. Установка сегментных регистров, сделанная в этом утверждении, остается  при ассемблировании в  силе пока  другое такое же утверждение не определит новые установки. Ассемблер обрабатывает эти  утверждения последовательно, даже  если программа  ветвится и закручивается  в циклы.  Утверждение ASSUME  остается в  силе, пока ассемблер  не встретит  при последовательном  просмотре  программы следующее.  Заметим, что в утверждении  ASSUME не обязано  определять  все сегментные  регистры. В  нашем примере  не объявлен  регистр SS.  На практике содержимое сегментного  регистра может быть  временами и неизвестно  в  программе.  В этих  случаях утверждение  ASSUME должно указывать сегмент NOTHING. Например, утверждение

  ASSUME  ES:NOTHING

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

Важно отметить, что утверждение ASSUME не генерирует команд машинного языка. Это  директива ассемблеру  полагать, что сегментные  регистры установлены в соответствии  с указанной в этом утверждении  информацией.  Добиться  правильное  установки сегментов  -  забота  программиста. Аналогично, ассемблер не может проверить, что утверждение ASSUME  при  выполнении будет  соответствовать  содержимому  сегментных  регистров. Из-за  того,  что  программа может  прийти к  любому конкретному  ASSUME множеством разных путей,  за его  корректность отвечает программист.  В нашем примере предполагается,  что сегментные регистры устанавливаются  до выполнения данного куска программы. Если они установлены неверно, то программа будет выполняться неправильно даже если ассемблирование прошло успешно.

Первая команда увеличивает значение VAR1, находящейся в сегменте данных. Ассемблер полагает, что регистр DS указывает на сегмент  DATA в соответствии  с утверждением  ASSUME. Поскольку  регистр DS  предполагается при  использовании данных по умолчанию, то для этой  команды ассемблер не  генерирует сегментный префикс. Сформированная  этой инструкцией 4-байтовая машинная команда не содержит сегментного  префикса. 

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

Префиксный  байт 26H  говорит процессору  использовать при создании  20-битового адреса памяти регистр ES.  В колонке объектных кодов на  листинге ассемблер отмечает префиксную команду двоеточием.

Третья  команда  изменяет переменную  VAR3  в  сегменте  CODE.  Утверждение ASSUME связывает этот сегмент с регистром CS. Ассемблер  автоматически  генерирует соответствующий  префикс  переназначения  сегмента. В  данном  случае префикс  2EH  предписывает процессору  использовать  при  вычислении  исполнительного  адреса регистр CS.

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

Программа может  использовать утверждение SEGMENT для передачи  информации  другим  программам.  Оператор  SEGMENT  может задавать  выравнивание сегмента в памяти,  способ его комбинирования с другими  сегментами и  имя его типа. Для  программистов IBM  PC особый  интерес представляют два  вида выравнивания сегментов. Выравнивание  по  параграфам  (тип PARA)  размещает  начало сегмента  с  начала  параграфа -  ячейки памяти, адрес которой в памяти  кратен 16-ти .  Это означает,  что  первый байт  сегмента  будет иметь смещение 0  относительно значения сегментного  регистра. Выравнивание по байтам  (тип BYTE), наоборот,  размещает сегмент  в любом  месте памяти. В  этом случае сегментный регистр может  и не указывать на первый байт  сегмента. В программе  может потребоваться  ненулевое смещение для  доступа к началу сегмента.

Различные  способы  связывания  сегментов задает  параметр типа  связи. Особенно это  полезно при модульном  программировании.  Описание PUBLIC приводит к объединению всех сегментов с одинаковыми  именами в один  большой  сегмент.  Например, можно  объединить все  сегменты кодов.  Это приведет к соединению  разных подпрограмм в их  собственных модулях с главной процедурой. Другой полезный тип связи  - AT, при указании  которого  в сочетании с  адресным выражением,  сегмент располагается  по  заданному  абсолютному  адресу.  Такое  объявление необходимо  при работе с данными  в фиксированном месте,  например, с векторами прерываний в начале памяти.

Намного более  полное  описание описание  утверждения SEGMENT  можно найти  в справочном томе к макроассемблеру IBM PC. Некоторые  из  возможностей оператора  SEGMENT  мы  будем использовать  далее в  примерах.