Глава 7. Использование моделей памяти программы и сегментации

          Каждый процессор семейства 80х86 имеет не менее 4 сегментных
     регистров (CS,  DS, ES и SS). Эти регистры содержат значение сег-
     мента,  которое описывает физический блок памяти объемом  до  64К
     (или  до 4 гигабайт в процессоре 80386 и старше).  Все адреса вы-
     числяются с использованием в качестве базового значения одного из
     сегментных регистров.

          Смысл значения записанного в сегментном регистре бывает раз-
     личным и зависит от используемого в процессоре режиме адресации -
     реального (это единственный режим, который может использоваться в
     процессорах 8086 и 80186), когда сегментное значение представляет
     собой фактический номер параграфа,  или защищенного режима, когда
     сегментный регистр содержит селектор (не имеющий числового значе-
     ния).

          Операционная система или среда программы определяет, работа-
     ет программа в реальном или защищенном режиме. Если вы используе-
     те защищенный режим процессоров 80386 или 80486,  то операционная
     система определяет также, допустимы ли большие сегменты (до 4 ги-
     габайт). Турбо  Ассемблер  в  одинаковой степени поддерживает все
     эти операционные среды.

          В случае общей модели 80х86 программы состоят из  одного или
     более сегментов,  где каждый сегмент представляет собой физически
     различные части кода или данных (или код  и  данные),  к  которым
     можно обращаться  через сегментный регистр.  На основе этой общей
     схемы можно построить много производных схем.  Чтобы  упорядочить
     их, разработаны стандартные схемы памяти. Так как этих соглашений
     придерживаются многие языки высокого уровня,  в программах на Ас-
     семблере также следует это делать.

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

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

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

          В данной  главе описывается,  как использовать в вашей прог-
     рамме модели и сегменты, и какие директивы позволяют это делать.


Директива MODEL

