Оперативная память

         

В 5 Исходный текст процедуры cnvindec



Пример В.5. Исходный текст процедуры cnvindec

PUBLIC cnvindec объявляем процедуру общедоступной
subr SEGMENT word public 'subr'; начало сегмента subr
ASSUME cs:subr cs ассоциируется с subr
.386 задаем тип микропроцессора
dten dd 10 константа для умножения на 10
cnvindec PROC far начало блока процедуры
push bp сохранение содержимого bp
mov bp, sp bp = sp базовый адрес в стеке
push edx сохраняем содержимое edx
push fs сохраняем содержимое fs
push si сохраняем содержимое si Ifs si,
[bp+6] fs:si = адрес начала строки текста mov dword ptr [bp+6], 0; result = 0 очистка результата
cnvloop: xor eax, eax очистка еах
lods byte ptr fs:[s ]; al = очередной символ строки
cmp al, '0' код символа меньше кода цифры 0 ?


jb endcnv ; -> да, конец формирования числа
cmp al, '9' К°Д символа больше кода цифры 9 ?
ja endcnv -> да, конец формирования числа
sub al, 30h вычитаем код цифры О
xchg eax, [bp+6j переставляем еах и result
mul cs:dten edx:eax = result * 10
add [bp+6], eax result = result + eax
jmp short cnvloop -> на начало цикла преобразования
endcnv: pop si восстанавливаем содержимое si
pop fs восстанавливаем содержимое fs
pop edx восстанавливаем содержимое edx
pop bp восстанавливаем содержимое bp
ret возврат из подпрограммы
cnvindec ENDP конец блока процедуры
subr ENDS конец сегмента subr
END конец текста модуля

Подпрограмма примера В.5 оформлена в виде готового для компиляции модуля. Способ оформления такого модуля описан в предыдущем разделе и показан в примере В.З. Поэтому мы начнем с основного текста.

В сегменте subr перед текстом процедуры описано двойное слово dten и ему присвоено значение 10. Эта переменная используется в процедуре при умножении, она нужна потому, что операндом команды mul не может быть константа 10.

Процедура преобразования имеет имя cnvindec. Ее текст начинается с подготовки регистра bpсохранения в стеке используемых регистров. После этого в регистры fs:si загружается адрес преобразуемой строки.

Важно
Перед вызовом процедуры в стек сначала записывается сегмент, а затем смещение строки. Только при выполнении этого условия команда Ifs поместит в регистр fs код сегмента, а в регистр si — смещение.

После загрузки адреса строки в регистры параметры не нужны и отведенное для них место используется для размещения формируемого числа. Предварительно команда mov dword ptr [bp+6], о очищает два слова стека с адресами [bp+6] И [bp+8].
Цикл формирования числа начинается с команды, имеющей метку cnvloop, и заканчивается командой jmp short cnvloop. Код формируемого числа может содержать до 32-х разрядов, поэтому вычислительные операции выполняются с операндами, имеющими размер двойного слова.

Цикл начинается с очистки регистра еах и записи в его младший байт (al) кода очередного символа. Затем проверяется, чему соответствует этот код. Если он соответствует цифре, то из содержимого al вычитается код цифры 0, производится перестановка содержимого еах и result и выполняется умножение result * 10. В связи с тем, что константа dten расположена в кодовом сегменте, в команде mui перед ней явно указано имя регистра cs. Младшая часть результата умножения (содержимое еах) прибавляется к result и происходит возврат на начало цикла формирования числа.
Если очередной символ не является цифрой, то выполнение цикла прекращается и происходит переход на метку endcnv. Начиная с этой метки расположены команды, восстанавливающие содержимое сохраненных в стеке регистров, и команда retf, завершающая выполнение подпрограммы.

Замечание 1
Замечание 1
Значение формируемого подпрограммой примера В. 5 числа может изменяться в пределах от 0 до 4294967295 (232 — 1). Контроль переполнения результата отсутствует, это сделано для упрощения текста подпрограммы. При необходимости вы можете ввести такой контроль или увеличить диапазон допустимых значений числа. Напомним, что при умножении на 10 старшая часть произведения находится в регистре edx, но подпрограмма не работает с этим регистром.

Использование процедуры cnvindec. Для использования в задачах модуль примера В. 5 компилируется, и полученный объeктный модуль объединяется с объектным модулем основной задачи. Как это делается, описано в данном приложении в разделе . Здесь нас будет интересовать вызов подпрограммы задачей.

Предположим, что в разделе данных задачи зарезервирован буфер для размещения вводимой строки текста и ему присвоено имя linbuf. Для хранения сформированного числа в разделе данных надо зарезервировать двойное слово, присвоив ему подходящее имя, например, argument.

В задаче можно выбрать любой удобный для вас способ ввода текста строки с клавиатуры. Только не забывайте, что вводимые символы нужно отображать на экране монитора, а способ отображения зависит от установленного задачей видеорежима. В текстовых видеорежимах обычно применяется стандартная функция DOS, ее код ОАbp.

Подпрограммы для ввода текста в графических видеорежимах описаны в главе 5, раздел, а их использование показано в приложении А, пример А.10 .
После ввода строки, для формирования числа в основном тексте задачи выполняются следующие команды:

@Invoke cnvindec <ds, offset linbuf>; вызов подпрограммы
pop argument ; запись сформированного числа

При компиляции, обнаружив имя einvoke, Макроассемблер ищет его в своих таблицах, и если описанное в примере В.4 макроопределение включено в текст задачи, то макровызов преобразуется в следующие три команды:

push ds ; запись в стек содержимого ds
push offset linbuf ; запись в стек смещения
linbuf call cnvindec ; обращение к подпрограмме

После возврата из подпрограммы в стеке находится результат в виде двойного слова, которое задача должна вытолкнуть в специально выделенную переменную argument. Кроме того, в регистре ai находится код символа, обнаружив который подпрограмма завершила свою работу. В случае необходимости в задаче можно предусмотреть проверку кода этого символа и выполнение тех или иных действий в зависимости от результата проверки.

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



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