Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
31
Добавлен:
20.06.2014
Размер:
262.14 Кб
Скачать

5. Выгрузка рп с помощью ее вызова

из специальной программы

Чтобы выгрузить резидентную программу, необходимо:

- восстановить прежние значения всех перехваченных векторов прерываний;

- освободить блок памяти занимаемый программой;

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

Для выполнения функции освобождения блоков памяти служит прерывание:

Int 21,49 - освободить блок памяти

ES - сегментный адрес выгружаемого блока памяти

Размер выгружаемого блока памяти определяется чтением данных из

блока MCB внутри самого прерывания Int 21,49.

Восстановить прежние значения всех перехваченных векторов прерываний

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

спрятаны старые значения их адресов.

ЗАМЕЧАНИЕ: Корректно выгрузить можно только последнюю резидентную

программу, перехватившую заданное прерывание. В противном случае, все

позже загруженные резидентные программы, вызываемые тем же прерыванием,

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

Для управления процессом выгрузки опять воспользуемся мультиплексным

прерыванием INT 2Fh.

Обработчик прерывания INT 2Fh резидентной программы должен:

- приняв прерывание, проверить номер функции в регистре AH и, если

номер не свой, передать управление ранее загруженной резидентной

программе, также использующей прерывание INT 2Fh

JMP CS:old_2f

здесь 'old_2f' - ячейка памяти, где хранится старый адрес вектора

прерывания INT 2Fh.

- если номер функции свой, проверить номер подфункции в регистре AL

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

резидентной программы из памяти), вернуться в вызвавшую программу

командой IRET.

В качестве вызывающей программы на первый случай используем специальную

короткую программу выгрузки.

Пример 5

Создадим резидентную программу примера 3, но с возможностью ее

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

установки. Приведем здесь только измененное начало резидентной части

программы, включающую программу выгрузки, и полностью - ее

инициирующую часть.

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

old_2F dd 0 ;Старый адрес Int 2Fh

old_09 dd 0 ;Старый адрес Int 09h

sym1 dw 421Eh ;1-й выводимый символ

sym2 dw 241Eh ;2-й выводимый символ

M4: cmp AH,0C8h ;Cвоя функция прерывания 2Fh?

jnz M5 ;На переход, eсли не своя

cmp AL,01 ;Cвоя подфункция прерывания 2Fh?

jnz M5 ;На переход, если не своя

;---------------------- ;Начало программы выгрузки

push DS ;Сохраним те регистры, содержимое

push ES ;которых меняется в программе

push DX

mov DX,CS:word ptr old_09

mov DS,CS:word ptr old_09+2

mov AX,2509h ;Восстановление старого адреса old_09

INT 21h ;обработчика прерывания int 09h

mov DX,CS:word ptr old_2F

mov DS,CS:word ptr old_2F+2

mov AX,252Fh ;Восстановление старого адреса old_2F

INT 21h ;обработчика прерывания int 2Fh

mov ES,CS:2Ch ;Занесение из PSP:2Ch адреса

mov AH,49h ;окружения в рег.ES и выгрузка

INT 21h ;блока окружения

push CS ;Сегментный адрес начала блока

pop ES ;с программой из рег. CS в ES

mov AH,49h ;Выгрузка блока с резидентной

INT 21h ;программой

pop DX ;Восстановим содержимое

pop ES ;регистров DS, ES и DX

pop DS

;---------------------- ;Конец программы выгрузки

iret ;Возврат в вызвавшую программу

M5: jmp CS:old_2F ;Переход к 'чужой' резидентной

;программе раньше нас перехватившей

;прерывание INT 2Fh

M2: pushF ;Это начало основной части

call CS:old_09 ;резидентной программы,

push AX ;полностью соответствующей

push BX ;тексту примера 3

.......... ..................

.......... ..................

M1: ;---------------------- ;Инициирующая часть

mov AX,352Fh ;Получить в ES:BX старый адрес

INT 21h ;обработчика прерывания int 2Fh

mov word ptr old_2F,BX ;и запомнить его

mov word ptr old_2F+2,ES ;в ячейке old_2F

mov AX,252Fh ;Установка нового адреса <адр.M4>

lea DX,M4 ;обработчика прерывания int 2Fh

INT 21h ; -------

mov AX,3509h ;Получить в ES:BX старый адрес

INT 21h ;обработчика прерывания int 09h

mov word ptr old_09,BX ;и запомнить его

mov word ptr old_09+2,ES ;в ячейке old_09

mov AX,2509h ;Установка нового адреса <адр.M2>

lea DX,M2 ;обработчика прерывания int 09h

INT 21h ; -------

mov AH,09h ;Вывод строки:

lea DX,x ;'Резидентный обработчик загружен$'

INT 21h ; -------

mov AX,3100h ;Завершить и оставить резидентной

mov DX,(M1-Pr+10Fh)/16 ;часть размером (M1-Pr+10Fh)/16

INT 21h ; -------

x db 'Резидентный обработчик загружен$'

Seg1 ENDS ;Конец сегмента

END Pr ;Полный конец программы Pr

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

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

сегмента, а в инициирующей части этого не требуется.

Дело в том, что при дальних вызовах подпрограмм командами CALL, INT

или переходах JMP автоматически изменяются только адреса в регистрах

CS и IP. Содержимое остальных регистров остается без изменения.

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

COM-программы. Здесь содержимое регистров DS и CS одинаково. Поэтому

команда:

mov word ptr old_2F,BX

по умолчанию равная команде:

mov DS:word ptr old_2F,BX

эквивалентна также и команде:

mov CS:word ptr old_2F,BX

А резидентная часть программы выполняется после ее вызова прерыванием

в 'чужой' среде, где содержимое регистров DS и CS разное.

В качестве программы вызова выгрузки РП используем следующую

короткую программу:

Seg1 SEGMENT

ASSUME SS:Seg1,DS:Seg1,CS:Seg1,ES:Seg1

ORG 100h ;Начало программы с 0100h

Pr: mov AH,0C8h ;Вызов INT 2Fh с функцией C8h

mov AL,01 ;и подфункцией 01h для

INT 2Fh ;выгрузки программы.

mov AX,4C01h ;Завершить обычным способом

INT 21h ; -------

Seg1 ENDS ;Конец сегмента

END Pr ;Полный конец программы Pr

Программа достаточно прозрачна и дополнительных пояснений не требует.

Соседние файлы в папке Кр и методичка Разработка резидентной программы в MS DOS