........................................................ Задать вопрос – НА ФОРУМЕ ........................................................ Возьми кнопку себе на сайт! ........................................................ © 2001. Design by Grayscale ........................................................ |
М. Остринский
Создание резидентных программ и работа с прерываниямиДля чего нужны резидентные программыСуществуют программы, остающиеся в памяти компьютера после завершения своей работы. Эти
программы носят название резидентных или TSR-программ (от английского словосочетания "Terminate and
State Resident" - "завершиться и остаться в памяти").
Резидентные программы - это постоянно находящиеся в памяти программы помощи (POP UP HELP),
калькуляторы, справочники и словари, программы копирования и качественной печати экрана, русификаторы,
вирусы и многое другое.
Находясь в оперативной памяти, резидентная программа пассивна до наступления ключевого
события - таким событием может быть прерывание.
При активизации резидентной программы не имеет значения, какая программа выполняется в этот
момент, и нет необходимости завершать ее работу.
В дальнейшем мы будем называть программу, выполняющуюся в момент активизации резидентной
программы, основным процессом, а саму резидентную программу - фоновым процессом.
Что такое прерываниеПрерыванием называются действия, производимые компьютером для выполнения системных и
сервисных функций во время работы основного процесса.
Если основной процесс - просмотр текста в экранном редакторе, то примером прерывания является
вызов резидентного калькулятора.
Процесс прерывания (в дальнейшем его будем называть просто прерыванием) проходит в три стадии:
1.) приостановка выполнения основного процесса;
2.) обработка прерывания;
3.) возврат управления основному процессу.
Резидентная программа собственно и осуществляет обработку прерываний.
Здесь следует сделать уточнение. Программист пишет программу, логически анализирующую
возникшую ситуацию - это обработка прерывания на высоком уровне. Для выполнения действий по
управлению аппаратурой (ввод/вывод символа, чтение с жесткого диска и т. д.) используются процедуры
базовой системы ввода/вывода BIOS (Base Input/Output System). Обращение к ним из программы также
называется прерыванием, более точно - сервисным прерыванием.
Отличием программ обработки прерываний от обычных подпрограмм, является то, что система перед
их вызовом помещает в стек регистр слова состояния процессора (PSW) для его восстановления в конце
прерывания, а управление всегда передается с помощью косвенной адресации.
Аппаратные и сервисные прерыванияРассмотрим в качестве примера задачу контроля за функционированием химического реактора.
Требуется автоматизировать принятие экстренных мер по сигналу с датчиков, контролирующих параметры
процесса, в случае отклонения этих параметров от заданных.
Невозможно заранее предугадать, когда произойдет подобное событие. Компьютер в этот момент
может выполнять любую программу, например, тестировать обслуживающий персонал на знание техники
безопасности или управлять оптимальной загрузкой производственного оборудования. Когда поступает
сигнал с датчиков о нештатной работе, выполнение основного процесса должно быть прервано.
Такие прерывания называются асинхронными или аппаратными. Они генерируются системой MS DOS
при получении от оборудования сигнала о каком-либо событии.
Аппаратные прерывания нумеруются в порядке приоритета вызова от 0-го до 15-го для IBM PC/AT и
от 0-го до 7-го для IBM PC/XT. Все эти прерывания, кроме 2-го (IRQ2), могут быть запрещены ("маскированы")
путем сброса флага "I" в регистре слова состояния процессора (бит 7), и затем снова разрешены обратным
действием. Не рекомендуется надолго (более 1/18 секунды реального времени) запрещать прерывания, так
как это приведет к отставанию системных часов от абсолютного времени.
В отличие от аппаратных, сервисные прерывания происходят только если в программе есть явное
указание произвести прерывание. Сервисные прерывания используются для реализации функций работы
с внешними или внутренними устройствами, такими, как диски, экран дисплея, принтеры, мышь и т. д.
Практически все сервисные прерывания могут выполнять большой набор функций для реализации
различных операций работы с внешними устройствами.
Как вызвать сервисное прерываниеКаждое прерывание имеет уникальный порядковый номер. В руководствах по MS DOS и BIOS для
каждого прерывания описаны действия, выполняемые компьютером. Например, чтобы прочитать символ,
вводимый с клавиатуры, необходимо осуществить прерывание с номером 16H и функцией 00H.
По команде
MOV AH,00H номер функции загружается в регистр AH.
По команде
INT 16H происходит прерывание, и символ, введенный с клавиатуры, помещается в регистр AL.
В таблице приведены примеры аппаратных и сервисных прерываний для IBM PC/AT.
Некоторые из этих прерываний дополняют друг друга. При нажатии клавиши на клавиатуре, системой
генерируется аппаратное прерывание INT 09H (IRQ 1), при обработке которого сканкод нажатой клавиши
помещается в буфер клавиатуры, а одна из функций сервисного прерывания INT 16H позволяет считать
этот код из буфера клавиатуры и возвращает ASCII-код символа, соответствующего нажатой клавише.
Как устанавливаются в системе резидентные программы обработки прерыванийВ оперативной памяти компьютера первые 256*2 слов зарезервированы для хранения сегментных
адресов программ обработки прерываний. Например, адрес программы обработки прерывания от клавиатуры
INT 16H находится в ячейках 16H*2 (базовый адрес сегмента) и в 16H*2+1 (смещение). Зарезервированное
поле адресов программ носит специальное название - область векторов прерываний. При возникновении
события, вызывающего прерывание, система читает соответствующий событию вектор прерывания и
вызывает программу обработки прерывания, помещенную по адресу, на который указывает этот вектор.
Процесс обработки прерывания считается завершенным, когда программа обработки прерывания засылает
в порт с адресом 20H микросхемы контроллера прерываний код 20H.
Разработчики аппаратуры персонального компьютера придерживались идеологии "открытой
архитектуры". К компьютеру можно подключать множество периферийных устройств, а изменять
стратегию управления этими устройствами очень просто - достаточно поместить в область векторов прерываний
адрес программы, обслуживающей новое устройство.
Таким же точно образом устанавливаются в систему и резидентные программы.
Работать с векторами прерываний можно двумя способами. Первый способ - это прямая запись и
чтение оперативной памяти в области векторов прерываний. Второй и более удобный способ - использование
сервисного прерывания DOS INT 21H, функция 35H которого позволяет считать вектор прерывания в
двухсловный элемент памяти, а функция 25H позволяет установить нужный вектор прерывания по адресу,
помещенному в двухсловный элемент памяти.
Структура резидентной программыВ отличие от обычных программ, подавляющая часть кода которых выполняется в интервале с
момента запуска до завершения, резидентные программы состоят из двух частей: собственно резидентной
и вспомогательной части. При запуске программы выполняется только вспомогательная часть, подготавливающая
резидентную часть к активизации.
Вспомогательная часть выполняет следующие действия:
1.) сохраняет векторы "захватываемых" прерываний во внутренних переменных;
2.) устанавливает эти векторы по адресу резидентной части программы;
3.) инициализирует внутренние переменные резидентной части;
4.) завершает работу программы без удаления резидентной части из памяти компьютера.
Реализация этих действий на низком уровне представляет собой:
1.) вызов 35-й функции прерывания DOS INT 21H (GET VECTOR), которая позволяет сохранить
вектор прерывания в двухсловной метке;
2.) вызов 25-й функции прерывания DOS INT 21H (SET VECTOR), которая позволяет установить вектор
прерывания по известному адресу;
3.) присвоение начальных значений внутренним переменным в зависимости от их назначения в программе;
4.) вызов прерывания DOS 27H (KEEP), которое позволяет завершить выполнение программы без
удаления резидентной части из памяти компьютера.
С того момента как резидентная часть программы находится в ОЗУ, и на нее указывает вектор
"захваченного" прерывания, она может быть активизирована путем вызова этого прерывания.
Построение резидентной части может осуществляться по трем схемам выполнения.
В схеме "А" сначала вызывается системная обработка, а затем производится добавочная
пользовательская обработка, написанная программистом. Эта схема подходит в том случае, когда программист
хочет чем-либо дополнить системную обработку. Например, можно заставить машину менять по нажатию
клавиш Ctrl-Alt атрибуты яркости символов на противоположные.
Пример 1. Резидентная программа, которая инвертирует яркость всех символов на экране
при нажатии сочетания клавиш Ctrl-Alt.
Программа, построенная по схеме "B", выполняет сначала пользовательскую обработку и
только потом системную. Этот случай пригоден для изменения содержимого регистров или осуществления
каких-либо действий перед системной обработкой. Схемой "B" пользуются все вирусные
программы, отслеживающие прерывание запуска программы для того, чтобы присоединиться к ее концу.
В примере 2 программа, написанная по схеме "B", при выводе по прерыванию на экран символа
"пробел", заставляет систему выводить его на красном фоне. Данная программа перехватывает
вектор сервисного прерывания INT 10H, функции 09H и 0AH которого служат для вывода символов на
экран с текущей позиции курсора. Когда вызывается одна из этих функций, резидентная программа
проверяет номер символа, выводимого на экран (он находится в регистре AL), и в зависимости от результата
проверки переустанавливает цвет символа (регистр BL). После проверки производится переход на
системную обработку, выводящую символ на экран с установленными при пользовательской обработке
параметрами, и возвращается управление основному процессу.
Схема "C" полностью исключает системную обработку и заменяет ее пользовательской. При
необходимости вообще исключить обработку данного прерывания резидентная часть должна состоять
лишь из операторов засылки в порт 20H сигнала о конце прерывания (код 20H) и оператора возврата IRET.
Пример 3 иллюстрирует рассматриваемую схему. Программа использует пользовательское прерывание по
таймеру INT 1CH и выводит в левом верхнем углу значение счетчика. Системный таймер генерирует
прерывание INT 1CH ("тикает") приблизительно 18,5 раз в секунду. Программа дожидается 10
таких "тиков" и увеличивает номер символа, выводимого в левом верхнем углу экрана, на единицу.
Активизация резидентных программ по горячим клавишамСамым распространенным способом активизации резидентных программ по прерыванию является
вызов по так называемым "горячим" клавишам ("hot keys"), т. е. по заранее установленной
комбинации клавиш.
Легче всего обрабатывать сочетания клавиш Ctrl, Alt, LeftShift и RightShift. Резидентная программа,
вызываемая по "горячим клавишам", обычно устанавливается на прерывание INT 09H, хотя может устанавливаться
и на прерывание INT 16H. В начале резидентной части необходимо проверить байт памяти, находящийся
по адресу 0000:0417H, в котором хранятся битовые флаги состояния клавиатуры, т. е. информация о нажатых
в данный момент управляющих клавишах. Если значение бита равно 1 (бит "взведен"), значит соответствующая
клавиша в данный момент нажата или включен соответствующий режим.
Пример 1 иллюстрирует резидентную программу, использующую вызовы
по "горячим" клавишам. Программа перехватывает аппаратное прерывание INT 09H и производит сначала
системную обработку (схема "A"), затем проверяет флаги клавиатуры. Если флаги клавиатуры указывают
на нажатие клавиш Ctrl и Alt, то программа осуществляет предписанные ей действия и передает управление
основному процессу.
Если необходимо использовать для активизации резидентной программы дополнительные (не
входящие в байт флагов состояния клавиатуры) клавиши, то следует добавочно использовать порт клавиатуры.
Далее приведен фрагмент резидентной части, активизирующейся по сочетанию клавиш Ctrl-Alt-R.
PROCESS: PUSHF ; НАЧАЛО РЕЗИДЕНТНОЙ ЧАСТИ CALL CS:OLD_VEC ; Имитация прерывания PUSH AX ; Вызов системной обработки PUSH ES ; Сохранение в стеке регистров IN AX,60H ; AX и ES CMP AX,19 ; Чтение порта клавиатуры в AX JNZ A1 ; Проверка нажатия клавиши "R" MOV AX,0 ; если нет, то возврат управления MOV ES,AX ; Чтение флагов состояния MOV AL,ES:[0417H] ; клавиатуры в регистр AL и AND AL,00001100B ; определение нажаты ли клавиши CMP AL,00001100B ; Ctrl-Alt, если нет, то JNZ CMP ; возврат управления ... ... ; дальше как в примере 1 ... Некоторым резидентным программам для нормальной работы необходимо захватывать более одного
вектора прерываний. Примером таких программ являются русификаторы. Эти программы перехватывают прерывание
INT 09H и с его помощью отслеживают момент смены режимов "Рус/Лат" по "горячим" клавишам, а также
перехватывают функцию 00H прерывания INT 10H для загрузки в знакогенератор шрифтов различных
размеров при смене одного видеорежима на другой (к примеру, при смене текстового режима 25*80 со
шрифтом 8*14 точек на текстовый режим 42*80 со шрифтом 8*8 точек).
Особенности программированияПравильное построение резидентной и вспомогательной частей обеспечивает нормальную
активизацию и работу фонового процесса, но после его завершения программу ожидает еще один важный
этап - возврат управления основному процессу, во время выполнения которого была активизирована
резидентная программа. Для успешного возврата в основной процесс необходимо восстановить значения
всех регистров, которые были использованы во время работы резидентной части. Удобнее всего это сделать,
поместив в начале работы фонового процесса значения этих регистров в стек, а в конце работы восстановить
прежние значения, взяв их из стека.
Если регистры не будут восстановлены, то нормальный возврат в основной процесс не произойдет.
Это скорее всего приведет к краху системы. Такая ошибка довольно часто допускается программистами,
начинающими работать над написанием резидентных программ.
В резидентных программах необходимо аккуратно работать со стеком, так как при недостаточном его
размере будет портиться память, находящаяся после резидентной программы.
К непредсказуемым последствиям приводит также несбалансированность операторов PUSH (положить
в стек) и POP (извлечь из стека).
Все резидентные программы обработки прерываний должны заканчиваться командой IRET, так как она
кроме возврата осуществляет восстановление слова состояния процессора (PSW).
Может сложиться впечатление, что писать резидентные программы можно только на языках низкого
уровня. Пример 4 опровергает это представление. Более того, транслятор
языка TurboPascal дает возможность реализации рассмотренных выше функций загрузки и чтения векторов
прерываний на высоком уровне с помощью собственных библиотечных процедур. При использовании
транслятора TurboPascal программист не обязан следить за восстановлением регистров, так как это
осуществляется автоматически при выходе из подпрограмм типа "Interrupt".
Написание резидентных программ ошибочно считается в среде пользователей и программистов
"высшим пилотажем". Каждый программист, понимающий процессы, происходящие в компьютере, может
достичь успехов в этой области.
|