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

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

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

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

Добавлен: 16.02.2019

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

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

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

Глава 23. Область PSP и DTA. Системные переменные (окружение DOS) 

229 

Дело  в  том,  что  резидент,  как  правило,  занимает  больше  места  в  оперативной 

памяти  после  его установки, чем на диске. Иными словами, COM-файл на винче-
стере, например, может иметь размер 130 байт, а в памяти — 350 и более байт. По-
чему так происходит? Вспомните, что перед вызовом прерывания 

27h

, которое ос-

тавляет  программу  в  памяти,  необходимо  указать  в  регистре 

dx

  последний 

освобождающийся байт. Все, что расположено перед смещением, указанным в 

dx

остается в памяти. В табл. 23.3 приведено состояние памяти после загрузки на вы-
полнение файлов типа COM.  

Таблица 23.3. Состояние памяти после загрузки программы 

Смещение 

Значение 

Примечание 

0000h 

Начало PSP. Команда int 20h 

Остается в памяти вместе с ре-
зидентом 

002Ch 

Сегментный адрес окружения DOS 

Остается в памяти вместе с ре-
зидентом 

0080h 

Командная строка и по умолчанию 
DTA 

Остается в памяти вместе с ре-
зидентом 

00FFh 

Последний байт PSP 

Остается в памяти вместе с ре-
зидентом 

0100h 

Метка начала программы (например: 
Begin) 

Резидентная часть программы 
(останется в памяти). Вспомним, 
что метки памяти не занимают 

Тело резидента. То есть то, что будет 
постоянно находиться в памяти 

Резидентная часть 

0134h 

Метка, указывающая на то, что после 
нее можно освобождать память (на-
пример: Init) 

Часть программы, которая будет 
удалена из памяти после вызова 
прерывания 27h 

Инициализация резидента (вывод со-
общений на экран, получение, сохра-
нение и установка векторов прерыва-
ний и пр.) 

Часть программы, которая будет 
удалена из памяти после вызова 
прерывания 27h 

0154h 

Команда int 27h (оставляет часть 
программы в памяти и выходит в DOS) 

Часть программы, которая будет 
удалена из памяти после вызова 
прерывания 27h 

0156h 

Данные, строки для вывода и пр., ко-
торые не требуются резиденту в про-
цессе работы. Необходимы только для 
того, чтобы вывести сообщения на 
экран, сохранить в процессе инициа-
лизации резидента некоторые пере-
менные и пр. Удаляются из памяти 
после выполнения команды int 27h 

Часть программы, которая будет 
удалена из памяти после вызова 
прерывания 27h 

 
На рис. 23.3 показано состояние памяти после загрузки программы в память.  


background image

 

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

230 

 

Рис. 23.3. Системные переменные в только что запущенной программе 

Как уже упоминалось ранее, оставлять PSP в памяти вместе с резидентной про-

граммой  обычно  не  нужно.  В  прилагаемом  примере  мы  используем  префикс 
(256 байт),  как  буфер.  Для  этого  высчитаем  размер  программы  и  ее  данных,  ос-
тающихся в памяти: резидентная часть + 256 байт PSP. 

Резидентная часть — та часть программы, которая остается в памяти. Резидент — 

более широкое понятие, включающее в себя еще и процедуру инициализации. Иногда 
называют резидентом и резидентную часть, что не совсем верно, зато коротко. 

Но и это еще не все, что остается в памяти вместе с резидентной частью нашей 

программы. Помимо PSP, в памяти находится также и сегмент с окружением DOS, 
создаваемый операционной системой для каждого процесса (программы). Сегмент 
может занимать 32 Кбайта и более, но, как правило, не превышает 50—100 байт. 

Каким образом можно избавиться от окружения DOS, тем самым, освободив дополни-

тельно  некоторое  количество  памяти  для  других  программ?  Подобная  процедура  была 
актуальна для программ, работающих под управлением MS-DOS и в режиме реального 
использования памяти. Максимальный объем ОЗУ в этом режиме составляет 640 Кбайт. 
Тем не менее, в данной главе мы рассмотрим, каким образом можно освободить память, 
занятую системными переменными, а также пареллельно изучим кое-что новое. 

В PSP по смещению 

2Ch

 находится сегмент окружения DOS. Вспомните, как мы 

в одной из прошлых глав урезали и отводили блоки памяти. То же самое нам надо 
сделать и с памятью, занимаемой системными переменными. Вот, как это выглядит 
в файле-приложении (листинг 23.1). 

Листинг 23.1. Освобождение памяти 

... 
mov es,word ptr cs:[2Ch]    ;Получим сегмент строки окружения. 
mov ah,49h                  ;Функция освобождения памяти. 
int 21h                     ;Освобождаем память... 
... 


background image

Глава 23. Область PSP и DTA. Системные переменные (окружение DOS) 

231 

В листинге нам встречается новая функция. Ее описание приведено в табл. 23.4. 

Таблица 23.4. Функция 

49h

 

прерывания 

21h

:  

освободить блок основной памяти 

Вход 

Выход 

ah = 49h 

es 

= сегмент распределенного блока 

jc 

— ошибка, при этом: 

ax 

= код ошибки 

 
После  выполнения  данной  функции  память  освобождается.  Это  легко  прове-

рить,  если  запустить  резидент,  освобождая  память  (т. е.  используя  функцию 

49h

),  

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

Для  того  чтобы  лучше  понять,  что  же  такое  окружение  DOS,  к  данной  главе 

прилагается программа  env23.asm, которая выводит на экран все системные пере-
менные. Для более детального и наглядного изучения окружения DOS настоятель-
но  рекомендуется  вначале  посмотреть  результат  работы  этого  файла  (что  именно 
он выводит на экран), а затем запустить его под отладчиком и тщательно изучить.  

