Резидентные программы

Popf

Mov eax,word ptr old_handler

Cli

Pushf

Pop es

Push 0

Popf

Cli

Pushf

Mov dword ptr old_handler,eax

Pop es

Push 0

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

Когда в реальном режиме выполняется команда INT, управление передается по адресу, который считывается из специального массива, таблицы векторов прерываний, начинающегося в памяти по адресу 0000h:0000h. Каждый элемент этого массива представляет собой дальний адрес обработчика прерывания в формате сегмент:смещение или 4 нулевых байта, если обработчик не установлен. Команда INT помещает в стек регистр флагов и дальний адрес возврата, поэтому, чтобы завершить обработчик, надо выполнить команды popf и retf или одну команду iret, которая в реальном режиме полностью им аналогична.

; Пример обработчика программного прерывания

int_handler proc far

mov ax,0

iret

int_handler endp

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

push 0; сегментный адрес таблицы векторов прерываний

pop es; в ES

pushf; поместить регистр флагов в стек

cli; запретить прерывания

; (чтобы не произошло аппаратного прерывания между следующими

; командами, обработчик которого теоретически может вызвать INT 87h

; в тот момент, когда смещение уже будет записано, а сегментный

; адрес еще нет, что приведет к передаче управления в неопределенную область памяти)

; поместить дальний адрес обработчика int_handler в таблицу

; векторов прерываний, в элемент номер 87h (одно из неиспользуемых прерываний)

mov word ptr es:[87h*4], offset int_handler

mov word ptr es:[87h*4+2], seg int_handler

popf; восстановить исходное значение флага IF

Теперь команда INT 87h будет вызывать наш обработчик, то есть приводить к записи 0 в регистр АХ.

Перед завершением работы программа должна восстанавливать все старые обработчики прерываний, даже если это были неиспользуемые прерывания типа 87h. Для этого надо перед предыдущим фрагментом кода сохранить адрес старого обработчика. Полный набор действий для программы, перехватывающей прерывание 87h, будет выглядеть следующим образом:

; скопировать адрес предыдущего обработчика в переменную old_handler

mov eax,dword ptr es:[87h*4]

; установить новый наш обработчик

mov word ptr es:[87h*4], offset int_handler

mov word ptr es:[87h*4+2], seg int_handler

; тело программы

[...]

; восстановить предыдущий обработчик

mov word ptr es:[87h*4],eax

Для изменения таблицы векторов прерываний в обычных программах, DOS предоставляет две системные функции: 25h и 35h — установить и считать адрес обработчика прерывания, которые и рекомендуются к использованию в обычных условиях.

; скопировать адрес предыдущего обработчика в переменную old_handler

mov ax,3587h; АН = 35h, AL = номер прерывания

int 21h; функция DOS: считать адрес обработчика прерывания

mov word ptr old_handler,bx; возвратить смещение в ВХ

mov word ptr old_handler+2,es; и сегментный адрес в ES,

; установить наш обработчик

mov ax,2587h; АН = 25h, AL = номер прерывания

mov dx,seg int_handler; сегментный адрес

mov ds,dx; в DS

mov dx,offset int_handler; смещение в DX

int 21h; функция DOS: установить обработчик

[...]

; восстановить предыдущий обработчик

lds dx,old_handler; сегментный адрес в DS и смещение в DX

mov ax,2587h; АН = 25h, AL = номер прерывания

int 21h; установить обработчик

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

Программы, остающиеся в памяти, после того как управление возвращается в DOS, называются резидентными. Превратить программу в резидентную просто — достаточно вызвать специальную системную функцию DOS.

Функция DOS 31h: Оставить программу резидентной

Ввод: АН = 31h AL = код возврата DX = размер резидента в 16-байтных параграфах (больше 06h), считая от начала PSP

Кроме того, существует и иногда используется предыдущая версия этой функции — прерывание 27h:

INT 27h: Оставить программу резидентной

Ввод: АН = 27h DX = адрес последнего байта программы (считая от начала PSP) + 1

Эта функция не может оставлять резидентными программы размером больше 64 Кб, но многие программы, написанные на ассемблере, соответствуют этому условию. Так как резидентные программы уменьшают объем основной памяти, их всегда пишут на ассемблере и оптимизируют для достижения минимального размера.

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


_______________

Программа N 01 (первый обработчик прерывания). Записывает в оперативную память пассивный резидент, который для любой программы реагирует на прерывание 21h так, что выводит свою строку 'My string!$'.

CSEG segment

assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG

org 100h

Start:

;Переходим на метку инициализации. Нам нужно будет перехватить прерывание 21h, а также оставить программу резидентной в памяти

jmp Init

; Ниже идет, код обработчика прерывания 21h прерывания (он будет резидентный). После того, как программа выйдет, процедура Int_21h_proc останется в памяти и будет контролировать функцию 09 прерывания 21h.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: