sub dx,ax ; получение размера прогр-мы
mov ah,31h ; сохранить процесс
int 21h ; вызов MS-DOS
...
program ends
end_addr segment
end_addr ends
end start
----------------------------------------------------------------
В главе 2 был представлен набор формул для вычисления размера
программы в параграфах. Эти формулы могут быть использованы с
функцией "Сохранить процесс" также как и с функцией "Модифициро-
вать блок распределенной памяти". При использовании этих формул в
резидентных программах, появилось соответствующее уравнение, как
показано в листинге 3-4. Заметим, что хотя функция "Сохранить
процесс" и не требует адреса PSP, программам типа .EXE необходимо
сохранять адрес PSP при выходе с целью вычисления размера прог-
раммы.
Т.к. память резервируется в начале PSP, резидентные подпрог-
раммы не должны загружаться в верхнюю часть блока памяти (напри-
мер, путем использования переключателя /high компоновщика
MS-LINK). Если подпрограмма загружается в верхнюю часть памяти,
то она станет незащищенной при завершении резидентной подпрограм-
мы, т.к. сохраняемый блок памяти размещается в начале блока памя-
ти. Подпрограмма сама будет размещаться выше пространства резер-
вируемой памяти. Когда подпрограмма станет таким образом
незащищенной, MS-DOS может загрузить на то же самое место памяти
другую программу или нерезидентную часть файла COMMAND.COM, зати-
рая резидентную подпрограмму.
В любом случае, переключатель /high компоновщика MS-LINK за-
трагивает только программы типа .EXE. Когда конвертирующая прог-
рамма EXE2BIN для файла .COM удалит маркер "загрузка высокая",
MS-DOS будет загружать программу с начала PSP.
Другим способом инстоляции резидентных программ является пре-
рывание "завершить и оставить резидентной" int 27h, оставленное
из ранних версий MS-DOS. Способ использования прерывания int 27h
имеет ряд недостатков, которые сводят на нет использование этого
способа. В отличие от функции "Сохранить процесс" (Keep Process),
прерывание int 27h не требует адреса блока памяти (задаваемого
адресом PSP), а требует этот адрес в регистре CS. Только файлы
типа .COM имеют адрес PSP в регистре программного сегмента, за-
трудняя использование этой функции в программах типа.EXE. (Как
выполнить изменение регистра CS и еще выполнить программу?) Кроме
того, параметр размер указывается в байтах, а не в параграфах,
что ограничивает размер программы, который может быть сохраненным
до 64 Кбайт (максимальный размер программы типа .COM). Единствен-
ным достоинством этой функции является то, что в качестве пара-
метра может быть использовано без преобразования смещение послед-
него адреса, как показано ниже:
...
mov dx,offset last_byte ; получение количества байтов
int 27h ; завершение и оставить резидентной
...
last_byte:
program ends
end start
Фирма "Майкрософт" рекомендует для всех вновь разрабатываемых
и для всех существующих модернизированных программ преобразовать
это прерывание в функцию с кодом 31h. При выполнении преобразова-
ния не забудьте модифицировать параметр размер (Size) из байтов в
параграфы.
Доступ к резидентным подпрограммам через прерывания
В результате выполнения программы, показанной в листинге
3-4, в памяти системы будет установлена резидентная программа.
После размещения необязательно вся программа должна находиться в
памяти. Для включения этой программы в RTL необходимо передавать
ей намерение и сделать ее доступной для других программ.
RTL может содержать любую функцию и сделать любой вызов
MS-DOS (например, прерывание int 21h), пока библиотека вызывается
только текущей выполняющейся программой. Это ограничение предназ-
начено для предотвращения неумышленного повторного вызова MS-DOS,
который приведет к сбою системы. Следующая программа, показанная
в листинге 3-5, содержит пример интерфейса для RTL, который может
поддерживать много отдельных функций и очень похож на обработчик
прерывания MS-DOS int 21h.
- 3-35 -
Как показано в листинге 3-5, этот пример структуры может быть
расширен путем добавления необходимого программного кода для под-
держки подпрограмм сравнения, получения справок о таблицах, пре-
образования ввода-вывода, или, даже, общей области для нескольких
программ. Мы попытались включить некоторые примеры технических
приемов, рассмотренных в главе 2, такие как использование пара-
метров стека, отчеты об ошибках и т.д. Если эта подпрограмма ис-
пользуется для поддержки большого количества функций, то можно
заменить модель макроса таблицей переходов, как демонстрируется в
драйвере дискового запоминающего устройства с произвольной выбор-
кой RDISK в главе 6.
Библиотека MACRO, упоминаемая в программе EXRTL, содержит мо-
дель макроса, введенного в главе 1, а также макросы dis_chr отоб-
разить символ) и dis_str (отобразить строку), представленные в
документе "Technical Reference Manual. @DosCall" (Справочное ру-
ководство по техническому обслуживанию. Вызовы DOS), и, конечно
же, макрос для прерывания int 21h.
Листинг 3-5. Пример установки RTL
(подпрограмма EXRTL - Example Run-Time Library)
----------------------------------------------------------------
;====== RTL.ASM - этот файл вырабатывает файл типа .COM ======
V_NUM EQU 40h ; эта RTL использует вектор 40h
;
INCLUDE STDMAC.INC ; включение файла макробиблиотеки
;====== СЕКЦИЯ ПРОГРАММНОГО КОДА ==============================
;
frame STRUC ; схема структуры стека вызывающей программы
old_bp dw ? ; запомненный указатель базы
ret_IP dw ? ; адрес возврата (IP)
ret_CS dw ? ; адрес возврата (CS)
flags dw ? ; флажки вызывающей программы
funct dw ? ; номер выполняемой функции
frame ENDS
;
code_seg SEGMENT
ASSUME cs:code_seg
ASSUME ds:code_seg
main PROC FAR
ORG 0
seg_org EQU $
ORG 2Ch
env_adr LABEL WORD ; смещение среды в PSP
ORG 0100h
start: jmp install
entry: push bp ; сохранение указателя базы
mov bp,sp ; получение адреса стека
push ds ; сохранение сегмента данных
push ax ; сохранение регистра
push bx
mov ax,cs ; установка сегмента данных
mov ds,ax
mov ax,[bp].flags ; передача флажков вызывающ.пр-мы
sahf ; в AX и в мои флажки
clc ; очистка переноса (нет ошибки)
- 3-36 -
pushf ; и сохранение копии флажков
mov bx,[bp].funct ; получение кода функции
@Case bl,<1,2>,
popf ; получение копии флажков
stc ; установка переноса-непр.функция
pushf ; сохранение копии флажков
jmp short exit
f1: @DisStr f1msg
jmp short exit
f2: @DisStr f2msg
exit: pop ax ; отсылка флажков обратно в стек
mov [bp].flags,ax ; через AX
pop bx ; восстановление регистров
pop ax
pop ds ; восстановление сегмента данных
pop bp ; восстановление указателя базы
iret ; возврат из прерывания
main ENDP
;
f1msg db 'Function # 1 performed',CR,LF,'$'
f2msg db 'Function # 2 performed',CR,LF,'$'
lst_byt: ; последний байт для сохранения
;
; Это программа установки.
;
; Для объяснения причин удаления блока среды смотри раздел
; "Биты управления памятью"
;
; Удаление блока среды - DS указывает на текущий сегмент
; Установка ES для указания на блок среды
;
install:
mov es,env_adr ; получение адреса среды
mov ah,49h ; освобождение распределенной памяти
@DosCall ; вызов MS-DOS
jnc setvect ; переход, если ошибки нет
@DisStr fail49 ; информация об ошибке
mov ah,4Ch ; завершение процесса
@DosCall ; аварийное завершение при ошибке
;
; Установка вектора - DS указывает на текущий сегмент
setvect:
mov dx,offset entry ; получение точки входа RTL
mov al,V_NUM ; установка номера вектора
mov ah,25h ; установка вектора
@DosCall ; вызов MS-DOS
;
; Завершение и оставление в памяти резидентной подпрограммы
mov dx,(offset lst_byt - seg_org + 15) shr 4
mov ah,31h ; сохранить процесс
@DosCall ; вызов MS-DOS
;
fail49 db 'Failed to Free Environment Block',CR,LF'$'
code_seg ENDS
END start
----------------------------------------------------------------
- 3-37 -
Особенность подпрограммы EXRTL состоит в том, что при выпол-
нении функции Keep Process ("сохранить процесс") отсутствует па-
мять для локального стека. Это должно было бы привести к фаталь-
ной ошибке программы EXRTL, потому что программный стек станет
полностью незащищенным и субъектом разрушения. Однако, этого не
происходит, потому что подпрограмма EXRTL не является автономной
программой, а вызывается другими программами, которые имеют свои
локальные стеки. Подпрограмма EXRTL выполняет все свои операции,
используя стек вызывающей программы.
После написания RTL, необходимо обеспечить некоторые средства
ее использования. В связи с тем, что в процессе работы невозможно
определить, где MS-DOS загрузит процедуру в памяти, нельзя вызы-
вать библиотеку по инструкции CALL из программы, желающей осу-