|----------------|
Замечание: Все указатели DWORD хранятся как, | OFFSET (смеще-| Замечание: Все указатели DWORD хранятся как | OFFSET (смеще-
следующее после SEGMENT (сег- | ние) | ние), следующее после \/\/\/\/\/\/\/\/ SEGMENT (сег-
мента) \/\/\/\/\/\/\/\/ мента)
Рис.3-13. Блок параметров для функции 4Bh (AL=0) -
EXECUTE (выполнить)
После того, как резидентная подпрограмма или RTL будут отклю-
чены, необходимо выполнить второй шаг, заключающийся в восстанов-
лении памяти. Память восстанавливается из MS-DOS посредством
функции с номером 49h "Освободить распределенную память". MS-DOS
безразлично, относится или нет восстанавливаемая память к прог-
- 3-44 -
рамме, так что если адрес начала блока памяти занят резидентной
подпрограммой, то память может быть освобождена и восстановлена.
Установленная подпрограмма может обычно определить этот адрес,
так как одной из ее опций является обеспечение кода функции вызо-
ва подпрограммы и сообщения ей о запрещении и удалении самой се-
бя. Для подпрограмм, которые могут быть установлены посредством
использования векторов прерываний, для целей инструктирования об
удалении самой себя, может быть распределен второй вектор преры-
вания.
Если известно, что адрес сегмента вектора прерывания подпрог-
раммы и адрес сегмента блока памяти подпрограммы одинаковы, то
другим способом является написание программы чтения вектора, оп-
ределения из него адреса сегмента блока памяти, и инструктирова-
ние MS-DOS об освобождении памяти.
В некоторых случаях ни один из этих способов не работает, так
как MS-DOS не может восстановить всю память. Проблема скорее все-
го относится к внутренним проблемам MS-DOS, так как возникает не-
адекватное представление для выполнения некоторых противоречивых
требований.
Функция 4Bh - загрузка и выполнение программ
Резидентные подпрограммы и RTL очень часто инициируются с по-
мощью входного файла пользователя или командного файла, но при
случае программе может понадобиться загрузить другую программу в
память, либо использовать ее в качестве оверлейной (перекрывае-
мой) программы, или как часть процесса установки резидентной
подпрограммы. В любом случае, первоначальная программа называется
порождающей (parent), а другая программа порожденной (child).
MS-DOS для таких случаев обеспечивает функцию загрузки и вы-
полнения программ с кодом 4Bh. Эта функция может выполняться в
одном из двух режимов. Первый режим - выполнение программы -
предназначен для загрузки программного файла в память и выполне-
ния этой программы. Порожденная программа выполняется без управ-
ления со стороны порождающей программы. Этот режим выбирается пу-
тем установки регистра AL в нулевое значение и установкой
соответствующих значений в блоке параметров. Параметры, требуемые
для выполнения функции 4Bh, показаны на рис.3-13, а пример за-
грузки и выполнения программы содержится в программе LOAD (за-
грузка), показанной в листинге 3-8. Макробиблиотека, упоминаемая
в программе LOAD, является такой же, какая использована в прог-
рамме EXRTL (смотри листинг 3-5).
Листинг 3-8. Загрузка программы с помощью функции MS-DOS
4Bh (AL = 0)
----------------------------------------------------------------
;======LOAD.ASM - Этот файл вырабатывает файл типа .COM ========
; LOAD имеет возможность загрузки и выполнения другой программы.
; LOAD вызывается путем набора следующей информации:
; "LOAD <имя файла> < аргументы программы>
; Между LOAD и именем файла, а также между именем файла и аргу-
; ментами должен быть только один символ "пробел". Имя файла
; должно включать расширение.
;
NEWPROG EQU 82h ; адрес загрузки командной строки в PSP
NEWSTR EQU 81h ; адрес строки в PSP (пробел 20h)
NEWLEN EQU 80h ; адрес длины командной строки
- 3-45 -
;
INCLUDE STDMAC.INC ; включение описания макробиблиотеки
;====== ПРОГРАММНАЯ СЕКЦИЯ =====================================
;
code_seg SEGMENT
ASSUME cs:code_seg
ASSUME ds:code_seg
ORG 0
SEG_ORG EQU $
main PROC FAR
start:
mov sp,offset TOP_STK ; установка вершины стека
;
; Грамматический разбор командной строки для поиска конца или
; пробела. Преобразование имени программы в строку ASCIIZ.
;
mov bx,0 ; очистка BX
mov bl,NEWLEN[bx] ; получение длины ком.строки
or bl,bl ; проверка длины строки
jnz cmd_ok
@DisStr bad_cmd ; ошибка в командной строке
jmp exit
cmd_ok:
dec bx ; вычитание 1 для пробелов
mov cx,bx ; копирование длины в счетчик
mov di,NEWPROG ; поиск адреса (1-й не пробел)
mov al,' ' ; поиск значения (пробел)
repne scasb ; поиск расширения файла
pushf ; сохранение результата поиска
sub bx,cx ; получение оставшегося счетчи-
popf ; ка и результатов поиска
jz set_zb ; нулевой флажок => параметры
; (найден пробел)
inc bx ; ненулевой флажок подразуме-
; вает конец строки
set_zb: ; преобразование командной
; строки в ASCIIZ
mov byte ptr NEWSTR[bx],0
mov cmd_buf,cl ; установка длины строки пара-
; метра
cmp cl,0 ; достигнут конец строки?
jle free_mem ; нет параметров команды
;
; Прием остатка строки и передача его в текстовый буфер команд-
; ной строки для вызываемой программы
;
inc cl ; передача CR
mov si,di ; передача исходного индекса
mov di,offset cmd_txt ; или установка индекса назна-
; чения
rep movsb ; передача остатка строки
add cmd_buf,1 ; увеличение количества проб.
;
; Освобождение системной памяти для загрузчика и вызываемой
; программы. Сокращение блока распределения до необходимого
; минимума.
- 3-46 -
;
free_mem:
mov bx,(offset LST_BYT - SEG_ORG + 15) shr 4
mov ah,04Ah ; ES содержит адрес PSP
@DosCall ; модификация распред. памяти
jnc modify_ok
push ax ; (помещение в стек при ошиб-
; ке)
@DisStr fail4A ; сообщение об ошибке или
; завершение, если сбой
jmp error
;
; Установка блока параметров и регистровых параметров для
; вызова функции загрузки или выполнения программы.
modify_ok:
mov ax,cs ; установка всех параметров
mov p1,ax ; сегментов в этот сегмент
mov p2,ax
mov p3,ax
mov dx,offset NEWPROG
mov bx,offset param_block
mov spoint,sp ; сохранение указателя стека
mov ax,4B00h ; функция загрузки или выпол-
; нения программы
@DosCall
;
; Восстановление регистров сегмента и указателя стека после
; вызова.
;
mov cx,cs ; дублирование CS во все сегм.
mov ss,cx ; сначала восстанавливается стек
mov sp,cs:spoint ; восстановление указателя стека
mov ds,cx
mov es,cx
jnc exit ; выход из программы, если все хорошо
push ax ; сохранение кода ошибки
@DisStr fail4B ; вывод ошибки, если сбой
;
; Грамматический разбор кода ошибки, возвращаемого системой
; и отображение соответствующего текста сообщения
;
error:
pop ax ; обратное получение кода ошибки
@Case ax,<+,2,7,8,9,10h,11h>,
mov dx,offset err0 ; плохой код ошибки - неравны
jmp merge
em1: mov dx,offset err1 ; неправильная функция
jmp merge
em2: mov dx,offset err2 ; файл не найден
jmp merge
em7: mov dx,offset err7 ; память засорена
jmp merge
em8: mov dx,offset err8 ; недостаточно памяти
jmp merge
em9: mov dx,offset err9 ; неправильный блок памяти
jmp merge
em10: mov dx,offset err10 ; неправильная среда
- 3-47 -
jmp merge
em11: mov dx,offset err11 ; неправильный формат файла .EXE
jmp merge
merge: mov ah,09h ; отображение строки
@DosCall
exit: mov ax,04C00h ; завершение при окончании
@DosCall
main ENDP
;
bad_cmd db 'Error in Command Line',CR,LF,'$'
; ошибка в командной строке
fail4A db 'Failed to Modify Allocated Memory Blocks'
db CR,LF,'$'
; сбой при модификации блока распределенной памяти
fail4B db 'Failed to Load Program Overlay',CR,LF,'$'
; сбой при загрузке программного оверлея
err0 db '>>> UNKNOWN ERROR CODE <<<',CR,LF,'$'
; неизвестный код ошибки
err1 db '>>> invalid function <<<',CR,LF,'$'
; неправильная функция
err2 db '>>> file not found <<<',CR,LF,'$'
; файл не найден
err7 db '>>> memory arena trashed <<<',CR,LF,'$'
; память засорена
err8 db '>>> not enough memory <<<',CR,LF,'$'
; недостаточно памяти
err9 db '>>> invalid memory block <<<',CR,LF,'$'