11.3 Примеры простейших резидентных программ
11. 3 Примеры простейших резидентных программ Примеры простейших резидентных программ типа COM Следующий пример демонстрирует полностью законченную резидентную программу, которая перехватывает прерывание от клавиатуры (вектор прерывания для клавиатуры под номером 09H) и в программе обработки прерывания вызывает старый обработчик прерывания от клавиатуры. CODE SEGMENT ASSUME CS: CODE, DS: CODE ORG 100H Start: ; начало резидентной части JMP Init OLD_VEC DD? ; значение старого вектора KbProc PROC ; процедура обработки прерывания PUSHF CALL CS: OLD_VEC; вызов старого обработчика IRET ; возврат из процедуры KbProc ENDP Init: ; начало нерезидентной части MOV BX, 09H * 4; вычисление смещения XOR AX, AX MOV ES, AX ; настройка ES на таблицу MOV AX, ES: [BX]; векторов прерываний ; сохранение значения старого вектора прерывания MOV WORD PTR OLD_VEC, AX MOV AX, ES: [BX + 2] MOV WORD PTR OLD_VEC + 2, AX ; установка нового значения вектора прерывания CLI MOV ES: [BX], OFFSET KbProc MOV ES: [BX + 2], CS STI ; завершение программы и загрузка резидентной части MOV DX, (Init – Start + 10FH) / 16 MOV AH, 31H MOV AL, 0 INT 21H CODE ENDS END Start
Перед установкой нового значения вектора прерывания нужно запретить немаскируемые прерывания. Дело в том, что во время установки значения вектора прерывания может возникнуть сигнал прерывания и процессор попытается вызвать обработчик по вектору, значение которого еще до конца не установлено. Это может повлечь за собой непредсказуемые результаты. Поэтому перед установкой значения вектора прерывания всегда нужно ставить команду запрета маскируемых прерываний CLI. По окончании установки значения вектора прерывания нужно разрешить маскируемые прерывания командой STI.
В этом примере нужно обратить внимание на следующие строки: PUSHF CALL CS: OLD_VEC Дело в том, что вызвать старый обработчик через команду INT нельзя, поскольку его вектор прерывания указывает на наш обработчик. Поэтому нужно «смоделировать» работу команды INT, которая помимо занесения в стек значений регистров CS и IP заносит туда еще и значение регистра флагов. Таким образом, перед вызовом дальней процедуры нужно занести в стек значение регистра флагов, чтобы при входе в старый обработчик стек имел такую же структуру, как если бы сначала вызывался старый обработчик при обработке процессором прерывания от клавиатуры. Пример резидентной программы типа COM с переключением стеков и настройкой регистра DS на сегмент команд: CODE SEGMENT ASSUME CS: CODE, DS: CODE ORG 100H Start: ; начало резидентной части JMP Init OLD_VEC DD? ; значение старого вектора KbProc PROC ; процедура обработки прерывания PUSHF CALL CS: OLD_VEC; вызов старого обработчика MOV CS: OLD_AX, AX ; сохранение AX MOV CS: OLD_SS, SS; сохранение SS MOV CS: OLD_SP, SP; сохранение SP MOV AX, CS MOV SS, AX ; переключение стека MOV SP, OFFSET Stac + 128 PUSH DS ; сохранение DS PUSH CS POP DS ; настройка DS на CS POP DS ; восстановление DS MOV AX, CS: OLD_SS MOV SS, AX ; восстановление стека MOV SP, CS: OLD_SP MOV AX, CS: OLD_AX ; восстановление AX IRET ; возврат из процедуры KbProc ENDP OLD_SS DW? OLD_SP DW? OLD_AX DW? Stac DB 128 DUP (? ) Init: ; начало нерезидентной части MOV BX, 09H * 4; вычисление смещения XOR AX, AX MOV ES, AX ; настройка ES на таблицу MOV AX, ES: [BX]; векторов прерываний ; сохранение значения старого вектора прерывания MOV WORD PTR OLD_VEC, AX MOV AX, ES: [BX + 2] MOV WORD PTR OLD_VEC + 2, AX ; установка нового значения вектора прерывания
CLI MOV ES: [BX], OFFSET KbProc MOV ES: [BX + 2], CS STI ; завершение программы и загрузка резидентной части MOV DX, (Init – Start + 10FH) / 16 MOV AH, 31H MOV AL, 0 INT 21H CODE ENDS END Start
Последний пример будет использоваться в дальнейшем для добавления к программе типа COM других элементов структуры резидентной программы.
Примеры простейших резидентных программы типа EXE Следующий пример демонстрирует программу типа EXE с раздельными программными сегментами для различных элементов резидентной и нерезидентной частей. Действие программы аналогично первому примеру резидентной COM программы – вызывается старый обработчик прерывания от клавиатуры, переключения стеков не происходит. Data SEGMENT OLD_VEC DD? Data ENDS
Resident SEGMENT ASSUME CS: Resident, DS: Data KbProc PROC PUSH DS PUSH AX MOV AX, Data MOV DS, AX PUSHF CALL OLD_VEC POP AX POP DS IRET KbProc ENDP Resident ENDS
Code SEGMENT PARA ASSUME CS: Code, DS: Data Start: MOV AX, Data MOV DS, AX MOV BX, 09H * 4; вычисление смещения XOR AX, AX MOV ES, AX ; настройка ES на таблицу MOV AX, ES: [BX]; векторов прерываний ; сохранение значения старого вектора прерывания MOV WORD PTR OLD_VEC, AX MOV AX, ES: [BX + 2] MOV WORD PTR OLD_VEC + 2, AX ; установка нового значения вектора прерывания CLI MOV WORD PTR ES: [BX], OFFSET KbProc MOV WORD PTR ES: [BX + 2], Resident STI ; завершение программы и загрузка резидентной части MOV DX, Code SUB DX, Data ADD DX, 10H MOV AH, 31H MOV AL, 0 INT 21H Code ENDS
Stac SEGMENT PARA STACK DB 128 DUP (? ) Stac ENDS END Start
В разделе изменения значения вектора прерывания необходимо указать конструкции «WORD PTR», поскольку смещение процедуры KbProc может быть меньше 256 и тогда значение этого выражения можно записать как в байт, так и в слово; в следующей строке значение выражения Resident неизвестно на этапе трансляции и для него тоже необходимо указать тип. Следующий пример дополняет предыдущий переключением стека в резидентной части. Data SEGMENT DB 32 DUP 0 Data ENDS
Stac SEGMENT PARA DB 128 DUP (? ) Stac ENDS
Resident SEGMENT ASSUME CS: Resident, DS: Data KbProc PROC PUSHF CALL CS: OLD_VEC MOV CS: OLD_AX, AX ; сохранение AX MOV CS: OLD_SS, SS; сохранение SS MOV CS: OLD_SP, SP; сохранение SP MOV AX, Stac MOV SS, AX ; переключение стека MOV SP, 128 PUSH DS ; сохранение DS MOV AX, Data MOV DS, AX ; настройка DS на сегмент данных POP DS ; восстановление DS
MOV AX, CS: OLD_SS MOV SS, AX ; восстановление стека MOV SP, CS: OLD_SP MOV AX, CS: OLD_AX ; восстановление AX IRET OLD_SS DW? OLD_SP DW? OLD_AX DW? KbProc ENDP OLD_VEC DD? Resident ENDS
Code SEGMENT PARA ASSUME CS: Code, DS: Data Start: MOV AX, Data MOV DS, AX MOV BX, 09H * 4; вычисление смещения XOR AX, AX MOV ES, AX ; настройка ES на таблицу MOV AX, ES: [BX]; векторов прерываний ; сохранение значения старого вектора прерывания MOV WORD PTR OLD_VEC, AX MOV AX, ES: [BX + 2]
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|