23.3. Основной резидент 

Теперь остановимся подробней на работе резидента. Как уже упоминалось, наш 

резидент  сохраняет  в  файле  нажатые  пользователем  клавиши.  Как  именно  он  это 
делает? 

В  данном  случае  мы  будем  использовать  PSP  в  качестве  буфера,  где  будет  хра-

ниться  определенное  количество  ASCII-кодов  нажатых  клавиш,  которые  будут  пе-
риодически (после выполнения определенных условий) записываться в специальный 
LOG-файл.  Почему  периодически?  Можно,  конечно,  сохранять  сразу  же  нажатую 
клавишу, но это будет не совсем красиво, да и пользователь может заподозрить "что-
то неладное", т. к. после каждого нажатия будет производиться запись на диск, при 
этом замедляя работу и выдавая тем самым присутствие нашей программы в памяти. 
Эта проблема исчезает, если загружена программа кэширования записи или этот ре-
жим включен системой. Однако мы будем рассчитывать на то, что кэширование дис-
ков отключено. В таком случае, гораздо проще сохранять в буфер, скажем, максимум 
80 символов, а затем их сбрасывать в файл. Более того, мы сможем производить не-
которую коррекцию вводимых пользователем строк. Например, замеченные опечат-
ки, которые будут меняться при нажатии клавиши <Backspace>. Мы в памяти также 
будем это делать, что избавит LOG-файл от "мусора". 

Итак,  в  качестве  буфера  для  нажатых  пользователем  клавиш  будем  использо-

вать PSP. Все равно память, отведенная под PSP, резиденту не потребуется. А это, 
как уже отмечалось, лишние 256 (100h) байт. 

Клавиши будут сохраняться, начиная со смещения 

0

 сегмента, в который загру-

зился  наш  резидент.  По  смещению 

00F6h

  будем  хранить  смещение,  по  которому 

следует  заносить  очередной  символ  (и  количество  введенных  пользователем  сим-
волов). В принципе, хватило бы и одного байта, но слово удобнее будет использо-
вать, например, при записи символов в файл. 


background image

 

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

232 

При каких условиях будет осуществляться сброс буфера в LOG-файл? 
Запись содержимого буфера будет производиться в случае, если: 

 

пользователь нажмет клавишу <Enter>; 

 

пользователь нажмет клавишу, имеющую расширенный код (например: <F1>—
<F10>, клавиши со стрелками и пр.); 

 

пользователь введет 80 символов, ни один из которых не будет равен коду, пе-
речисленному в двух предыдущих пунктах (дабы избежать переполнения буфера). 
В буфер очередной символ заносит процедура 

Store_sym

 (листинг 23.2).  

Листинг 23.2. Процедура Store_sym 

... 

;Занесем в di количество введенных символов: 

(1)    mov di,cs:[0F6h] 

;Оно больше 79? 

(2)    cmp di,79 

;Нет, меньше. Тогда дописываем в буфер очередной символ. 

(3)    jb OK_store 

(4)    push di              ;Иначе сбросим буфер в файл. 

(5)    push ax 

(6)    call Save_string 

(7)    pop ax 

(8)    pop di 

 

(9)  OK_store: 

(10)   stosb                     ;Занесем очередной символ в буфер. 

(11)   inc word ptr cs:[0F6h]    ;Увеличим счетчик. 

(12) ret                         ;Конец процедуры... 

... 

23.3.1. Команды безусловного перехода 

Никаких  вопросов  здесь  не  должно  возникнуть,  кроме  вопроса  по  команде  из 

строки  (3).  Обратите  внимание,  что  в  строках  (2),  (3)  мы  проверяем,  больше  ли 
число 79, чем то, которое находится в регистре 

di

. Если меньше, то переходим на 

метку 

OK_store

. Это, как вы уже знаете, — условный переход. Однако данную ин-

струкцию мы пока не рассматривали. В принципе, должно быть все понятно. 

je

 (от 

англ.  jump  if  equal —  переход,  если  равно) —  это  переход,  если  приемник  равен 
источнику,  а 

jb

  (от  англ.  jump  if  below —  переход,  если  меньше) —  это,  как  уже 

ясно из перевода, переход, если приемник меньше источника (т. е. в данном случае, 
если 

di

  меньше   9).  Список  команд  условного  перехода  приведен  в  табл. 23.5,  

а пример их использования — в листинге 23.3.  


background image

Глава 23. Область PSP и DTA. Системные переменные (окружение DOS) 

233 

Таблица 23.5. Список команд условного перехода 

Команда 

Описание 

JB (Jump if Below) 

Переход, если приемник меньше источника 

JBE (Jump if Below or Equal)  

Переход, если меньше или равно 

JNB (Jump if Not Below)  

Переход, если не меньше (равносильна JAE) 

JA (Jump if Above)  

Переход, если больше 

JAE (Jump if Above or Equal)  

Переход, если больше или равно 

JNA (Jump if Not Above)  

Переход, если не больше (равносильна JBE) 

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

... 
mov ax,34 
cmp ax,35 
... 

Переход  будет  выполнен  при использовании следующих команд после сравне-

ния: 

  JNE

  JAE

  JNA

  JB

  JBE

Переход не будет выполнен при использовании следующих команд после срав-

нения: 

  JE

  JA

  JNB

Ваша задача сейчас — внимательно разобрать и проанализировать приведенные 

выше команды. 

23.3.2. Команды управления флагами 

Команд  управления  флагом  переноса  (

CF

)  существует  две: 

stc

  и 

clc

 

(табл. 23.6 и 23.7). 

Таблица 23.6. Команда 

stc

 

Команда  Перевод 

Назначение 

Процессор 

stc 

Set carry flag 

— установить флаг 

переноса 

Установка флага переноса 

8086