Ассемблер для процессоров Intel Pentium
Шрифт:
Пример представляет собой 32-разрядную процедуру (она называется easel). В качестве входного параметра процедура принимает целое число из диапазона 0-2, а в регистре ЕАХ возвращает адрес строки, соответствующий значению параметра. Принципы организации процедур мы рассмотрим в следующих главах, сейчас же акцентируем наше внимание на работе программного кода процедуры easel, не вникая в детали ее взаимодействия с другими частями программы.
Для извлечения единственного параметра используется
Листинг 5.2. Ассемблерный аналог конструкции case
.686
.model flat
option casemap: none
.data
s1 DB «String 1», 0
s2 DB «String 2», 0
s3 DB «String 3», 0
err DB «Incorrect parameter!», 0
label_array label dword ; массив меток, в котором будут
; находиться смещения
; меток LI, L2 и L3
DD 3 DUP (?)
.code
_case_l proc
push EBP mov EBP, ESP
mov EBX, dword ptr [EBP+8] ; извлекаем параметр (номер строки)
; и сохраняем его в регистре ЕВХ
lea ESI, label_array ; адрес массива меток -> ESI
mov [ESI], offset LI ; заполняем массив меток смещениями
mov [ESI+4], offset L2 ; меток LI, L2 и L3 mov [ESI+8], offset L3
lea EAX, err_exit ; сохраняем в регистре ЕАХ смещение
; метки для выхода из процедурь
; в случае ошибки
shl ЕВХ, 2 ; поскольку для адресации
; используются двойные слова,
; умножаем номер строки на 4
сmp ЕВХ, 8 ; значение учетверенного параметра
; не должно превышать 8 (номер строки
; лежит в диапазоне 0-2)
jle next1 ; верхнее значение меньше 8? Если
; да, следующая проверка
jmp EAX ; нет, параметр превышает значение 2,
; выйти из процедуры с ошибкой
next1 :
cmp EBX, 0 ; параметр не является отрицательным
; числом? Если
jge get_string ; нет, продолжить выполнение
; процедуры
jmp EAX ; да, параметр вне диапазона, выйти
; с ошибкой
get_string: ; параметр находится в нужном
; диапазоне, получить адрес
; соответствующей строки и выйти из
; процедуры
cmovge EAX, [ESI][EBX]
jmp EAX
L1: ; сюда передается управление при
; значении входного параметра,
; равном 0
lea EAX, s1 ; адрес строки s1 -> EAX
jmp exit ; выход из процедурь
L2: ; сюда передается управление при
; значении входного параметра,
; равном 1
lea EAX, s2 ; адрес строки s2 -> EAX
jmp exit ; выход из процедурь
L3: ; сюда передается управление при
; значении входного параметра,
; равном 2
lea EAX, s3 ;
jmp exit ; выход из процедурь
err_exit: ; сюда передается управление
; при возникновении ошибки
lea EAX, err ; адрес сообщения об ошибке -> ЕАХ
exit:
pop EBP
ret
_case_l endp
end
Анализ работы процедуры начнем со строк
lea ESI, label_array
mov [ESI], offset L1
mov [ESI+4], offset L2
mov [ESI+8], offset L3
Как и в предыдущем примере, вначале заполняем массив меток смещениями используемых ветвей программы. Поскольку 32-разрядные приложения работают со смещениями, равными двойному слову, то наш массив labelarray состоит из трех двойных слов, в которых и сохраняются смещения меток LI, L2 и L3. Все эти действия и выполняют четыре команды, показанные выше.
Следующая команда помещает в регистр ЕАХ смещение метки, куда должно передаваться управление в случае ошибки:
lea EAX, err_exit
Для передачи управления в нашей процедуре используется команда
jmp EAX
Она принимает в качестве операнда регистр (в данном случае – ЕАХ), содержащий смещение команды, куда передается управление.
С помощью следующей команды устанавливается смещение одной из меток (LI, L2 или L3), в которую должно передаваться управление при корректном значении параметра процедуры:
sh1 EBX, 2
Фрагмент программного кода, в котором выполняется проверка параметра на принадлежность диапазону 0-2, думаю, понятен и в объяснениях не нуждается. Если полученный параметр корректен, то выполняется команда
cmovge EAX, [ESI][EBX]
Остановимся на работе этой инструкции ассемблера более подробно. Описание группы команд, к которой принадлежит cmovge, приводится далее в этой главе, но в нашем случае эта инструкция выполняет две функции:
– анализирует результат предыдущей операции (флаг SF);
– если SF = 1, то в регистр ЕАХ помещается смещение одной из меток (LI, L2 или L3). Само смещение находится по адресу, равному сумме адресов массива label_агтау (регистр ESI) и индекса строки (регистр ЕВХ).
Подобную процедуру при желании можно усовершенствовать и использовать для организации ветвлений в программах на ассемблере.
5.3. Организация циклов
Очень часто условные переходы используются при программировании циклических операций, или циклов, когда обрабатывается группа элементов. Количество итераций (прохождений) в цикле чаще всего определяется количеством обрабатываемых элементов, хотя это и не обязательно. Цикл может закончиться в одном из двух случаев:
– выполнены все итерации;