Директива MODEL позволяет вам задать для программы несколько стандартных моделей сегментации. Вы можете также использовать ее для задания языка для процедур программы. Директива MODEL имеет следующий синтаксис: MODEL [модификатор_модели] модель_памяти [имя_сегмента_кода] [,[модификатор_языка] язык] [, модификатор_модели] В режиме MASM используется тот же синтаксис, но директива имеет вид .MODEL. "Модель_памяти" и "модификатор_модели" определяют модель сегментации памяти, используемую в программе. В применяемых в Турбо Ассемблере стандартных моделях можно использовать специальные сегменты для: - кода; - инициализированных данных; - неинициализированных данных; - инициализированных данных дальнего типа; - неинициализированных данных дальнего типа; - констант; - стека. Сегмент кода содержит обычно код модуля (но при необходимос- ти может также содержать данные). В целях совместимости с языками высокого уровня инициализированные данные и константы интерпрети- руются по-разному. Они содержат такие данные, как сообщения, ког- да важно начальное значение. Неинициализированные данные и стек содержат данные, начальные значения которых не существенны. Ини- циализированные данные дальнего типа (far) - это неинициализиро- ванные данные, которые не являются частью стандартного сегмента данных, и которые доступны только при изменении значения сегмент- ного регистра. Это же относится к неинициализированным данным дальнего типа, только вместо инициализированных данных здесь со- держатся неинициализированные данные. Специальные модели памяти задают, как можно ссылаться на эти сегменты с помощью сегментных регистров, и как они объединяются в группы (если это имеет место). При написании программы вы должны хранить эти сегменты отдельно, независимо от размера программы. Затем для объединения сегментов в группы вы можете выбрать соот- ветствующую модель. Если вы храните эти сегменты раздельно, и ва- ша программа увеличивается в размере, вы можете использовать большую модель. Единственным обязательным параметром директивы MODEL являет- ся модель памяти. Каждая стандартная модель памяти описывается в Таблице 7.1. Поле "модификатор_модели" позволяет вам изменить отдельные аспекты модели. Вы можете задавать при необходимости несколько модификаторов модели. Доступные модификаторы модели приведены в Таблице 7.2. Заметим, что в целях совместимости с MASM 5.2 вы можете за- давать спецификатор модели в двух местах. Если вы не используете спецификатор модели, Турбо Ассемблер подразумевает спецификатор NEARSTACK и USE32 (при выборе процессоров 80386 или 80486). Если не задано обратное, то основой считается DOS. В больших моделях кода для переопределения используемого по умолчанию имени сегмента кода используется необязательное поле "имя_сегмента_кода". Обычно это имя модуля с присоединенным к нему именем _TEXT. Стандартные модели памяти Таблица 7.1 ----------T---------T--------T--------------T-------------------¬ ¦Модель ¦ Код ¦Данные ¦Предполагаемые¦Описание ¦ ¦ ¦ ¦ ¦регистры ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦TINY ¦ ближний ¦ближний ¦cs=dgroup ¦Весь код и все дан-¦ ¦ ¦ ¦ ¦ds=ss=dgroup ¦ные комбинируются¦ ¦ ¦ ¦ ¦ ¦в одну группу с¦ ¦ ¦ ¦ ¦ ¦именем DGROUP. Эта¦ ¦ ¦ ¦ ¦ ¦модель используется¦ ¦ ¦ ¦ ¦ ¦для программ, ас-¦ ¦ ¦ ¦ ¦ ¦семблируемых в фор-¦ ¦ ¦ ¦ ¦ ¦мат .COM. Некоторые¦ ¦ ¦ ¦ ¦ ¦языки эту модель не¦ ¦ ¦ ¦ ¦ ¦поддерживают. ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦SMALL ¦ ближний ¦ближний ¦cs=_text ¦Код представляет¦ ¦ ¦ ¦ ¦ds=ss=dgroup ¦собой один сегмент.¦ ¦ ¦ ¦ ¦ ¦Все данные комбини-¦ ¦ ¦ ¦ ¦ ¦руются в группу с¦ ¦ ¦ ¦ ¦ ¦именем DGROUP. Это¦ ¦ ¦ ¦ ¦ ¦наиболее общая мо-¦ ¦ ¦ ¦ ¦ ¦дель, использующая-¦ ¦ ¦ ¦ ¦ ¦ся для автономных¦ ¦ ¦ ¦ ¦ ¦программ на Ассемб-¦ ¦ ¦ ¦ ¦ ¦лере. ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦MEDIUM ¦ дальний ¦ближний ¦cs= ¦Для кода использу-¦ ¦ ¦ ¦ ¦<модуль>_text ¦ется несколько сег-¦ ¦ ¦ ¦ ¦ds=ss=dgroup ¦ментов, по одному¦ ¦ ¦ ¦ ¦ ¦на модуль. Данные¦ ¦ ¦ ¦ ¦ ¦находится в группе¦ ¦ ¦ ¦ ¦ ¦с именем DGROUP. ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦COMPACT ¦ ближний ¦дальний ¦cs=_text ¦Код находится в од-¦ ¦ ¦ ¦ ¦ds=ss=dgroup ¦ном сегменте. Все¦ ¦ ¦ ¦ ¦ ¦ближние данные на-¦ ¦ ¦ ¦ ¦ ¦ходятся в группе с¦ ¦ ¦ ¦ ¦ ¦именем DGROUP. Для¦ ¦ ¦ ¦ ¦ ¦ссылки на данные¦ ¦ ¦ ¦ ¦ ¦используются даль-¦ ¦ ¦ ¦ ¦ ¦ние указатели. ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦LARGE ¦ дальний ¦дальний ¦cs= ¦Для кода использу-¦ ¦ ¦ ¦ ¦<модуль>_text ¦ется несколько сег-¦ ¦ ¦ ¦ ¦ds=ss=dgroup ¦ментов, по одному¦ ¦ ¦ ¦ ¦ ¦на модуль. Все¦ ¦ ¦ ¦ ¦ ¦ближние данные на-¦ ¦ ¦ ¦ ¦ ¦ходятся в группе с¦ ¦ ¦ ¦ ¦ ¦именем DGROUP. Для¦ ¦ ¦ ¦ ¦ ¦ссылки на данные¦ ¦ ¦ ¦ ¦ ¦используются даль-¦ ¦ ¦ ¦ ¦ ¦ние указатели. ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦HUGE ¦ дальний ¦дальний ¦cs= ¦То же, что модель¦ ¦ ¦ ¦ ¦<модуль>_text ¦LARGE (что касается¦ ¦ ¦ ¦ ¦ds=ss=dgroup ¦Турбо Ассемблера). ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦TCHUGE ¦ дальний ¦дальний ¦cs= ¦Это эквивалентно¦ ¦ ¦ ¦ ¦<модуль>_text ¦модели LARGE, но с¦ ¦ ¦ ¦ ¦ds=nothing ¦другими предположе-¦ ¦ ¦ ¦ ¦ss=nothing ¦ниями о сегментных¦ ¦ ¦ ¦ ¦ ¦регистрах. ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦TPASCAL ¦ ближний ¦дальний ¦cs=code, ds ¦Эта модель поддер- ¦ ¦ ¦ ¦ ¦=data, ss= ¦живается ранними¦ ¦ ¦ ¦ ¦nothing ¦версиями Турбо Пас-¦ ¦ ¦ ¦ ¦ ¦каля. В более позд-¦ ¦ ¦ ¦ ¦ ¦них версиях не тре-¦ ¦ ¦ ¦ ¦ ¦буется. ¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+---------+--------+--------------+-------------------+ ¦FLAT ¦ ближний ¦ближний ¦cs=_text ¦То же, что и модель¦ ¦ ¦ ¦ ¦ds=ss=flat ¦SMALL, но подходит¦ ¦ ¦ ¦ ¦ ¦для использования в¦ ¦ ¦ ¦ ¦ ¦OS/2. ¦ L---------+---------+--------+--------------+-------------------- Модификаторы модели Таблица 7.2 -----------------------------T----------------------------------¬ ¦ Модификатор модели ¦ Функция ¦ +----------------------------+----------------------------------+ ¦ NEARSTACK ¦ Указывает, что сегмент стека дол-¦ ¦ ¦ жен включаться в DROUP (если¦ ¦ ¦ группа DGROUP присутствует), а SS¦ ¦ ¦ должен указывать на DGROUP. ¦ ¦ ¦ ¦ ¦ FARSTACK ¦ Указывает, что сегмент стека не¦ ¦ ¦ должен включаться в DGROUP, а SS¦ ¦ ¦ должен указывать не nothing (не¦ ¦ ¦ определен). ¦ ¦ ¦ ¦ ¦ USE16 ¦ Задает, что все сегменты в¦ ¦ ¦ выбранной модели должны быть 16-¦ ¦ ¦ разрядными (при выборе процессора¦ ¦ ¦ 80386 или 80486). ¦ ¦ ¦ ¦ ¦ USE32 ¦ Задает, что все сегменты в¦ ¦ ¦ выбранной модели должны быть 32-¦ ¦ ¦ разрядными (при выборе процессора¦ ¦ ¦ 80386 или 80486). ¦ ¦ ¦ ¦ ¦ DOS, OS_DOS ¦ Задает, что прикладная программа¦ ¦ ¦ ориентируется на DOS. ¦ ¦ ¦ ¦ ¦ OS2, OS_OS2 ¦ Задает, что прикладная программа¦ ¦ ¦ ориентируется на DOS. ¦ L----------------------------+----------------------------------- "Язык" и "модификатор_языка" вместе определяют соглашения, используемые при вызове процедуры, а также используемый по умол- чанию характер начала и завершения кода каждой процедуры. Они оп- ределяют также как будут объявляться общедоступные идентификато- ры (которые использует компоновщик). Турбо Ассемблер будет автоматически генерировать код входа и выхода для каждой процеду- ры, используя одно из следующих языковых соглашений: PASCAL, C, CPP (C++), SYSCALL, BASIC, FORTRAN, PROLOG и NOLANGUAGE (язык не задан). Если вы не задаете язык, то Турбо Ассемблер предполагает использование NOLANGUAGE. Используйте "модификатор_языка" для задания кода начала и завершения процедур для WIndows или оверлейного загрузчика фирмы Borland. Можно задавать параметры NORMAL, WINDOWS, ODDNEAR и ODDFAR. Если вы не задаете параметр, то Турбо Ассемблер по умол- чанию подразумевает NORMAL. Примечание: Более подробно об этом рассказывается в Главе 16. Кроме того, вы можете переопределить используемый по умолча- нию язык и модификатор языка при определении процедуры. Подроб- ности можно узнать в Главе 10. При объявлении общедоступного идентификатора вы можете также переопределить язык.

