Информационный сервер для программистов: Исходники со всего света. Паскальные исходники со всего света
  Powered by Поисковый сервер Яndex: Найдется ВСЁ!
На Главную Pascal Форум Информер Страны мира
   Резидентные Программы    >>    abouttsr
   
 
 Кое что о резидентах   Виктор Вагнер 17.05.1993

Статья Виктора Вагнера о резидентных программах



2k 
 

Кое-что о резидентах В 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 очевидно (они тоже должны быть глобальными, либо описанными в