Модели памяти

Общая структура программы

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

 

STACKSG SEGMENT STACK ; сегмент стека

DB 128 DUP(?)

STACKSG ENDS

 

DATASG SEGMENT ; сегмент данных

<описания переменных>

DATASG ENDS

 

CODESG SEGMENT ; сегмент команд

ASSUME CS: CODESG, DS: DATASG, SS: STACKSG

S: MOV AX, DATASG

MOV DS, AX ; загрузить DS

... ; остальные команды

MOV AX, 4C00h ; завершить программу с кодом возврата 0
INT 21h ; выполнить прерывание 21h

CODESG ENDS

 

END S ; конец программы, точка входа

 

Сегмент стека описан с параметром STACK, поэтому в самой программе не нужно загружать сегментный регистр SS. Сегмент стека следует описывать всегда, даже когда не предполагается его использовать, т.к. стек использует операционная система для обработки прерываний. Рекомендуемый размер сегмента стека с запасом составляет 128 байтов. Если программа сама использует стек, то под него отводится столько места, сколько требуется, плюс 128 байтов.

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

Обязательным последним действием программы в сегменте кода должен быть вызов специальной функции под номером 4C. Функция определена за прерыванием 21h и предназначена для выполнения корректного выхода в операционную систему MS-DOS после завершения работы программы. Для выполнения функции в регистр AH должен быть помещен код 4Ch, а в регистр AL – код выхода. Как правило, успешное завершение программы соответствует коду выхода 0.

В конце программы следует указать директиву END – признак конца программы. Все строки после этой директивы игнорируются. В директиве указывается метка команды, с которой должно начаться выполнение программы (точка входа, в нашем примере эта метка S).

Все предложения должны входить в состав программного сегмента. Размещать их вне сегментов недопустимо. Вне сег­ментов разрешено указывать только директивы информационного характера (например, EQU). В сегменте данных разрешается размещать команды, а в сегменте команд описания переменных.

Для программ, содержащих по одному сегменту кода, данных и стека, описание директив сегментации можно упростить. Для этого в транслятор TASM введена возможность использования упрощенных директив сегментации (табл. 6).

 

Табл. 6. Упрощенные директивы определения сегмента.

Режим MASM Режим IDEAL Назначение
.CODE [имя] CODESEG [имя] Начало или продолжение сегмента кода.
  .DATA   DATASEG Начало или продолжение сегмента инициализированных данных. Также используется для определения данных типа NEAR.
.CONST CONST Начало или продолжение сегмента констант модуля
  .DATA?   UDATASEG Начало или продолжение сегмента неинициализированных данных. Также используется для определения данных типа NEAR.
.STACK [размер] STACK [размер] Начало или продолжение сегмента стека модуля. Параметр [размер] задает размер стека.
.FARDATA [имя] FARDATA [имя] Начало или продолжение сегмента инициализированных данных типа FAR.
.FARDATA? [имя] UFARDATA [имя] Начало или продолжение сегмента неинициализированных данных типа FAR.

 

 

Совместно с упрощенными директивами сегментации используется директива модели памяти MODEL, которая позволяет управлять размещением сегментов и выполняет функции директивы ASSUME. Директива связывает сегменты с сегментными регистрами (но явно инициализировать DS все равно необходимо). Формат директивы следующий:

 

MODEL <модель памяти>,[<модификатор директивы>],[<язык>],[<модификатор языка>]

 

Параметр "модель памяти" является обязательным. Он определяет модель сегментации памяти: набор и размеры сегментов данных и кода, способ связывания сегментов и сегментных регистров. В табл. 7 приведены возможные значения параметра.

 

Табл. 7. Модели памяти.

Модель Тип кода Тип данных Описание модели
  TINY   NEAR   NEAR Код и данные объединены в одну группу с именем DGROUP.
  SMALL   NEAR   NEAR Код занимает один сегмент, данные объединены в одну группу с именем DGROUP. Модель обычно используют для большинства программ на ассемблере.
    MEDIUM     FAR     NEAR Код занимает несколько сегментов, по одному на каждый объединяемый модуль. Все ссылки на передачу управления типа FAR. Данные объединены в одной группе; все ссылки на них типа NEAR.
COMPACT NEAR FAR Код в одном сегменте; ссылка на данные типа FAR
LARGE FAR FAR Код и данные расположены в нескольких сегментах.

 

 

Параметр "модификатор директивы" уточняет особенности выбранной модели (табл. 8). Для микропроцессоров 386 и выше сегменты могут быть 16 или 32-разрядными. При use16 используется 16-разрядная адресация, а при use32 – 32-разрядная. В первом случае размер сегмента не должен превышать 64 Кбайт, во втором – 4 Гбайт.

 

 

Табл. 8. Модификаторы модели памяти.

Модификатор Назначение
USE16 Сегменты выбранной модели 16-разрядные.
USE32 Сегменты выбранной модели 32-разрядные.
DOS Программа будет работать в MS-DOS.

Параметры "язык" и "модификатор языка" необязательные и задают особенности вызова процедур при связывании программ на различных языках программирования. При использовании директивы MODEL транслятор делает доступными несколько идентификаторов, к которым можно обращаться, чтобы получить информацию о параметрах модели (табл. 9).

 

 

Табл. 9. Идентификаторы, создаваемые директивой MODEL.

Идентификатор Значение переменной
@CODE Физический адрес сегмента кода.
@DATA Физический адрес сегмента данных типа NEAR.
@FARDATA Физический адрес сегмента данных типа FAR.
@FARDATA? Физический адрес сегмента неинициализированных данных типа FAR.
@CURSEG Физический адрес сегмента неинициализированных данных типа NEAR.
@STACK Физический адрес сегмента стека.

 

 

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

 

MASM ; режим работы MASM

MODEL SMALL ; модель памяти SMALL

.DATA ; начало сегмента данных

... ; определение данных

.STACK ; начало сегмента стека

DB 128 DUP(?) ; размер стека 128 байт

.CODE ; начало сегмента кода

S: MOV AX, @DATA ; получить адреса сегмента данных

MOV DS, AX ; адрес сегмента данных в регистр AX

... ; остальные команды программы

MOV AX, 4C00h ; завершить программу с кодом возврата 0
INT 21h ; выполнить прерывание 21h

END S ; конец программы, точка входа

 

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

Контрольные вопросы

1. В чем заключается идея сегментирования адресов?

2. Что представляет и как описывается программный сегмент?

3. В чем состоит назначение сегментных регистров?

4. Объясните назначение и применение директив SEGMENT и ASSUME.

5. Опишите структуру программы на языке ассемблера.

6. Для чего используется модели памяти?