Кое-что о резидентах
В 6 номере "Монитора" за 93 год автор статьи "Резидентный
будильник на Turbo Pascal" задает вопрос "почему не работает
обработчик прерывания 2F в резидентном режиме, хотя он
прекрасно работает в нерезидентном?". Ответ очевиден - все дело
в размерах стека. Процедура , описанная как interrupt в Turbo
Pascal при входе сохраняет в стеке содержимое всех регистров
процессора, да еще и размещает в нем свои локальные переменные.
В нерезидентной программе это не страшно, так как для этого
используется ее стек, который по умолчанию равен 16К, а при
работе резидентного обработчика объем стека может быть
существенно меньше. Поскольку прерывание 2F перехватывают все,
кому не лень, и каждый из обработчиков занимает по меньшей мере
6 байт стека (флаги+адрес возврата), при попытке запихать туда
все регистры стек может переполниться со всеми вытекающими
последствиями. Единственный выход из этой ситуации - описывать
процедуру не как interrupt и писать ее на встроенном
ассемблере, вставляя в конец кода IRET вручную. (не забудьте
поставить перед IRET POP BP, так как в начало каждой процедуры
на встроенном ассемблере добавляется
PUSH BP
MOV BP,SP
При этом, если у процедуры нет локальных переменных, вы теряете
только 2 байта стека. После этого необходимо переключить стек
на свой и далее можно делать все что угодно.
Вообще, если вы пишете обработчик прерывания на Turbo Pascal
рекомендуется разбить его на две процедуры:
Procedure DoHandle;
var
.....
{Имеет столько локальных переменных, сколько вам надо}
begin
{Делает то, что вам надо}
end;
и
Procedure HandleInt(...);interrupt;
begin
{Запись нужных вам регистров в глобальные переменные}
GlobalAX:=AX;
...
{переключение стека}
asm
MOV CallerSP,SP
MOV CallerSS,SS
MOV SS,MySS
Mov SP,MYSP
end;
{Вызов собственно обработчика}
DoHandle;
{переключение стека обратно}
asm
MOV SS,CallerSS
MOV SP,CallerSP
end;
{Модификация тех регистров, которые вы хотите изменить}
AX:=GlobalAX;
end;
где использование глобальных переменных GlobalAX и т.д.
необходимо потому, что после переключения стека доступ к
параметрам процедуры interrupt будет невозможен, назначение
переменных CallerSS и CallerSP очевидно (они тоже должны быть
глобальными, либо описанными в
|