Идентификаторы, генерируемые директивой MODEL

Когда вы используете директиву MODEL, Турбо Ассемблер созда- ет и инициализирует отдельные переменные, отражающие детали выб- ранной модели. Эти переменные путем использования операторов ус- ловного ассемблирования могут вам помочь написать код, зависящий от модели. О том, как можно использовать эти переменные для изме- нения процесса ассемблирования, рассказывается в Главе 15.

Идентификатор @Model

Идентификатор @Model содержит числовое значение, представля- ющее текущую используемую модель. Вы можете задавать его как текстовую макрокоманду с одним из следующих значений: 1 = действует модель tiny (крошечная) 2 = действует модель small (малая) или flat 3 = модель compact (компактная) 4 = medium (средняя) 5 = large (большая) 6 = huge (огромная) 7 = tchuge (Турбо Си) 0 = tpascal (Турбо Паскаль)

Идентификатор @32Bit

Идентификатор @32Bit содержит значение, определяющее, явля- ются ли сегменты в текущей модели 16- или 32-разрядными. Если вы задали в модели MODEL 16-разрядные сегменты, то это значение рав- но 0, а если 32-разрядные - то 1.

Идентификатор @CodeSize

Идентификатор @CodeSize указывает используемый по умолчанию размер указателя кода в текущей модели памяти. Если он установлен в 0, то модели памяти используют ближние указатели кода типа NEAR (модeли TINY, SMALL, FLAT, COMPACT, TPASCAL), а значение 1 указы- вает, что модели памяти используют дальние указатели FAR (все другие модели).

Идентификатор @DataSize

Идентификатор @DataSize указывает используемый по умолчанию размер указателя данных в текущей модели памяти. Если он установ- лен в 0, то модели памяти используют ближние указатели данных ти- па NEAR (модeли TINY, SMALL, FLAT, COMPACT, TPASCAL), а значение 1 указывает, что модели памяти используют дальние указатели FAR (все другие модели).

Идентификатор @Interface

Идентификатор @Interface дает информацию о языке и операци- онной системе, которые выбраны в операторе MODEL. Данная тексто- вая макрокоманда содержит число, биты которого представляют сле- дующие значения: Модификаторы модели Таблицы 7.3 -----------------T----------------------------------------------¬ ¦ Биты 0-7 ¦ Значение ¦ +----------------+----------------------------------------------+ ¦ 0 ¦ NOLANGUAGE ¦ ¦ 1 ¦ C ¦ ¦ 2 ¦ SYSCALL ¦ ¦ 4 ¦ PASCAL ¦ ¦ 5 ¦ FORTRAN ¦ ¦ 6 ¦ BASIC ¦ ¦ 7 ¦ PROLOG ¦ ¦ 8 ¦ CPP ¦ L----------------+----------------------------------------------- Бит 8 имеет нулевое значение для DOS и равен 1 для OS/2. Например, значение идентификатора @Interface показывает, что вы выбрали операционную систему OS/2 и язык Си.

