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

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

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

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

Добавлен: 16.02.2019

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

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

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

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


background image

 

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


background image

Глава 12. Повторная загрузка резидента 

121 

 

Рис. 12.5. Загрузка из переменной слова в регистр ax 

 

Рис. 12.6. Загрузка из переменной байта в регистр al 

 

Рис. 12.7. Загрузка из переменной байта в регистр al 


background image

 

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


background image

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