Читайте также: |
|
.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.
Передача указателей
Мы знаем, как передать значения таких параметров как BYTE или WORD, но как передать указатель? Указатели передаются как двойные слова, или DWORD. Для доступа к указателям в стеке нам придется воспользоваться старым приемом: разобьем двойное слово указателя на две переменные segment и offset, которые будут иметь тип WORD, и уже к ним будем обращаться в. нашей ассемблерной программе. К примеру, если мы вызываем ассемблерную функцию в модели MEDIUM, (скажем, это будет вызов типа FAR) в следующей строке:
pfoo(&x)
то получить адрес переменной Х можно будет с помощью следующих подстановок:
offset EQU [ВР+6] segment EQU [BP+8]
Если мы захотим изменить значение X, то нам придется сделать следующее:
mov DI,offset
mov AX,segment
mov ES,AX
mov ES:[DI],CX
Эта программа состоит из двух основных частей:
§ Во-первых, создается указатель на Х через регистры ES и DI;
§ Во-вторых, изменяется значение переменной X.
Ну вот и все о том, что связано с передачей параметров. Новые расширения директив PROC и USES просто великолепны, и вы можете всегда ими пользоваться, если чувствуете от их применения комфорт. Если вы предпочитаете все делать в стиле MASM 5.0, то это ваше право. С точки зрения быстродействия программы здесь нет никакой разницы.
Локальные переменные
Теперь вы знаете, как передавать переменные в процедуры, а вот как насчет временных и локальных переменных, которые действуют только внутри процедуры?
Когда мы пишем программы на Си, то применяем локальные переменные для вычислений, сохранения результатов и т. д. Так же, как и в Си, мы можем создать локальные переменные в наших ассемблерных функциях, используя стек. Конечно, можно создать локальные переменные в области данных (например, в сегменте данных), но этого не стоит делать. Почему? Дело в том, что стек как раз и создавался для временного хранения данных и локальных переменных, так что именно им и стоит пользоваться.
Давайте посмотрим, как это делается. Когда мы определяем стек, сохраняя регистр ВР, то можем извлекать параметры путем прибавления положительного смещения к регистру ВР, например, [ВР+6] и т. д. Таким образом, получается, что в действительности стек — это область непрерывной памяти, которую мы можем использовать также и для хранения локальных переменных. Для этого нам надо только использовать отрицательное смещение относительно регистра ВР.
В случае, если мы хотим иметь две локальные переменные 1осаl_1 и 1оса1_2, можно использовать следующую подстановку:
local_1 EQU [ВР-2]
local_2 EQU [BP-4]
Это дает нам два целых числа. Пока нам не известно, что записано по этим адресам и мы можем только предполагать, что данный участок памяти можно использовать безболезненно. Однако нужно помнить, что мы только что использовали стек для хранения данных и теперь нам необходимо самим изменить регистр SP для отражения этого. Если этого не сделать, то первая встретившаяся инструкция PUSH обязательно что-нибудь запишет в нашу переменную и непременно «испортит» ее.
Для исключения этой ситуации можно предложить уменьшить значение регистра SP на длину переменных, которые мы хотим сохранить. В нашем случае это составит четыре байта. В Листинге 2.4 показано, как это сделать.
Дата добавления: 2015-07-12; просмотров: 88 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Листинг 2.2. Простая процедура сложения. | | | Листинг 2.4. Корректировка регистра SP. |