Упрощенные сегментные директивы

После выбора модели памяти вы можете использовать упрощенные сегментные директивы для того, чтобы начинать отдельные сегменты. Эти упрощенные директивы вы можете использовать только после ди- рективы MODEL, которая задает для модуля модель памяти. В модуле допускается указывать столько директив сегментации, сколько необ- ходимо. Турбо Ассемблер для получения одного сегмента комбинирует все части с одинаковыми именами (как если бы вы ввели все эти фрагменты после одной директивы сегментации). Перечень директив содержится в Таблице 7.4. --------------------------T-------------------------------------¬ ¦ Директива ¦ Описание ¦ +-------------------------+-------------------------------------+ ¦ CODESEG [имя] ¦ Начинает или продолжает сегмент кода¦ ¦ ¦ модуля. Для моделей с дальним типом¦ ¦ ¦ кода вы можете задать имя, являющее-¦ ¦ ¦ ся фактическим именем сегмента. За-¦ ¦ ¦ метим, что таким образом вы можете¦ ¦ ¦ генерировать для модуля более одного¦ ¦ ¦ сегмента кода. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ .CODE [имя] ¦ Эквивалентна директиве CODESEG. До-¦ ¦ DATASEG ¦ пускается только для режима MASM.¦ ¦ ¦ Начинает или продолжает ближний или¦ ¦ ¦ инициализируемый по умолчанию сег-¦ ¦ ¦ мент данных. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ .DATA ¦ Эквивалентна директиве DATASEG. До-¦ ¦ CONST ¦ пускается только для режима MASM.¦ ¦ ¦ Начинает или продолжает сегмент¦ ¦ ¦ констант модуля. Постоянные данные¦ ¦ ¦ всегда являются ближними (NEAR) и¦ ¦ ¦ эквивалентны инициализированным дан-¦ ¦ ¦ ным. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ .CONST ¦ Эквивалентна директиве CONST. До-¦ ¦ UDATASEG ¦ пускается только для режима MASM.¦ ¦ ¦ Начинает или продолжает ближний или¦ ¦ ¦ не инициализируемый по умолчанию¦ ¦ ¦ сегмент данных. Соблюдайте осторож-¦ ¦ ¦ ность и включайте в этот сегмент¦ ¦ ¦ только неинициализированные данные,¦ ¦ ¦ в противном случае получаемая выпол-¦ ¦ ¦ няемая программа будет иметь больший¦ ¦ ¦ чем нужно размер. Описание распреде-¦ ¦ ¦ ления неинициализированных данных¦ ¦ ¦ можно найти в Главе 12. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ .DATA? ¦ Эквивалентна директиве UDATASEG.¦ ¦ ¦ Действует только для режима MASM. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ STACK [размер] ¦ Начинает или продолжает сегмент ¦ ¦ ¦ стека модуля. Необязательный пара-¦ ¦ ¦ метр "размер" определяет объем ре-¦ ¦ ¦ зервируемой для стека памяти (в сло-¦ ¦ ¦ вах). Если вы не задаете размер,¦ ¦ ¦ Турбо Ассемблер резервирует по умол-¦ ¦ ¦ чанию 200h слов (1 килобайт). ¦ ¦ ¦ ¦ ¦ ¦ В режиме MASM все метки, код или¦ ¦ ¦ данные, следующие за оператором¦ ¦ ¦ STACK, не будут рассматриваться как¦ ¦ ¦ часть сегмента стека. Однако в режи-¦ ¦ ¦ ме Ideal резервируется специальная¦ ¦ ¦ область, и сегмент стека остается¦ ¦ ¦ открытым, благодаря чему вы можете¦ ¦ ¦ добавлять метки и другие неинициали-¦ ¦ ¦ зированные данные. ¦ ¦ ¦ ¦ ¦ ¦ Директивы стека обычно требуется ис-¦ ¦ ¦ пользовать, если вы пишете на языке¦ ¦ ¦ Ассемблера автономную программу.¦ ¦ ¦ Большинство языков высокого уровня¦ ¦ ¦ сами создают для вас стек. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ .STACK [размер] ¦ Эквивалентна директиве STACK. Дей-¦ ¦ ¦ ствует в режиме MASM. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ FARDATE [имя] ¦ Начинает или продолжает дальний не-¦ ¦ ¦ инициализированный сегмент данных¦ ¦ ¦ (FAR) с заданным именем. Если вы не¦ ¦ ¦ задаете имя, Турбо Ассемблер исполь-¦ ¦ ¦ зует сегментное имя FAR_DATA. В мо-¦ ¦ ¦ дуле может содержаться более одного¦ ¦ ¦ неинициализированного сегмента дан-¦ ¦ ¦ ных типа FAR. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ .FARDATA [имя] ¦ Эквивалентна FARDATA. Действует в¦ ¦ ¦ режиме MASM. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ UFARDATA ¦ Начинает или продолжает дальний не-¦ ¦ ¦ инициализированный сегмент данных с¦ ¦ ¦ заданным именем. Если вы не задаете¦ ¦ ¦ имя, то Турбо Ассемблер использует¦ ¦ ¦ имя сегмента FAR_BSS. В модуле у вас¦ ¦ ¦ может быть несколько неинициализиро-¦ ¦ ¦ ванных сегментов данных типа FAR. ¦ ¦ ¦ ¦ +-------------------------+-------------------------------------+ ¦ .FARDATA? [имя] ¦ Эквивалентна UFARDATA. Действует¦ ¦ ¦ только в режиме MASM. ¦ L-------------------------+-------------------------------------- Примечание: Если вам требуется знать фактические име- на, имена классов и выравнивание сегментов, создаваемых по упрощенным директивам сегментации, см. Приложение A.

