Директива USES
Надо сказать, что ассемблер MASM, начиная с версии 5.1, имеет некоторые новые директивы, упрощающие порядок передачи параметров и создания фрейма стека. Для этого вы можете использовать директиву USES вместе с директивой PROC. Они сообщат ассемблеру, какие именно регистры будут использоваться в функции. Директива USES оберегает вас от всей рутины, связанной с определением стекового фрейма и подстановками переменных. Более того, она генерирует код пролога и эпилога для сохранения регистров, которые вы указали для использования в функциях. Таким образом, содержимое этих регистров не будет изменено, когда процедура вернет управление вызвавшей ее Си-функции.
Внимание!
Помните, что Си и ассемблер используют одни и те же регистры процессора. Если вы пользуетесь регистром в ассемблерной программе, то должны его сохранить в стеке и восстановить перед завершением функции. Иначе, ваша Си-программа может просто "сломаться" в момент выхода из вызова ассемблерной вставки.
Директива PROC и относящийся к ней уточнитель USES имеет следующий синтаксис.
label PROC [[attributes]] [[USES register_list]] [[,]]
[[parameter list][:type]]...]]
§
Поле label — это имя процедуры;
§ Поле attributes сообщает ассемблеру свойства вашей процедуры. Она может содержать множество параметров, таких как тип процедуры (NEAR или FAR), «видимость» процедуры (PUBLIC или PRIVATE) и, наконец, тип языка (С, PASCAL и т. д.). Эта возможность делает наши программы на ассемблере более читаемыми. Правда, это связывает руки, но зато программы обретают определенную элегантность;
§ Поле register_list показывает, какие регистры будет использовать функция. При этом ассемблер генерирует код, который может сохранить их на время работы процедуры и восстановить при выходе;
§ Поле parameter_list очень похоже на список параметров в Си;
Для каждой передаваемой процедуре переменной должен быть указан тип, определяющий их размер (например, BYTE или WORD).
Тип задается в поле type.
Если вы пишите процедуру, в которую передаете три целых величины, и будете использовать регистры SI, DI и СХ, то должны включить следующий оператор:
far proc USES SI DI СХ, integer_1:WORD, integer_2:WORD,
integer_3:WORD
Используя директивы PROC и USES, давайте перепишем процедуру из Листинга 2.2.
Листинг 2.3. Модифицированная версия Add_Int.
.MODEL MEDIUM,С ; использовать модель MEDIUM ; и соглашения по вызову Си
.CODE ; начало кода
PUBLIC _Add_Int ; объявляем функцию как общедоступную
_Add_lnt PROC USES integer_1 :WORD, integer_2 :WORD
mov AX,integer_l ; загрузить первый операнд в AХ
add AX,integer_2 ; сложить второй операнд с AХ
_Add_Int ENDP ; конец процедуры
END ; конец кода
Как видно из Листинга 2.3, тяжкое бремя сохранения регистра ВР, создания и уничтожения стекового фрейма теперь отдано на откуп ассемблеру. Более того мы получили прямой доступ к параметрам integer 1 и integer 2.