EXRTL может изменить значение бита переноса; затем, перед выхо-
дом, она может скопировать флажки обратно в стек (включая новое
значение флажка переноса). Эти операции позволяют подпрограмме
EXRTL использовать флажок переноса для сигнализации условий ошиб-
ки для вызывающей программы, используя инструкцию IRET для восс-
тановления флажков из стека.
Листинг 3-6. Выполнение программы для RTL
----------------------------------------------------------------
;====== RTL_TEST.ASM - Этот файл вырабатывает .COM файл ========
V_NUM EQU 40h ; эта RTL использует вектор 40h
INCLUDE STDMAC.INC ; включение файла макробиблиотеки
;====== СЕКЦИЯ ПРОГРАММНОГО КОДА ===============================
code_seg SEGMENT
ASSUME cs:code_seg
ASSUME ds:code_seg
main PROC FAR
ORG 0100h
start: mov cx,3 ; начало при неправильном значении
loop: push cx ; код функции
int V_NUM ; вызов RTL
pop cx ; очистка параметра возврата
jnc nxt ; переход, если ошибки нет
@DisStr caserr ; показать ошибку
nxt: dec cx
jge loop ; цикл через 0
mov ah,4Ch ; завершение процесса
@DosCall
caserr db 'Case Error - Illegal Function Code',CR,LF,'$'
main ENDP
code_seg ENDS
END start
- 3-41 -
Последний вопрос, насколько полно может использовать подпрог-
рамма EXRTL операционную систему MS-DOS, когда получает управле-
ние непосредственно из другой программы? В некоторых других рези-
дентных программах, представленных в следующих разделах этой
книги, это происходит не так. Эти программы получают управление
через прерывания аппаратных средств или прерывания MS-DOS.
Адрес .----------------------.
|/\/\/\/\/\/\/\/\/\/\/\| Таблица векторов
/\/\/\/\/\/\/\/\/\/\/\ семейства микро-
| | процессора 8086
|----------------------|<---------------.
0000:0100| IP или CS RTL |--------------. |
|----------------------| | |
\/\/\/\/\/\/\/\/\/\/\/ | |
|\/\/\/\/\/\/\/\/\/\/\/| | |
|----------------------|<------------- |
| Элемент RTL | Установленная |
\/\/\/\/\/\/\/\/\/\/\/ RTL |
|\/\/\/\/\/\/\/\/\/\/\/| |
.----------| IRET | |
| |----------------------| |
| \/\/\/\/\/\/\/\/\/\/\/ |
| |\/\/\/\/\/\/\/\/\/\/\/| Программа |
| |----------------------|пользователя |
| |/\/\/\/\/\/\/\/\/\/\/\| |
| /\/\/\/\/\/\/\/\/\/\/\ |
--------->| Int 40h |----------------
|/\/\/\/\/\/\/\/\/\/\/\|
/\/\/\/\/\/\/\/\/\/\/\
|----------------------|
|/\/\/\/\/\/\/\/\/\/\/\|
/\/\/\/\/\/\/\/\/\/\/\
| |
----------------------
Рис. 3-12. Доступ к библиотеке исполняющей системы (RTL)
Как определить, установлены ли резидентные программы?
До сих пор мы предполагали, что библиотека исполняющей систе-
мы (RTL) должна быть загружена в память, и только после этого
должны стартовать программы, которые ее используют. При некоторых
обстоятельствах RTL может всегда находиться в памяти. Чем загру-
жать повторную копию RTL, загрузчик сначала должен определить
загружена ли уже RTL в память, и загружать ее только тогда, если
она отсутствует в памяти. Имеется два способа определения наличия
RTL в памяти, которые оба зависят от использования предварительно
назначенного вектора прерывания для доступа к RTL.
Первый способ - чтение содержимого вектора прерывания по-
средством функции с кодом 35h "Получить вектор прерывания" для
определения начального адреса подпрограммы обслуживания прерыва-
ния (ISR - Interrupt service routine). Следующий шаг состоит в
том, чтобы поместить в регистры DS и SI начальный адрес устанав-
ливаемой существующей подпрограммы. Затем выполняется инструкция
CMPS (сравнение строк) для сравнения некоторого количества бай-
тов (в регистре CS) двух секций программы. Если результат сравне-
ния положительный, то подпрограмма уже представлена в памяти. Ес-
ли сравнение не произошло, то подпрограмма не была установлена в
памяти. Эффективность этого способа намного упадет, если все RTL
(или резидентные подпрограммы) будут начинаться с одинаковой по-
следовательности инструкций. И, наоборот, эффективность может
сильно возрасти, если все резидентные подпрограммы будут содер-
жать блок заголовка, показанный в листинге 3-7, и который уни-
кально идентифицирует каждую резидентную подпрограмму.
Второй способ проверки наличия RTL или резидентной подпрог-
раммы в памяти, требует, чтобы все неиспользуемые векторы преры-
вания (в больших системах от вектора 40h до вектора 0FFh) были
установлены в известное состояние. Это состояние может быть либо
верхней, либо нижней памятью (0000:0000 или FFFF:FFFF), или адре-
сом инструкции IRET. В MS-DOS версии 2.0 и выше вектор 28h всегда
указывает на ячейку инструкции IRET, хотя это не гарантируется!
Более элегантным решением для обработки незапрошенных прерыва-
ний и инициализации всех неиспользуемых векторов прерываний для
указания на эту подпрограмму (смотри главу 6 "Устанавливаемые
драйверы устройств") является установка драйвера псевдо-устройс-
тва. Этот драйвер может затем содержать инструкцию IRET, отчет об
ошибках, выдаваемый на консоль, или все, что потребуется. При
постоянном распределении одного вектора для постоянного указания
на драйвер незапрошенных прерываний (например, вектор 40h) прог-
рамма установки может прочитать и сравнить этот вектор и вектор
резидентной подпрограммы, чтобы убедиться в том, была ли уже ре-
зидентная программа установлена в памяти.
Листинг 3-7. Идентификация входных строк подпрограммы
----------------------------------------------------------------
enter: jmp start ; обход области данных
db '<имя подпрограммы>' ; здесь задается имя подпр-мы
... ... ; область данных
start: <начало программного кода>
... ...
----------------------------------------------------------------
Удаление резидентных подпрограмм из памяти
Когда программа закончила использование RTL, или когда рези-
дентная подпрограмма больше не нужна, может возникнуть необходи-
мость восстановления памяти, которая была распределена для этой
подпрограммы. Наиболее простым способом удаления резидентной
подпрограммы является перезагрузка системы. Это позволит восста-
новить все векторы, которые требует система, и возвратить системе
всю распределенную память. Однако, это очень решительный шаг и
лучше зарезервировать его для безнадежных ситуаций.
Удаление подпрограммы без перезагрузки системы необходимо вы-
полнять с помощью следующих двух шагов:
1. Отключение подпрограммы.
2. Восстановление памяти.
Первый шаг состоит в установке в нулевое состояние вектора,
- 3-43 -
указывающего на подпрограмму. Нулевое состояние для любых потен-
циальных пользователей означает, что подпрограмма больше недо-
ступна. Если резидентная подпрограмма была расположена на участке
памяти ("заплате") для ранее существующего вектора, то вектор
должен быть восстановлен так, чтобы он указывал на первоначальную
ячейку. Можно написать программу для восстановления вектора, если
значение старого вектора хранится где-нибудь в резидентной под-
программе, и программа восстановления может найти его. Этот про-
цесс сохранения вектора для его последующего восстановления де-
монстрируется в листингах программ INIT28 (листинг 3-12) и REMOVE
(листинг 3-13).
Если память резидентной подпрограммы управляется с помощью
своего собственного прерывания аппаратных средств (но не в форме
"заплаты"), то перед удалением резидентной подпрограммы необходи-
мо обеспечить невозможность возникновения прерывания от этого ус-
тройства. Можно изменить вектор в таблице или оставить его так,
как он есть.
РЕГИСТРЫ ВНЕШНИЙ СЕГМЕНТ
.----------------.
AX:4B00 (шест.)<---Функция ВЫПОЛНИТЬ ПРОГРАММУ| ... |
|----------------|
BX:Указатель на имя файла в ASCIIZ ---------->| имя файла/пути |
| нулевой байт |
DX:Указатель на блок параметра --------. |----------------|
| | ... |
Адрес ENVIRONMENT (СРЕДА) | \/\/\/\/\/\/\/\/ xxxx:0000 .--------
---------. |
| ASCIIZ string 1 |<----. |
| ASCIIZ string 2 | | |
| ... | | | СЕГМЕНТ ДАННЫХ
| ASCIIZ string N | | | .----------------.
| нулевой байт | | | | ... |
----------------- | ----->|----------------|
-----------|envir.seg или 0 |
|----------------|
Текстовый буфер командной строки <------------|DWORD:указывает |
| текст |
|----------------|
File Control Block 1:load @ 5Ch <------------|DWORD:указывает |
(FCB1-блок управления файлом 1:загрузка @ 5Ch)| FCB 1 |
|----------------|
File Control Block 2:load @ 6Ch <-----------|DWORD:указывает |
(FCB2-блок управления файлом 2:загрузка @ 6Ch)| FCB 2 |