Идентификаторы, создаваемые упрощенными директивами сегментации

Когда вы используете упрощенные директивы определения сег- ментов, они создают переменные, отражающие детали распределения сегмента (аналогично тому, как это делает директива MODEL). Под- робнее об этом рассказывается в Главе 15. Идентификаторы упрощенных директив сегментации Таблица 7.5 ----------------------------T-----------------------------------¬ ¦ Идентификатор ¦ Значение ¦ +---------------------------+-----------------------------------+ ¦ @code ¦ Сегмент или группа, которые подра-¦ ¦ ¦ зумеваются для сегмента CS. ¦ ¦ ¦ ¦ ¦ @data ¦ Сегмент или группа, которые подра-¦ ¦ ¦ зумеваются для сегмента DS. ¦ ¦ ¦ ¦ ¦ @fardata ¦ Имя текущего сегмента FARDATA. ¦ ¦ ¦ ¦ ¦ @fardata? ¦ Имя текущего сегмента UFARDATA. ¦ ¦ ¦ ¦ ¦ @curseg ¦ Имя текущего сегмента. ¦ ¦ ¦ ¦ ¦ @stack ¦ Сегмент или группа, которые подра-¦ ¦ ¦ зумеваются для сегмента SS. ¦ L---------------------------+------------------------------------

Директива STARTUPCODE

Директива STARTUPCODE обеспечивает код инициализации, соот- ветствующий текущей модели и операционной системе. Она отмечает также начало программы. Эта директива имеет следующий синтаксис: STARTUPCODE или .STARTUP ; (только для режима MASM) Директива STARTUPCODE инициализирует регистры DS, SS и SP. Для моделей SMALL, MEDUIUM, COMPACT, LARGE, HUGE и TPASCAL Турбо Ассемблер устанавливает DS и SS в @data, а SP - в конец стека. Для моделей TINY и TCHUGE директива STARTUPCODE не изменяет сег- ментных регистров.

Идентификатор @Startup

Идентификатор @Startup помещается в начало кода инициализа- ции, который генерируется по директиве STARTUPCODE. Он представ- ляет собой ближнюю метку, отмечающую начало программы.

Директива EXITCODE

Директива EXITCODE используется для генерации кода заверше- ния, соответствующего текущей операционной системе. Вы можете использовать ее в модуле несколько раз (для каждой точки входа). Эта директива имеет следующий синтаксис: EXITCODE [возвращаемое_значение] В режиме MASM вы можете использовать следующий синтаксис: .EXIT [возвращаемое_значение] Необязательное "возвращаемое_значение" описывает число, ко- торое должно возвращаться в операционную систему. Если вы не за- даете возвращаемое значение, Турбо Ассемблер предполагает, что это значение содержится в регистре AX.

Определение общих сегментов и групп

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

Директива SEGMENT

Директива SEGMENT открывает сегмент. Все последующие код или данные до директивы ENDS, которая закрывает сегмент, будут вклю- чены в этот сегмент. В режиме Ideal директива SEGMENT имеет следующий синтаксис: SEGMENT имя [атрибуты] В режиме MASM директива SEGMENT имеет следующий синтаксис: имя SEGMENT [атрибуты] где "имя" - это имя сегмента. Назначать сегментам имена нужно в соответствии с их использованием. Примеры имен сегментов можно найти в Приложении A. В одном сегменте вы можете несколько раз открыть и закрыть сегмент с одним и тем же именем. Турбо Ассемблер выполняет конка- тенацию всех частей сегмента. Атрибуты сегмента нужно задавать только при первом его открытии. Атрибуты могут включать в себя все или некоторые значения атрибутов сегмента, которые определяют следующее: - атрибут комбинирования сегмента; - атрибут класса сегмента: - атрибут выравнивания сегмента; - атрибут размера сегмента; - атрибут доступа к сегменту. Примечание: Заметим, что Турбо Ассемблер обрабатывает значения атрибутов слева-направо.

Атрибут комбинирования сегментов

