Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29241
Скачиваний: 1689
Часть III. Файловая оболочка, вирус, резидент
214
21.1.2. Практика
Новшество первое
Обратите внимание, как мы вызываем процедуру
Draw_frame
(
Main_proc
,
main.asm). На первый взгляд — ничего особенного. Но это только кажется. Раньше
мы заносили в стек адреса строк и их атрибуты, которые будут выводиться вверху
и внизу окна оболочки. Теперь мы атрибуты в стек не заносим. Но как же тогда
задать цвет, которым должны выводиться сообщения? Обратите внимание, что на-
ходится перед строками
Mess_head
и
Mess_down
:
Mess_head db 1Eh, ' Super Shell, Версия 1.0 ',0
Mess_down db 1Dh, ' Россия, Москва, 2010 ',0
Вот это и есть как раз нужные нам атрибуты соответствующих строк. Поступая
таким образом, мы экономим байты в программе, более того, мы не нагружаем
стек. Отпадает необходимость заносить в стек два слова атрибутов для верхней
строки и два слова для нижней. Процедура вывода строк на экран (
Draw_messfr
,
display.asm) перед тем, как выводить строку, занесет в
ah
первый символ, который
и будет являться атрибутом. Это гораздо проще и нагляднее (листинг 21.1).
Листинг 21.1. Вывод строки на экран
...
;SI уже содержит смещение выводимой строки
mov ah,[si] ;Первый символ в строке — атрибут
inc si ;Следующий байт — начало строки
call Count_strmid ;Вычисляем середину строки
call Print_string ;Выводим строку на экран
...
На рис. 21.1 отображено состояние отладчика перед вызовом процедуры вывода
строки на экран.
Рис. 21.1. Атрибут в начале строки
Глава 21. Работа с блоками основной памяти
215
Новшество второе
Теперь процедура рисования рамки (
Draw_frame
, display.asm) выводит еще и ли-
нию вверху окна по нашему требованию. Для этого нам понадобилось просто из-
менить один бит (листинг 21.2).
Листинг 21.2. Вывод линии вверху окна
...
push 10b ;Экран не копировать, но вывести верхнюю линию.
call Draw_frame ;Рисуем рамку
...
Нулевой бит последнего заносимого слова в стек (если он установлен) указыва-
ет на то, следует ли копировать экран в буфер или нет. Второй бит — следует ли
рисовать линии вверху окна или нет.
21.1.3. Оператор test
Как проверить, включен ли нулевой бит или нет, при этом не затронув осталь-
ных битов? Похоже, что команда
cmp
в данном случае нам не поможет.
Да, действительно, для проверки состояния одного бита в регистре или пере-
менной оператор
cmp
не годится. И вот почему.
Представьте, что первый раз мы выводим окно, предварительно скопировав эк-
ран, но не рисуем линию вверху. Тогда нулевой бит должен быть равен 1. Перед
вызовом процедуры
Draw_frame
в стек занесем просто единицу (листинг 21.3).
Листинг 21.3. Первый вариант вызова подпрограммы рисования окна
...
;Рисуем рамку, предварительно сохранив экран, но не выводим линию вверху
push 1 ;Отвечает за конфигурацию окна
call Draw_frame
...
В подпрограмме
Draw_frame
заносимый в стек параметр из листинга 21.3 загру-
зим в переменную
Other
. Чтобы проверить, какое именно число занесено в эту пе-
ременную, в данном случае воспользуемся оператором
cmp
:
cmp Other,1
Если после проверки флаг нуля устанавливается, т. е.
Other=1
, то нужно предва-
рительно скопировать экран в память.
Здесь все просто. Теперь представим, что нужно вывести окно с линией вверху,
но не копировать экран, т. е. первый бит будет равен единице, а нулевой — 0 (лис-
тинг 21.4).
Часть III. Файловая оболочка, вирус, резидент
216
Листинг 21.4. Второй вариант вызова подпрограммы рисования окна
...
push 10b ;или push 2
call Draw_frame
...
cmp Other,2
...
И, наконец, представим, что нужно и вывести линию вверху, и сохранить экран
(листинг 21.5).
Листинг 21.5. Третий вариант вызова подпрограммы рисования окна
...
push 11b ;или push 3
call Draw_frame
...
cmp Other,3
...
Визуально кажется, что все в порядке, и, тем не менее, существует проблема.
Нулевой бит (сообщающий подпрограмме о том, следует ли сохранять содер-
жимое экрана или нет) мы проверяем в начале процедуры
Draw_frame
и до того
момента, как вывели окно, а вывод верхней линии — после того, как экран сохра-
нен, и окно нарисовано.
Вопрос: можно ли с помощью команды
cmp
проверить, установлен ли опреде-
ленный бит, игнорируя оставшиеся биты проверяемого слова (
Other
)?
Произвести такую проверку можно с помощью логического оператора
and
и ко-
манды
cmp
. В листинге 21.6 приведен фрагмент кода, который осуществляет про-
верку отдельного бита переменной.
Листинг 21.6. Проверка бита в переменной с помощью команды cmp
...
;Перенесем временно в ax значение переменной Other
mov ax,Other
push ax
;Аннулируем все биты, кроме нулевого (вспомним логические команды)
and ax,1
;Проверим, равен ли теперь ax 1?
cmp ax,1
pop ax
mov Other,ax ;Восстановим переменную Other
je Ravno ;Перейдем, если равен
...
Глава 21. Работа с блоками основной памяти
217
Следует отметить, что операторы
mov
и
pop
не изменяют флаги (в том числе
и флаг нуля), поэтому проверять результат сравнения можно через неограниченное
количество таких команд, что мы и делаем в листинге 21.6.
Как на ваш взгляд: красивый получился код? Вполне красивый, за исключением
того, что для проверки всего лишь одного бита мы написали программу, состоя-
щую из 7 строк.
Вероятно, в ассемблере есть другие способы? Безусловно! Ассемблер — такой
гибкий язык, что может делать невероятные вещи! Чтобы временно не сохранять
регистр или переменную перед проверкой одного, двух, трех... битов, используется
оператор
test
(табл. 21.1).
Таблица 21.1. Оператор
test
Команда
Перевод
Назначение
Процессор
test приемник,
источник
Test
— тест, провер-
ка
Проверка одного и более би-
тов
8086
Пример использования данного оператора приведен в листинге 21.7.
Листинг 21.7. Пример использования оператора test
...
mov ax,10100001b
test ax,1 ;Проверим, равен ли нулевой бит единице.
jnz Ravno ;Переход, если равен
...
Обратите внимание, что после команды сравнения
cmp
мы используем операто-
ры условного перехода
je
/
jz
для перехода на определенную метку в случае, если
приемник и источник равны. В команде
test
все совсем наоборот.
Если проверяемый бит установлен, то флаг нуля сбрасывается и переход на мет-
ку в этом случае осуществят команды
jne
/
jnz
. Если же этот бит сброшен, т. е. ра-
вен нулю, то флаг нуля устанавливается, и переход на метку произведут операторы
je
/
jz
(листинг 21.8).
Очень важно это запомнить и не путать!
Листинг 21.8. Проверка третьего бита с помощью оператора test
...
mov cl,100101b
test cl,1000b ;Проверим, равен ли третий бит единице
jz Ne_ravno ;Переход, если НЕ равен
...
Часть III. Файловая оболочка, вирус, резидент
218
Итак, в переменной
Other
может храниться от одного до 8 различных парамет-
ров для выводимого окна. Причем каждый из этих параметров на вопрос должен
отвечать "ДА" или "НЕТ", т. е. "РАВНО" или "НЕ РАВНО". Как, например, в на-
шей процедуре
Draw_frame
. Этот способ очень компактный, удобный и не требует
заведения отдельной переменной для каждого параметра, как это обычно реализу-
ется в языках высокого уровня.
Напомним, что первый бит переменной
Other
отвечает за рисование линии
вверху окна, а нулевой — за копирование участка экрана перед выводом окна.
Вспомните окно подтверждения выхода из оболочки. Прежде чем будет выведено
это окно, система копирует текущее содержимое экрана в определенную память,
чтобы впоследствии его восстановить. Использование битов переменной для по-
добных целей, как уже отмечалось, подходит как нельзя лучше.
В листинге 21.9 приведен фрагмент кода из файла-приложения, выполняющий
проверку одного бита переменной.
Листинг 21.9. Проверка бита переменной Other в нашей оболочке
...
mov ax,Other ;Получим дополнительную информацию
test al,1 ;Нулевой бит равен 0?
jz No_copyscr ;Если так, то копировать экран не нужно.
...
На рис. 21.2 приведен этот же участок кода в отладчике.
Рис. 21.2. Использование оператора test