Страница 18 из 20
1.3.4 Сохранение программы в памяти после завершения. Программы, оставленные резидентными в памяти, могут служить в качестве утилит для других программ. Обычно такие программы вызы- ваются через неиспользуемый вектор прерывания. MS DOS рассматри- вает такие программы как часть операционной системы, защищая их от наложения других программ, которые будут загружены впоследст- вии. Резидентные программы обычно пишутся в форме COM, что обсуж- дается в пункте [1.3.6]. Программы, написанные в форме EXE оста- вить резидентными в памяти немного труднее. Завершение программы прерыванием 27H оставляет ее резидентной в памяти. CS должен указывать на начало PSP для того, чтобы эта функция работала правильно. В программах COM, CS сразу устанавли- вается соответствующим образом, поэтому надо просто завершить программу прерыванием 27H. В программах EXE , CS первоначально указывает на первый байт, следующий за PSP (т.е. 100H). При нор- мальном завершении EXE программы последняя инструкция RET вытал- кивает из стека первые положенные туда значения: PUSH DX / MOV AX,0 / PUSH AX. Поскольку DS первоначально указывает на начало PSP, то при получении этих значений из стека счетчик команд ука- зывает на смещение 0 в PSP, где при инициализации записывается инструкция INT 20H. Поэтому INT 20H выполняется, а это стандарт- ная функция для завершения программы и передачи управления в DOS. На рис. 1-5 показан этот процесс. Чтобы заставить прерывание 27H работать в EXE программе надо поместить 27H во второй байт PSP (первый содержит машинный код инструкции INT), а затем завершить программу обычным RET. Для обоих типов файлов прежде чем выпол- нить прерывание 27H, DX должен содержать смещение конца програм- мы, отсчитываемое от начала PSP. Средний уровень. Вектор прерывания устанавливается с помощью функции 25H преры- вания 21H, как показано в [1.2.3] (здесь используется вектор 70H). Позаботьтесь, чтобы процедура оканчивалась IRET. Кроме самой процедуры, устанавливаемая программа не должна делать ниче- го, кроме инициализации вектора прерывания, присвоения DX значе- ния смещения конца процедуры и завершения. Для COM файлов просто поместите оператор INT 27H в конец программы. Для EXE файлов поместите этот оператор в первое слово PSP и завершите программу обычным оператором RET. Для того чтобы выполнить процедуру, впос- ледствии загруженная программа должна вызвать INT 70H. Приведены примеры для обоих типов файлов (COM и EXE). В обоих установлена метка FINISH для отметки конца процедуры прерывания (напоминаем, что знак $ дает значение счетчика команд в этой точке). Для COM файлов FINISH дает смещение от начала PSP, как и требуется для прерывания 27H. Для EXE файлов смещение отсчиты- вается от первого байта, следующего за PSP, поэтому к нему необ- ходимо прибавить 100H, чтобы пересчитать на начало PSP. Заметим, что поместив процедуру в начало программы, мы можем исключить установочную часть кода из резидентной порции. Другой возможный фокус состоит в использовании инструкции MOVSB для пересылки кода процедуры вниз в неиспользуемую часть PSP, начиная со смещения 60H, что освобождает 160 байт памяти. Случай файла COM: ;---здесь процедура прерывания BEGIN: JMP SHORT SET_UP ;переход на установку ROUTINE PROC FAR PUSH DS ;сохранение регистров . (процедура) . POP DS ;восстановление регистров IRET ;возврат из прерывания FINISH EQU $ ;отметка конца процедуры ROUTINE ENDP ;---установка вектора прерывания SET_UP: MOV DX,OFFSET ROUTINE ;смещение процедуры в DX MOV AL,70H ;номер вектора прерывания MOV AH,25H ;функция установки вектора INT 21H ;устанавливаем вектор ;---завершение программы, оставляя резидентной LEA DX,FINISH ;определяем треб. смещение INT 27H ;завершение Случай файла EXE: ;---здесь резидентная процедура JMP SHORT SET_UP ;переход на установку ROUTINE PROC FAR PUSH DS ;сохранение регистров . (процедура) . POP DS ;восстановление регистров IRET ;возврат из прерывания FINISH EQU $ ;отметка конца процедуры ROUTINE ENDP ;---установка вектора прерывания SET_UP: MOV DX,OFFSET ROUTINE ;смещение процедуры в DX MOV AX,SEG ROUTINE ;сегмент процедуры в DS MOV DS,AX ; MOV AL,70H ;номер вектора прерывания MOV AH,25H ;функция установки вектора INT 21H ;установка вектора ;---завершение программы MOV DX,FINISH+100H ;вычисляем смещение конца MOV BYTE PTR ES:1,27H ;посылаем 27H в PSP RET ;завершаем процедуру Функция 31H прерывания 21H работает аналогично, за исключением того, что в DX должно содержаться число 16-байтных параграфов, требуемых процедуре (вычисление размера процедуры, начиная от начала PSP - см. в примере [1.3.1]). Преимуществом этой функции является то, что она передает родительской программе код выхода, дающий информацию о статусе процедуры. Родительская программа получает этот код с помощью функции 4DH прерывания 21H. Коды выхода обсуждаются в [7.2.5]. |