Атрибут комбинирования сегментов сообщает компоновщику, как нужно комбинировать сегменты различных модулей, имеющих одно и то же имя. Допустимые значения атрибута комбинирования сегмента пе- речисляются в следующем списке. Заметим, что если вы не указывае- те этот атрибут, Турбо Ассемблер предполагает PRIVATE. Атрибут комбинирования сегмента Таблица 7.6 --------------------T-------------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +-------------------+-------------------------------------------+ ¦ PRIVATE ¦ Сегмент не будет комбинироваться с други- ¦ ¦ ¦ ми сегментами с тем же именем вне данного ¦ ¦ ¦ модуля. Будет выполняться конкатенация ¦ ¦ ¦ сегмента с сегментами с тем же именем вне ¦ ¦ ¦ данного модуля для образования одного ¦ ¦ ¦ непрерывного сегмента. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ MEMORY ¦ То же, что PUBLIC. Будет выполняться кон- ¦ ¦ ¦ катенация сегмента с другими сегментами ¦ ¦ ¦ с тем же именем вне данного модуля для ¦ ¦ ¦ образования одного непрерывного сегмента, ¦ ¦ ¦ используемого как сегмент стека. Компо- ¦ ¦ ¦ новщик инициализирует регистры SS SP на- ¦ ¦ ¦ чальными значениями, так что они указы- ¦ ¦ ¦ вают на конец данного сегмента. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ COMMON ¦ Располагает данный сегмент и все другие ¦ ¦ ¦ сегменты с тем же именем по одному адре- ¦ ¦ ¦ су. Все сегменты с данным именем будут ¦ ¦ ¦ перекрываться и совместно использовать ¦ ¦ ¦ общую память. Размер полученного в ре- ¦ ¦ ¦ зультате сегмента будет равен размеру са- ¦ ¦ ¦ мого большого сегмента модуля. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ VIRTUAL ¦ Определяет специальный вид сегмента, ко- ¦ ¦ ¦ торый должен описываться внутри охватыва- ¦ ¦ ¦ ющего сегмента. Компоновщик интерпретиру- ¦ ¦ ¦ ет его как общую область и присоединяет ¦ ¦ ¦ его к охватывающему сегменту. Виртуальный ¦ ¦ ¦ сегмент наследует свои атрибуты из охва- ¦ ¦ ¦ тывающего сегмента. Директива ASSUME ¦ ¦ ¦ рассматривает виртуальный сегмент как ¦ ¦ ¦ часть порождающего сегмента. Во всех дру- ¦ ¦ ¦ гих отношениях виртуальный сегмент предс- ¦ ¦ ¦ тавляет собой общую область памяти, кото- ¦ ¦ ¦ рая используется разными сегментами. Это ¦ ¦ ¦ позволяет организовать совместное исполь- ¦ ¦ ¦ зование статических данных, которые бе- ¦ ¦ ¦ рутся различными модулями из включаемых ¦ ¦ ¦ файлов. ¦ ¦ ¦ ¦ +-------------------+-------------------------------------------+ ¦ AT xxx ¦ Располагает сегмент по абсолютному адресу ¦ ¦ ¦ параграфа. Адрес задается параметром xxx. ¦ ¦ ¦ Компоновщик для сегмента AT не порождает ¦ ¦ ¦ никаких данных или кода. Используйте ди- ¦ ¦ ¦ рективу AT для организации доступа по ¦ ¦ ¦ идентификатору к фиксированным адресам ¦ ¦ ¦ памяти (например, экран дисплея или об- ¦ ¦ ¦ ласти ПЗУ). ¦ L-------------------+--------------------------------------------

Атрибут класса сегмента

Атрибут класса сегмента - это заключенная в кавычки строка, которая помогает компоновщику определить соответствующий порядок сегментов при собирании их в программу из модулей. Компоновщик объединяет вместе в памяти все сегменты с одним и тем же именем класса. Типичным примером использования имени класса является объединение в группу всех сегментов кода программы (обычно для этого используется класс CODE). С помощью механизма класса груп- пируются также данные и неинициализированные данные.

Атрибут выравнивания сегмента

Атрибут выравнивания сегмента сообщает компоновщику, что нужно обеспечить размещение начала сегмента на заданной границе. Это важно, поскольку при правильном выравнивании доступ к данным в процессорах 80х86 выполняется быстрее. Допустимые значения это- го атрибута приведены в следующей таблице: Атрибут выравнивания сегмента Таблица 7.7 -----------------------T----------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +----------------------+----------------------------------------+ ¦ BYTE ¦ Выравнивание не выполняется. Сегмент ¦ ¦ ¦ начинается с границы следующего байта. ¦ ¦ ¦ ¦ ¦ WORD ¦ Начинает сегмент на границе следующего ¦ ¦ ¦ слова. ¦ ¦ ¦ ¦ ¦ DWORD ¦ Начинает сегмент на границе следующего ¦ ¦ ¦ двойного слова. ¦ ¦ ¦ ¦ ¦ PARA ¦ Начинает сегмент на границе следующего ¦ ¦ ¦ параграфа (выравнивание на 16 байт). ¦ ¦ ¦ ¦ ¦ PAGE ¦ Начинает сегмент на границе следующей ¦ ¦ ¦ страницы (выравнивание на 256 байт). ¦ ¦ ¦ ¦ ¦ MEMPAGE ¦ Начинает сегмент на границе следующей ¦ ¦ ¦ страницы памяти (выравнивание на 4 ки- ¦ ¦ ¦ лобайта). ¦ L----------------------+----------------------------------------- Если вы не задаете тип выравнивания, Турбо Ассемблер подра- зумевает PARA.

