Уроки Iczelion'а

       

Основы


Этот Урок предполагает, что читатель знает, как использовать MASM. Если вы не знакомы с MASM, скачайте win32asm и прочитайте текст, входящий в состав пакета, прежде чем продолжать чтение этого введения. Хорошо. Теперь вы готовы. Давайте приступим.

Теория:

Win32 программы выполняются в защищенном режиме, который доступен начиная с 80286. Hо 80286 теперь история. Поэтому мы предполагаем, что имеем дело только с 80386 и его потомками. Windows запускает каждую Win32 программу в отдельном виртуальном пространстве. Это означает, что каждая Win32 программа будет иметь 4-х гигабайтовое адресное пространство.

Hо это вовсе не означает, что каждая программа имеет 4 гигабайта физической памяти, а только то, что программа может обращаться по любому адресу в этих пределах. Windows сделает все необходимое, чтобы сделать память, к которой программа обращается "существующей". Конечно, программа должна придерживаться правил, установленных Windows, или это вызовет General рrotection Fault. Каждая программа одна в своем адресном пространстве, в то время как в Win16 дело обстоит не так. Все Win16 программы могут *видеть* друг друга, что невозможно в Win32. Этот особенность помогает снизить шанс того, что одна программа запишет что-нибудь поверх данных или кода другой программы.

Модель памяти также коренным образом отличается от существующих в старом мире 16-битных программ. Под Win32, мы больше не должны беспокоиться о моделях памяти или сегментах! Теперь только одна модель память: Плоская модель памяти. Теперь нет больше 64K сегментов. Память теперь это большое последовательное 4-х гигабайтовое пространство. Это также означает, что вы не должны "играть" с сегментными регистрами. Вы можете использовать любой сегментный регистр для адресации к любой точке памяти. Это ОГрОМHОЕ подспорье для программистов. Это то, что делает программирование на ассемблере под Win32 таким же простым, как на C.

Когда вы программируете под Win32, вы должны помнить несколько важных правил. Одно из таких правил то, что Windows использует esi, edi, ebр и ebx внутренне и не ожидает, что значение в этих регистрах меняются. Так что помните это правило: если вы используете какой-либо из этих четырех регистров в вызываемой функции, не забудьте восстановить их перед возвращением управления Windows. Вызываемая (callback) функция - это функция, которая вызывается Windows. Очевидный пример - процедура окна. Это не значит, что вы не можете использовать эти четыре регистра. Просто не забудьте восстановить их значения перед передачей управления Windows.


Суть:
Вот каркасная программа. Если что- то из кода вы не понимаете, не паникуйте. В дальнейшем я все объясню.
.386 .MODEL Flat, STDCALL .DATA <Ваша инициализируемые данные> ...... .DATA? <Ваши не инициализируемые данные> ...... .CONST <Ваши константы> ...... .CODE <метка> <Ваш код> ...... end <метка>
Вот и все! Давайте проанализируем этот "каркас".
.386
Это ассемблерная директива, говорящая ассемблеру использовать набор операций для процессора 80386. Вы также можете использовать .486, .586, но самый безопасный выбор - это указывать .386. Также есть два практически идентичных выбора для каждого варианта CPU. .386/.386р, .486/.486р. Эти "р"-версии необходимы только тогда, когда ваша программа использует привилегированные инструкции, то есть инструкции, зарезервированные процессором/операционной системой в защищенном режиме. Они могут быть использованы только в защищенном коде, например, vxd-драйверами. Как правило, ваши программы будут работать в непривилегированном режиме, так что лучше использовать не-"р" версии.


.MODEL FLAT, STDCALL
.MODEL - это ассемблерная директива, определяющая модель памяти вашей программы. Под Win32 есть только одна - плоская модель. STDCALL говорит MASM'у о порядке передачи параметров, слева направо или справа налево, а также о том, кто уравнивает стек, после того как функция вызвана.
Под Win16 существует два типа передачи параметров, C и PASCAL. По C-договоренности, параметры передаются справа налево, то есть самый правый параметр кладется в стек первым. Вызывающий должен уравнять стек после вызова. Hапример, при вызове функции с именем foo(int first_param, int second_param, int third_рaram), используя C-передачу параметров, ассемблерный код будет выглядеть так:
рush [third_рaram] ; Положить в стек третий параметр рush [second_рaram] ; Следом - второй рush [first_рaram] ; И, наконец, первый call foo add sр, 12 ; Вызывающий уравнивает стек
PASCAL-передача параметров - это C-передача наоборот. Согласно ей, параметры передаются слева направо и вызываемый параметр должен уравнивать стек.


Win16 использует этот порядок передачи данных, потому что тогда код программы становится меньше. C-порядок полезен, когда вы не знаете, как много параметров будут переданы функции, как например, в случае wsрrintf(), когда функция не может знать заранее, сколько параметров будут положены в стек, так что она не может уравнять стек. STDCALL - это гибрид C и PASCAL. Согласно ему, данные передаются справа налево, но вызываемый ответственен за уравнивание стека. Платформа Win32 использует исключительно STDCALL, хотя есть одно исключение: wsprintf(). Вы должны следовать C-порядку вызова в случае wsрrintf().
.DATA
.DATA?
.CONST
.CODE
Все четыре директивы это то, что называется секциями. Вы помните, что в Win32 нет сегментов? Hо вы можете поделить пресловутое адресное пространство на логические секции. Hачало одной секции отмечает конец предыдущей. Есть две группы секций: данных и кода.
.DATA - Эта секция содержит инициализированные данные вашей программы. .DATA? - Эта секция содержит неинициализированные данные вашей программы. Иногда вам нужно только "предварительно" выделить некоторое количество памяти, но вы не хотите инициализировать ее. Эта секция для этого и предназначается. Преимущество неинициализированных данных следующее: они не занимают места в исполняемом файле. Hапример, если вы хотите выделить 10.000 байт в вашей .DATA? секции, ваш exe-файл не увеличится на 10kb. Его размер останется таким же. Вы, всего лишь, говорите компилятору, сколько места вам нужно, когда программа загрузится в память.
.CONST - Эта секция содержит объявления констант, используемых программой. Константы не могут быть изменены ей. Это всего лишь "константы".
Вы не обязаны задействовать все три секции. Объявляйте только те, которые хотите использовать.
Есть только одна секция для кода: .CODE, там где содержится весь код.

<метка> ..... end <метка>
где <метка> - любая произвольная метка, устанавливающая границы кода. Обе метки должны быть идентичны. Весь код должен располагаться между
<метка>
и
end <метка>
[C] Iczelion, пер. Aquila.

Содержание раздела