Исходный текст программы разделяется на следующие секции:
· данные
· неинициализированные данные
· константы
· код
Секция данных содержит данные, доступные для чтения и записи. Вся секция данных включается в exe-файл и может быть инициализирована данными.
Неинициализированные данные не имеют никакого содержания при запуске, и даже не включены в exe-файл непосредственно, это только часть памяти, зарезервированной Windows. Эта секция доступна для чтения и записи.
Допустим, мы не знаем, какие данные мы будем использовать. Допустим, что они будут введены в ходе выполнения программы с клавиатуры. Но знаем, какой размер (в байтах) будут иметь эти данные. Если мы объявим эти данные в секции данных (то есть.DATA), не заполняя их определенными значениями, например, запишем: var1 db? (это означает, что в памяти выделяется один байт, с ним связывается var1, но ничем этот байт не заполняется). В результате компиляции и последующей компоновки будет создан исполняемый модуль, в состав которого будет включен этот байт. В этот байт сможем с клавиатуры ввести данные.
Этот же байт можно объявить в секции неинициализированных данных (то есть.DATA?), тогда он не будет включен в исполняемый модуль, то этот модуль по размеру (в байтах) будет меньше, чем в первом случае.
Кроме того, в первом случае при загрузке программы из винчестера в оперативной памяти сразу же автоматически будет отведено место под байт. Во втором случае при загрузке операционной системе придется помимо места под программу выделять место под байт.
.DATA | .DATA? | |
+ | Быстрая загрузка | Маленький объем исполняемого модуля |
- | Большой объем исполняемого модуля | Медленная загрузка |
|
Секция констант аналогична секции данных, но доступна только для чтения (проще и быстрее объявлять константы в файлах для включения, и использовать их как непосредственные значения – то есть создаются файлы с расширением “*.inc”, в которых определяются имена и значения констант, которые могут быть использованы в алгоритме основной программы).
Секция кода содержит текст программы на языке ассемблера, реализующий требуемый алгоритм работы.
У вас представлен шаблон программы на языке ассемблера.
.386
.MODEL Flat, STDCALL
.DATA
Инициализированные данные>
.DATA?
Неинициализированные данные>
.CONST
<Константы>
.CODE
<Метка (точка входа в программу)>
<Код программы>
end <Метка (точка входа в программу)>
Проанализируем особенности этого шаблона.
Директива – указания компилятору на выполнение некоторых действий или служат для задания режима его работы. У директив нет аналогов среди машинных команд.
1) Директивы установки типа процессора – это директивы, которые определяют минимально возможный тип применяемого процессора (то есть на каком процессоре сможет работать данная программа, при этом программы для ранних моделей процессора будут работать с процессорами более поздних моделей)
.386
Данная директива указывает ассемблеру использовать набор команд для процессора 80386. Директивы установки типа процессора приведены в таблице 1.
Директива | Описание |
.8086 | Допустимы команды для процессоров 8086 и 8088. Команды для процессоров 80186 и более поздних не используются. Команды для 8087 разрешены. |
.186 | Разрешены команды для процессора 80186, команды для последующих процессоров не используются. |
.286 | Доступны команды для 80286, команды для более поздних процессоров не используются. |
.386 | Доступны команды для 80386, команды для более поздних процессоров не используются |
.486 | Доступны команды для 80486, команды для процессоров Pentium не используются |
.586 | Доступны команды для процессоров 80286, команды для более поздних процессоров Pentium. |
.287 | Используются команды вычислений с плавающей запятой для математического сопроцессора 80287. |
.387 | Используются команды вычислений с плавающей запятой для математического сопроцессора 80387. |
.686 | Доступны команды для процессоров Pentium Pro. |
Таблица 1. Директивы установки типа процессора.
|
Самым оптимальным является использование директивы.386, поскольку все процессоры ряда 80х86 совместимы на уровне системы команд снизу вверх.
2) Директивы выбора модели памяти.
.MODEL FLAT, STDCALL
С помощью директивы.MODEL можно выбрать одну из стандартных моделей памяти для программ на языке ассемблера. Модель памяти можно рассматривать как конфигурацию, которая определяет каким образом надо комбинировать используемые сегменты. Каждая модель имеет свои ограничения по максимальному размеру памяти, выделяемой для команд и данных.
В таблице 2 представлены модели памяти, используемые в MASM.
Модель | Описание |
Tiny (тонкая) | Коды и данные вместе должны занимать не более 64 Кбайт. |
Small (малая) | Код <= 64 Кбайт, данные <= 64 Кбайт. Один сегмент кодов, один сегмент данных. |
Medium (средняя) | Данные <= 64 Кбайт, код любого размера. Много сегментов кодов, один сегмент данных. |
Compact (компактная) | Код <= 64 Кбайт, данные любого размера. Один сегмент кодов, много сегментов данных. |
Large (большая) | Код > 64 Кбайт, данные > 64 Кбайт. Много сегментов кодов и данных. |
Huge (огромная) | Аналогична модели Large, за исключением того, что отдельные переменные, такие как массив, могут быть больше 64 Kбайт. |
Flat (плоская) | Нет сегментов, 32-разрядная адресация используется как для кодов, так и для данных. |
Таблица 2. Модели памяти, используемые в MASM
|
При разработке программ для Windows используется только плоская модель памяти (FLAT).
Ключевое слово STDCALL устанавливает порядок передачи параметров при вызове подпрограмм и функций справа налево.
Самый пpавый паpаметp первым помещается в стек. Пусть есть функция, которая использует три параметра: f(p1, p2, p3), которая описана в тексте исходной программы. При вызове функции с именем f(p1, p2, p3) ассемблерный код будет выглядеть так:
push p3; Поместить в стек тpетий паpаметp
push p2; Следом - втоpой
push p1; И, наконец, первый параметр
call f
Эта функция для своей работы берет параметры из стека: сначала первый, потом второй и затем третий
3) Директивы, определяющие начала секций программы.
.DATA.DATA?.CONST.CODE
Все четыре директивы определяют начало секций программы. В плоской модели памяти, используемой в Windows, нет сегментов, но для удобства виртуальное адресное пространство делится на логические секции. Hачало одной секции отмечает конец предыдущей. Есть две группы секций:
· Секции данных (определяются директивами.DATA,.DATА? и.CONST)
· Секции кода (определяется директивой.CODE).
Секции данных
.DATA - секция, содержащая инициализированные данные программы.
.DATA? - секция, содержащая неинициализированные данные программы.
.CONST - секция, содержащая объявления констант, используемых программой. Константы не могут быть изменены в ходе выполнения программы.
Программист не обязан задействовать все тpи секции. Необходимо объявлять только те, которые будут использоваться.
Секция кода
.CODE - секция, содержащая весь код программы (команды ассемблера).
Начало секции кода должно начинаться с непрерывной (без пробелов) строки, которая заканчивается символом двоеточия “: ”. Эта строка с двоеточием называется меткой точки входа в программу. В конце секции кода пишется служебное слова “end”, после которого указывается эта же метка, то есть обе метки должны быть идентичны. Вся программа на языке ассемблера должна располагаться между точкой входа и точкой выхода, определяемой служебным словом “end” с меткой, соответствующей точке входа.
ПРИМЕР:
.code
start: это метка
…
end start