Атрибут размера сегмента

Если текущим выбранным процессором является процессор 80386, то сегменты могут быть 16- или 32-разрядными. Размер атри- бута сегмента сообщает компоновщику, какой размер вы хотите за- дать для конкретного сегмента. Допустимые значения атрибута при- ведены в следующей таблице: Значения атрибута размера сегмента Таблица 7.8 ----------------T-----------------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +---------------+-----------------------------------------------+ ¦ USE16 ¦ Сегмент будет 16-разрядным. Такой сегмент мо- ¦ ¦ ¦ жет содержать до 64К кода или данных. ¦ ¦ ¦ ¦ ¦ USE32 ¦ Сегмент будет 32-разрядным. Такой сегмент мо- ¦ ¦ ¦ жет содержать до 4 гигабайт кода или данных. ¦ L---------------+------------------------------------------------ Если в режиме MASM вы выбираете процессор 80386, то Турбо Ассемблер предполагает использование USE32. В режиме Ideal Турбо Ассемблер по умолчанию предполагает использование USE32.

Атрибут доступа к сегменту

В защищенном режиме для любого сегмента вы можете управлять доступом к определенным операциям с памятью, запрещая их. (Заме- тим, что данное средство поддерживается в настоящее время только компоновщиком Phar Lap. Если требуется использовать атрибут дос- тупа к сегменту, вы должны компилировать совместимый с ним объек- тный код с помощью параметра командной строки /op.) Атрибут дос- тупа к сегменту сообщает компоновщику, что к сегменту нужно применить специальные ограничения доступа. Допустимые значения данного атрибута приведены в следующей таблице: Значения атрибута доступа к сегменту Таблица 7.9 ----------------T-----------------------------------------------¬ ¦ Атрибут ¦ Значение ¦ +---------------+-----------------------------------------------+ ¦ EXECONLY ¦ Сегмент доступен только для выполнения. ¦ ¦ ¦ ¦ ¦ EXECREAD ¦ Сегмент доступен только для чтения и выполне- ¦ ¦ ¦ ния. ¦ ¦ ¦ ¦ ¦ READONLY ¦ Сегмент доступен только для чтения. ¦ ¦ ¦ ¦ ¦ READWRITE ¦ Сегмент доступен только для чтения и записи. ¦ L---------------+------------------------------------------------ Если вы выбираете один из этих атрибутов или используете USE32, компоновщик Phar Lap предполагает, что сегмент предназна- чен для выполнения в защищенном режиме. Если вы выбираете USE32, но не задаете одно из этих значений, Турбо Ассемблер предполагает использование атрибута READONLY.

Директива ENDS

Вы можете использовать директиву ENDS для закрытия сегмента, после чего данные в него больше включаться не будут. Директиву ENDS следует использовать для закрытия любого сегмента, открытого по директиве SEGMENT. Сегменты, открытые с помощью упрощенных ди- ректив определения сегментов, не требуют директивы ENDS. Директива ENDS имеет следующий синтаксис: ENDS [имя] В режиме MASM вы можете использовать следующий синтаксис: имя ENDS где "имя" задает имя сегмента, который должен быть закрыт. Если имя не согласуется с именем текущего открытого сегмента, Турбо Ассемблер будет выводить сообщение об ошибке. Если имя не задает- ся, Турбо Ассемблер подразумевает текущий сегмент.

Директива GROUP

---------------------------------------------------------------- Директива GROUP может использоваться для присваивания сег- ментов группам. Группы позволяют вам для доступа ко всем сегмен- там группы задавать один сегмент. В режиме Ideal директива GROUP имеет следующий синтаксис: GROUP имя имя_сегмента [, имя_сегмента.] В режиме MASM вы можете использовать следующий синтаксис: имя GROUP имя_сегмента [, имя_сегмента.] где "имя" представляет собой имя группы, а "имя_сегмента" - это имя сегмента, которое вы хотите присвоить группе.

Директива ASSUME

