Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29222
Скачиваний: 1689
Глава 12. Повторная загрузка резидента
119
;теперь в al символ '1' (31h); si = si + 1, т. е. si теперь указывает на '2'
lodsw
;теперь ax содержит '32' (3332h); si = si + 2, si указывает на '45'
...
String db '12345'
...
Рис. 12.3. Результат выполнения команды lodsb
Рис. 12.4. Результат выполнения команды lodsw
Часть III. Файловая оболочка, вирус, резидент
120
Принцип таков: если последний символ в инструкции
lods
—
b
, то загружается
один байт в
al
, и
si
увеличивается на 1. Если же последний символ
w
, то загружа-
ются два байта (слово) в
ax
, и
si
увеличивается на два. Здесь могут возникнуть два
вопроса:
1. Почему не загружаем ничего в
ds
?
2. Почему после команды
lodsw
в
ax
содержится '32', а не '23', что было бы вполне
логично?
П
Р И МЕ Ч А Н И Е
Когда число указывается в кавычках ('32'), то это значит, что оно занимает 2 байта.
Первый байт занимает число 3, а второй — 2.
Ответ на первый вопрос должен быть понятен: если
String
находится в том же
сегменте, в котором наша программа, и сегментный регистр не менялся в процессе
работы программы, то в него ничего загружать не надо. В нем и так находится
нужный сегмент. Ведь при запуске COM-программы все сегментные регистры рав-
ны нашему единственному сегменту.
Ответ на второй вопрос заслуживает подробного рассмотрения.
Дело в том, что в компьютере двух- и более байтовые числа хранятся в обрат-
ном порядке. Путаница не возникает, если к двухбайтовому числу мы обращаемся
как к двухбайтовому, а к четырехбайтовому (к двойному слову) обращаемся как
к четырехбайтовому. В листинге 12.4 приведены примеры.
Листинг 12.4. Загрузка чисел в переменные
...
Handle dw 1234h
;Изначально присваиваем переменной значение 1234h. В памяти это число
;расположится в таком порядке: 3412h. Проверьте в отладчике...
...
mov ax,Handle ;ax=1234h
mov al,byte ptr Handle ;al=34h
mov al,byte ptr Handle+1 ;al=12h
...
Byte ptr
, как вы уже знаете, обозначает, что мы хотим загрузить 1 байт с пере-
менной двухбайтового типа:
Handle dw 1234h
(
dw
от англ. define word — опреде-
лить слово (два байта)) — рис. 12.5—12.7.
Исходя из вышесказанного, рассмотрим, почему мы при сохранении вектора
прерывания
10h
заносим вначале смещение, а затем сегмент, хотя логичнее было
бы наоборот (листинг 12.5).
Глава 12. Повторная загрузка резидента
121
Рис. 12.5. Загрузка из переменной слова в регистр ax
Рис. 12.6. Загрузка из переменной байта в регистр al
Рис. 12.7. Загрузка из переменной байта в регистр al
Часть III. Файловая оболочка, вирус, резидент
122
Листинг 12.5. Сохранение адреса вектора прерывания в переменной
...
mov ax,3510h ;получим адрес (вектор) прерывания 10h.
int 21h ;теперь es содержит сегмент, а bx — смещение...
;сохраним сперва смещение
mov word ptr Int_10h_vect,bx
;а затем сегмент, учитывая, что данные хранятся в обратном порядке
mov word ptr Int_10h_vect+2,es
...
;переменная для хранения двух слов (четыре байта)
Int_10h_vect dd ?
...
word ptr
указывает на то, что нужно занести слово в переменную
Int_10h_vect
.
Обратите внимание, что данная переменная имеет тип
dd
(от англ. define double
word — определить двойное слово). Но мы-то заносим одно слово (
es
или
bx
)! Для
этого и указываем ассемблеру на то, что заносится слово в переменную, которая
может хранить двойное слово.
Итак, команда
lodsb
загружает в
al
однобайтовое число, находящееся по адресу
ds:si
(сегмент:смещение). В принципе, данная команда аналогична следующей
паре инструкций:
...
mov al,ds:[si]
inc si ;(или add si,1)
...
Только работает она гораздо быстрее, да и занимает меньше байтов. По анало-
гии: команда
lodsw
загружает в
ax
двухбайтовое число, расположенное также по
адресу
ds:si
. Она эквивалентна паре инструкций:
...
mov ax,ds:[si]
add si,2
...
Как правило, подобные команды (
lodsb
/
lodsw
) применяются при работе в цикле
для чтения значений из строки (или другого массива данных). Массив данных —
цепочка символов (байтов), расположенных последовательно друг за другом. На-
пример, следующая строка является своего рода массивом данных:
Data_array db 'Это массив данных'
Рассмотрим еще пару подобных команд, которые используются в нашем рези-
денте:
stosb
/
stosw
.
stosb
заносит однобайтовое число из
al
по адресу
es:di
,
а
stosw
— двухбайтовое число по тому же адресу (листинг 12.6, рис. 12.8).
Глава 12. Повторная загрузка резидента
123
Листинг 12.6. Использование команды stosw
...
mov di,offset Data_array
mov ax,2030h
stosw
...
Data_array dw ?
;теперь в этой переменной находится число 2030h, что равносильно
;команде: mov Data_array,2030h
...
Рис. 12.8. Результат выполнения команды stosw
Например, занесем в левый верхний угол экрана нашу "рожицу", используя дан-
ные команды. Вот как это выглядит (листинг 12.7).
Листинг 12.7. Вывод "рожицы" на экран с помощью оператора stosw
...
mov ax,0B800h
mov es,ax
mov di,0
mov ah,07h ;атрибут символа (белый на черном)
mov al,01h ;(сам символ — "рожица")
stows ;заносим, что эквивалентно: mov es:[di],ax
...