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

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

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

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

Добавлен: 16.02.2019

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

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

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

 

Часть III. Файловая оболочка, вирус, резидент 

144 

Что такое линейный адрес и зачем он нужен? 

Как  вы  уже  знаете,  то,  что  находится  на  экране,  расположено  по  адресу  от 

0B800:0000h

  до 

0B800:1000h

  (нулевая  страница).  Видеокарта  не  знает,  что  такое 

колонка и строка. Для нее все данные расположены в линейном массиве, т. е. от 

0

 

до 

1000h

. Так как один символ занимает 2 байта (символ и атрибут), то одна строка 

режима 3 занимает 160 байт (80 строк   2 = 160). Для того чтобы отобразить сим-
вол в первой строке (точнее, во второй, т. к. отсчет начинается с нуля), нам нужно 
выводить его по смещению 161, сегмента 

0B800h

. Следовательно, если мы указыва-

ем  строку/столбец,  то  нам  необходимо  перевести  эти  числа  в  линейный  массив, 
"понятный" видеокарте. Вот пример (разбираем внимательно!): 

;dh обычно указывает на строку 
mov dh,0 
;а dl — на столбец (это мы и будем делать во всех наших процедурах) 
mov dl,15 
;таким образом, мы будем выводить в нулевой строке 
;(т. е. самой верхней на экране), 15 столбце. 

Переводим  2 числа  (строка  и  колонка)  в  линейный  массив (переменная 

Linear

 

будет содержать в итоге адрес для вывода символа на экран): 

;Умножаем на 2 адрес строки, т. к. один символ на экране занимает 
;два байта: символ + его атрибут 
Linear = dl*2 
Linear = Linear + dh*160 

Теперь  переменная 

Linear

  равна  30.  Вот  он,  линейный  адрес: 

0B800:001Eh

 

(

1Eh=30

). Еще пример: 

mov dh,8                       ;Строка 8 
mov dl,56                      ;Столбец 56 
Linear = dl*2                  ;Теперь Linear = 112 
Linear = Linear + dh*160       ;Теперь Linear = 1392 или 570h 

И еще произведем вычисления для последнего символа на экране (правый ниж-

ний угол): 

Linear

 = (24 × 160 + 80 × 2) – 2 = 

0F9Eh

Здесь: 

 

80 —  количество  столбцов  на  экране,  которое  нужно умножить на 2 (учитывая 
не только символ, но и его атрибут). 

 

24 —  количество  строк  на  экране,  начиная  с  0.  Так  как  в  одной  строке 
80 символов (начиная с 1): 80 × 2 = 160, то, для того чтобы получить адрес само-
го последнего (24-го) ряда, нужно 24 умножить на 160. 
Затем все это складываем (адрес 24-й строки + адрес последнего символа – 2). 

Еще раз: 

(24-я строка × 160 + 80-й символ × 2) – 2 

или 

(24 × 160 + 80 × 2) – 2 = 3998 или 

0F9Eh


background image

Глава 14. Вывод окна в центре экрана 

145 

14.4. Практика 

Теперь рассмотрим, как это выглядит на практике. Итак, процедура (

Get_linear

display.asm) (листинг 14.2). 

Листинг 14.2. Процедура Get_linear 

... 

;умножаем dl на 2 (dl=dl*2). Просто сдвинем биты на 1 влево (по принципу 

;деления; см. предыдущий раздел). 

shl dl,1 

mov al,dh     ;в al — ряд, 

mov bl,160    ;который нужно умножить на 160 

mul bl        ;умножаем: al (ряд) * 160; результат — в ax 

 

;Здесь видим новый оператор mul — деление, который рассмотрим позже. 

 

mov di, ax    ;результат умножения — в di 

xor dh, dh    ;аннулируем dh 

add di,dx     ;теперь в di линейный адрес в видеобуфере. 

... 

14.5. Новые операторы 

В  табл. 14.3—14.5  приведено  описание  новых  операторов.  В  листингах  14.3—

14.5 показаны примеры использования этих операторов, а на рис. 14.3—14.5 — ре-
зультаты их работы. 

Таблица 14.3. Оператор 

shl

 

Команда 

Перевод 

Назначение 

Процессор 

shl источникприемник 

Shift left 

— сдвиг влево 

Сдвиг бит 

8086 

 

Листинг 14.3. Пример использования оператора shl 

mov ax,100b 

shl ax,1       ;Теперь в ax число 1000b 

Таблица 14.4. Оператор 

shr

 

Команда 

Перевод 

Назначение 

Процессор 

shr источникприемник 

Shift right 

— сдвиг вправо  Сдвиг бит 

8086 


background image

 

Часть III. Файловая оболочка, вирус, резидент 

146 

 

Рис. 14.3. Результат работы оператора shl 

 

Рис. 14.4. Результат работы оператора shr 

Листинг 14.4. Пример использования оператора shr 

mov ax,100b 
shr ax,1       ;Теперь в ax число 10b 

Таблица 14.5. Оператор 

mul

 

Команда 

Перевод 

Назначение 

Процессор 

mul bl 

Multiplex 

— умножение 

Умножение al на bl  8086 

 
Умножаем 

al

 на 

bl

, помещая результат в 

ax


background image

Глава 14. Вывод окна в центре экрана 

147 

Листинг 14.5. Пример использования оператора mul 

mov al,5 
mov bl,2 
mul bl   ;Теперь в ax число 10 

 

Рис. 14.5. Результат работы оператора mul bl 

Ну  вот,  собственно,  и  все.  Остальное  должно  быть  понятно  из  комментариев  

к программе. 

 


background image

 

 

 

Глава 15 

 

Обработка  
аппаратных прерываний 

 
В  этой  главе  рассмотрим  "многофункциональный"  резидент.  Будет  сложно,  но 

интересно. Наша резидентная программа выполняет следующие действия: 
1.  Записывает  в  файл  содержимое  текстового  экрана  (то,  что  в  момент  нажатия 

определенных клавиш находится в области экрана). 

2.  Меняет на экране все символы "A" и "a" на "О" и "о" соответственно. 
3.  Передает  неверные  данные  о  файлах  оболочкам  Norton  Commander,  Volkov 

Commander, Dos Navigator. 
И все это умеет один резидент, размер которого всего 746 байт! 

15.1. Теория 

Разобраться в инициализации резидента (метка 

Init

) труда не составит. Говоря 

в двух словах, мы делаем следующее: проверяем на повторную загрузку в память 
путем отправления нашего "позывного" (в данном случае — 

9889h

 в 

ax

) и получе-

ния или неполучения "отклика" (число 

8998h

  также  в 

ax

). Если после вызова пре-

рывания 

21h

  с  числом 

9889h

  в  аккумулятор  возвращается 

8998h

, то наш резидент 

уже в памяти (он-то и меняет местами 

ah

 и 

al

). Обратите внимание на первые че-

тыре строки процедуры 

Int_21h_proc

, которые как раз меняют местами 

ah

/

al

, но 

делают это только в том случае, если наш резидент уже загружен в память. 

Проведем  эксперимент.  Перенесем  приведенные  ниже  строки  после  установки 

всех прерываний, но перед вызовом 

int 27h

 (листинг 15.1). 

Листинг 15.1. Проверка на повторную загрузку резидента в память 

... 
mov ax,9889h 
int 21h 
cmp ax,8998h 
jne Set_resident 
... 

В этом случае наша программа выдаст сообщение о том, что она уже загружена 

в память, хотя и загружается первый раз. Следовательно, наш обработчик 

Int_21h_proc