Если вы хотите получить доступ к данным сегмента, сегментный регистр должен загружаться корректным значением сегмента. Часто это нужно делать вам самим. Например, для загрузки в регистр DS адреса текущего сегмента данных дальнего типа вы можете использо- вать команды: MOV AX,@fardata MOV DS,AX Когда программа загружает в сегментный регистр значение сег- мента, вы можете использовать этот сегментный регистр для доступа к данным в сегменте. Это быстро утомляет, и вы начинаете забывать каждый раз при обработке данных в памяти задавать сегментный ре- гистр (или у вас недостаточно практики в программировании). Чтобы указать Турбо Ассемблеру, что нужно связать сегментный регистр с именем сегмента или группы, используйте директиву ASSUME. Это позволяет Турбо Ассемблеру быть "достаточно проница- тельным" и использовать при доступе к данным конкретный сегмент. Фактически, Турбо Ассемблер использует также информацию о связи между сегментным регистром и именем сегмента также и для других целей: в режиме MASM значение, которое подразумевается для регистра CS, используется для определения сегмента или группы, к которому принадлежит метка. Таким образом, регистр CS должен кор- ректно задаваться в директиве ASSUME, в противном случае Турбо Ассемблер при каждом определении метки или процедуры будет сооб- щать об ошибке. Директива ASSUME имеет следующий синтаксис: ASSUME сегм_регистр : выражение [, сегм_регистр : выражение] или ASSUME nothing где "сегм_регистр" - это один из регистров CS, DS, ES или SS. Ес- ли вы задаете процессор 80386 или 80486, то можете использовать регистры FS и GS. "Выражение" может быть любым выражением, при вычислении которого получается имя сегмента или группы. В против- ном случае может использоваться ключевое слово NOTHING. Это клю- чевое слово отменяет связь между сегментным регистром и любым сегментом или именем группы. Директива ASSUME NOTHING отменяет связь между всеми сегмент- ными регистрами и сегментом или именем группы. Вы можете использовать директиву ASSUME при модификации сег- ментного регистра или в начале процедуры для задания в этой точке предположений о сегментных регистрах. На практике ASSUME исполь- зуется обычно в начале модуля и иногда внутри него. Если вы ис- пользуете оператор MODEL, то Турбо Ассемблер назначает директиву ASSUME по умолчанию. Если вы не задаете в директиве ASSUME значение, то ранее за- данное в ней значение не изменяется. Например, в следующем фрагменте программы показано, как мож- но загрузить текущий инициализированный сегмент данных дальнего типа в регистр DS, обратиться через этот регистр к памяти и восс- тановить регистр DS в значение сегмента данных: MOV AX,@fardata MOV DS,AX ASSUME DS:@fardata: MOV BX,<переменная_данных_дальнего_типа> MOV AX,@data MOV DS,AX ASSUME DS:@data

Переопределение сегмента

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

Изменение упорядочивания сегментов в модуле

Порядок сегментов в каждом модуле определяет начальное раз- мещение сегментов в программе компоновщиком. В MASM 1.0 и 2.0 сегменты передавались компоновщику в алфавитном порядке. В Турбо Ассемблере предусмотрены директивы (только в режиме MASM), кото- рые позволяют воспроизвести это поведение. Заметим, что данные директивы действуют так же, как парамет- ры командной строки /A и /S.

Директива .ALPHA

Директива .ALPHA определяет упорядочивание сегментов по ал- фавиту. Данная директива сообщает Турбо Ассемблеру, что сегменты в объектном файле нужно разместить в алфавитном порядке (в соот- ветствии с именами сегментов). Она имеет синтаксис: .ALPHA

Директива .SEQ

Директива .SEQ определяет последовательное упорядочивание сегментов и сообщает Турбо Ассемблеру, что сегменты нужно поме- щать в объектный файл в том порядке, в котором они встречаются в исходном файле. Поскольку это поведение предполагается Турбо Ас- семблером по умолчанию, директиву .SEQ используют обычно только для переопределения предыдущей директивы .ALPHA. Данная директива имеет следующий синтаксис: .SEQ

Директива DOSSEG: упорядочивание сегментов в порядке DOS

Обычно компоновщик упорядочивает сегменты в последовательном порядке - в том порядке, в котором он их обрабатывает при генера- ции программы. Если вы включаете в любой модуль программу дирек- тиву DOSSEG, то это указывает компоновщику, что вместо этого упорядочивания нужно использовать порядок сегментов, принятый в DOS. Компоновщик при этом выполняет в получаемой программе следу- ющее упорядочивание: - сначала идут сегменты с именем класса CODE (обычно сегмен- ты кода); - затем следуют сегменты, не имеющие имени класса CODE и не являющиеся частью DGROUP; - сегменты, являющиеся частью DGROUP в следующем порядке: 1. сегменты, не являющиеся классами BSS и STACK (обыч- но неинициализированные данные); 2. сегменты класса BSS (обычно инициализированные дан- ные); 3. сегменты класса STACK (область стека). Примечание: Не используйте директиву DOSSEG, в прог- раммах, не являющихся автономными программами на Ассембле- ре. Сегменты в группе DGROUP располагаются в том порядке, в ко- тором они определены в исходных модулях. Приведем синтаксис DOSSEG: DOSSEG

Изменение размера стека

Начальный и завершающий код процедур работает с регистрами, указывающими на стек. В процессоре 80386 или 80486 сегменты могут быть 16- или 32-разрядными. Таким образом, перед генерацией кор- ректного начального и завершающего кода Турбо Ассемблеру нужно знать корректный размер стека. Если вы выбираете стандартную модель с помощью директивы MODEL, размер стека выбирается автоматически. В Турбо Ассемблере предусмотрены директивы, которые могут установить или переопределить используемый по умолчанию при гене- рации начального и завершающего кода размер стека. Список этих директив приведен в следующей таблице: Директивы модификации размера стека Таблица 7.10 -----------------------T----------------------------------------¬ ¦ Директива ¦ Значение ¦ +----------------------+----------------------------------------+ ¦ SMALLSTACK ¦ Указывает, что стек 16-разрядный. ¦ ¦ ¦ ¦ ¦ LARGESTACK ¦ Указывает, что стек 32-разрядный. ¦ L----------------------+-----------------------------------------
                       Назад | Содержание | Вперед