Взаимодействие элементов резидентной программы.
Любая резидентная программа имеет по крайней мере две точки входа. При
запуске с клавиатуры программы типа.СОМ управление всегда передается на
первый байт после PSP (IP=100h). Поэтому практически всегда первой командой
резидентной программы является команда jmp, передающая управление на начало
секции инициализации.
После отработки функции DOS 31h программа остается в памяти в пассивном
состоянии. Для того, чтобы активизировать резидентную программу, ей надо
как-то передать управление. Вызвать к жизни резидентную программу можно
разными способами, но наиболее употребительным является механизм аппаратных
или программных прерываний. В этом случае в процессе инициализации необходимо
заполнить соответствующий вектор адресом точки входа в программу. Адрес образует вторую точку входа в программу, через которую осуществляется ее активизация. Очевидно, что резидентная секция программы должна заканчиваться командой выхода из прерывания iret.
Рис.1 элементы резидентной программы и их взаимодействие
|
PSP |
|
main proc jmp init |
|
Резидентные данные |
|
entry . . Резидентные программы . main endp |
|
int proc . . Секция инициализации . mov AH, 31h int 21h init endp
|
|
end main |
Резидентная часть
программы

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





После того, как программа загружена и осталась
резидентной, удалить ее из памяти уже нельзя никакими силами. Чтобы привести компьютер в обычное состояние, его придется перезагрузить. В DOS не предусмотрены средства удаления резидентных программ; резидентная программа должна иметь такие средства внутри себя. Трудность здесь заключается в том, что резидентные программы практически всегда заполняют какие-то векторы прерываний, и перед выгрузкой такой программы из памяти эти векторы следует восстановить, чтобы не нарушить работоспособность системы. Однако никто, кроме самой программы, не знает, какие векторы были разрушены, и что в них было до вмешательства резидентной программы. Поэтому почти невозможно корректно выгрузить резидентную программу без ее активного участия в этом процессе. Включение в резидентную программу средств ее выгрузки (обычно по команде пользователя) требует существенного ее усложнения.
Чтобы выгрузить резидентную программу, необходимо:
- восстановить прежние значения всех перехваченных векторов прерываний;
- освободить блок памяти занимаемый программой;
- освободить блок памяти занимаемый ее окружением.
Для выполнения функции освобождения блоков памяти служит прерывание:
Int 21,49 - освободить блок памяти
ES - сегментный адрес выгружаемого блока памяти
Размер выгружаемого блока памяти определяется чтением данных из
блока MCB внутри самого прерывания Int 21,49.
Восстановить прежние значения всех перехваченных векторов прерываний
можно только внутри собственной программы, так как никто не знает, где
спрятаны старые значения их адресов.
ЗАМЕЧАНИЕ: Корректно выгрузить можно только последнюю резидентную
программу, перехватившую заданное прерывание. В противном случае, все
позже загруженные резидентные программы, вызываемые тем же прерыванием,
останутся в памяти но вызываться не будут.
Текст программы:
Резидентный обработчик прерываний от таймера
SEG1 SEGMENT
ASSUME SS:Seg1, DS:Seg1, CS:Seg1,ES:Seg1
ORG 100h ; Начало программы с 0100h
PROGA: JMP M1 ; Пропускаем резидентную часть
;-------------------------Рез.часть
;Поля данных резидентной секции
old_2F dd 0 ; Старый адрес Int 2Fh
old_1C dd 0 ; Старый адрес Int 1Сh
count db 0 ; Счетчик для понижения частоты
;таймера
M4: CMP AH, 0C8h ;Cвоя функция прерывания 2Fh?
JNZ M5 ;На переход, eсли не своя
CMP AL,01h ;Cвоя подфункция прерывания 2Fh?
JNZ M5 ;На переход, если не своя
;--------------------Нач.выгрузки
;Сохраним те регистры, содержимое
PUSH DS ;которых меняется в программе
PUSH ES
PUSH DX
MOV DX,CS: word ptr old_1C
MOV DS,CS: word ptr old_1C+2
MOV AX,251Ch ;Восстановление старого адреса old_1C
INT 21h ;обработчика прерывания int 1Ch
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: PUSH AX ;-----------Нач. основной РП
PUSH BX ;Сохраним используемые в ней
PUSH CX ; регистры
PUSH ES
INC CS:COUNT ;Инкремент счетчика
TEST byte ptr CS:count,3Fh ;Пересчет на 64
JNZ M3 ;Если не 64-е прерывание - на выход
MOV AX,0B800h ;Настроим ES
MOV ES,AX ;на видеобуфер
;----------------------
MOV AL,84h ;Занесение адреса часов
OUT 70h,AL ;в порт 70h
IN AL,71h ;Чтение числа из порта 71h
MOV BX,00 ;Номер позиции на экране для вывода
CALL P1 ;Вывод 2-х цифр из AL на экран
MOV AL,82h ;Занесение адреса минут
OUT 70h,AL ;в порт 70h
IN AL,71h ;Чтение месяца из порта 71h
MOV BX,06 ;Номер позиции на экране для вывода
CALL P1 ;Вывод 2-х цифр из AL на экран
MOV AL,80h ;Занесение адреса секунд
OUT 70h,AL ;в порт 70h
IN AL,71h ;Чтение года из порта 71h
MOV BX,12 ;Номер позиции на экране для вывода
CALL P1 ;Вывод 2-х цифр из AL на экран
JMP M3
P1 PROC ;---------------Процедура вывода 2-х цифр из AL на экран
PUSH CX ;Сохраним те регистры, содержимое
PUSH AX ;которых меняется в программе
MOV CL,4 ;Число сдвигов
SHR AL,CL ;Сдвиг AL вправо 4 р
CALL P2 ;Перевод цифры из AL в символ
MOV ES:[BX+3980],AX ;Вывод старшей цифры
POP AX ;Восстановим AX
CALL P2 ;Перевод цифры из AL в символ
MOV ES:[BX+3982],AX ;Вывод младшей цифры
MOV AX,0E3Ah ;Вывод символа ':'
MOV ES:[BX+3984],AX
POP CX ;Восстановим CX
RET ;Выход из процедуры вывода
P1 ENDP ;Конец процедуры вывода
P2 PROC ;--------------Процедура перевода цифры из AL в символ
AND AL,0Fh ;Выделение мл. полубайта
ADD AL,'0' ;Добавление кода 30h
MOV AH,0Eh ;Байт атрибутов
RET ;Выход из процедуры перевода
P2 ENDP ;Конец процедуры перевода
M3: POP ES ;Восстановим содержимое
POP CX ;регистров ES,CX,BX и AX
POP BX
POP AX
