Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Программирование

Добавлен: 16.02.2019

Просмотров: 29241

Скачиваний: 1689

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 

Часть 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. Атрибут в начале строки 


background image

Глава 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). 


background image

 

Часть 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        ;Перейдем, если равен 
... 


background image

Глава 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      ;Переход, если НЕ равен 

... 


background image

 

Часть 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