Иллюстрированный самоучитель по SVGA

Учет особенностей компилятора

Оформление процедуры cnvindec

В комплект поставки Макроассемблера входят исходные тексты программных модулей, иллюстрирующие различные случаи применения директивы PROC. Тем не менее автор счел целесообразным показать, что изменится в тексте процедуры cnvindec (см. пример В.5), если в ее описание включить полную форму директивы PROC. Измененный текст приведен в примере В.7.

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

.LI STALL разрешаем печатать все
subr SEGMENT word public ' su эг '; начало сегмента s,ubr
.386 задаем тип микропроцессора
dten dd 10 константа для умножения на 10
cnvindec PROC FAR PASCAL USES e 3х fs si, address:dword
Ifs si, address fs:si = адрес начала строки текста
mov address, 0 result = 0 очистка результата
cnvloop: xor eax, eax очистка еах
lods byte ptr fs: [si] al = очередной символ строки
cmp al, '0' код символа меньше кода цифры 0?
jb endcnv › да, конец формирования числа
cmp al, '9' код символа больше кода цифры 9?
ja endcnv › да, конец формирования числа
sub al, 30h вычитаем код цифры 0
xchg eax, address переставляем еах и result
mul cs:dten edx: eax = result * 10
add address, eax result = result + eax
jmp short cnvloop › на начало цикла преобразования
endcnv: pop si восстанавливаем содержимое si
pop fs восстанавливаем содержимое fs
pop edx восстанавливаем содержимое edx
pop bp восстанавливаем содержимое bp
retf возврат из подпрограммы
cnvindec ENDP конец блока процедуры
subr ENDS конец сегмента subr
END конец текста модуля

В тексте примера В.7 отсутствуют директивы PUBLIC и ASSUME. Первая из них не нужна потому, что при полном описании процедура, по умолчанию, является общедоступной. Директива ASSUME необходима только при использовании компилятора MASM 5.1, а данный пример предназначен для компиляции на более поздних версиях, которые не требуют указания этой директивы. Зато в тексте модуля появилась новая директива .Listaii, она нужна для того, чтобы Макроассемблер включил в листинг команды пролога.

В основном тексте процедуры отсутствуют ссылки на регистр bp, вместо них используется имя параметра address. Если вы посмотрите листинг, то увидите, что ему соответствует тип Dword и значение [bp+6].

В пролог, кроме двух стандартных команд, включены команды, выполняющие сохранение в стеке регистров edx, fs и si. Эпилог в данном случае исключен, поскольку использована команда retf, а не ret. Поэтому команды, восстанавливающие содержимое регистров si, fs, edx и bp, включены в текст процедуры, первая из них имеет метку endcnv.

Замечание
Процедура примера В. 7 предназначена для вызова из программных модулей, составленных на языке ассемблера. Это объясняется тем, что сформированное число возвращается в стеке, именно по этой причине в тексте процедуры использована команда retf, исключающая вставку эпилога. Если вызывающий модуль составлен на алгоритмическом языке, то взять результат из стека, без специальных ухищрений, невозможно. Проще внести изменения в основной текст процедуры, позволяющие вызывать ее из модуля, составленного на любом языке
.

Первый вариант таких изменений заключается в том, что перед выходом из процедуры сформированное число помещается в регистр еах. Для этого пять последних команд текста процедуры заменяются следующими:

endcnv: raov еах, address; копируем результат в еах
ret; стандартная форма команды возврата

В данном случае выполнение процедуры завершает команда ret, поэтому Макроассемблер вставит перед ней эпилог, а к команде ret добавит операнд, равный 4, для выталкивания параметров из стека.

Обоснованием этого варианта является то, что в алгоритмических языках функция возвращает результат в регистре еах (или ах). Например, в модуле, составленном на Фортране, возможна такая форма вызова данной функции:

argument = cnvindec (string)

Описанный вариант применим, если результатом является только одно число. В общем случае у процедуры появляются дополнительные параметры, содержащие адреса для записи результатов вычислений. В конце раздела В. 4 было сказано, что если выходные параметры заданы в виде адресов, то при возврате из процедуры допустимо их удаление из стека.

При описании примера В.5 говорилось, что в регистре al передается код символа, являющегося ограничителем числа. Если он используется в вызывающем модуле, то к процедуре примера В.7 надо добавить еще один параметр, содержащий адрес для записи кода символа.

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

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.