03/05/95 03:08pm
upr_prg.lek
Роберт Журден "Справочник
программиста на компьютере фирмы
IBM".П.Нортон, Р.Уилтон "IBM PC и PS/2
руководство по
программированию" перевод
В.Н.Григорьева М "Радио и
связь" 1994.
Управление программами.
Обычно программы загружаются в память, запускаются, а затем удаляются операционной системой при завершении. Некоторые программы действуют как драйверы устройств или драйверы прерываний и они должны быть сохранены в памяти ("резидентными") после их завершения (вектора прерываний обеспечивают механизм, посредством которого последующие программы могут обращаться к резидентным процедурам). Иногда программе необходимо запустить из себя другую программу или выполнить команду DOS. Все эти операции можно выполнить, используя соответствующие службы DOS.
При загрузке программы в память ей выделяется область памяти, описываемая специальным управляющим блоком, и создается PSP (префикс программного сегмента):
При передаче управления программе ее регистры настраиваются следующим образом:
Манипуляции с памятью.
Обычно
программе отводится вся свободная,
в момент запуска память. Поскольку
реально может понадобиться меньший
объем, "лишняя" память может
быть использоваться по усмотрению
программиста.
Для определения фактических затрат
памяти, необходимых для размещения
кода и статических данных в конце
программы помещается
псевдосегмент вида:
ZSEG SEGMENT
;
ZSEG ENDS
Зная фактические затраты памяти можно сократить выделенный объем память до действительно необходимого размера, а остальное "вернуть ОС".
MS DOS обеспечивает три функции распределения памяти, номера от 48H до 4AH прерывания 21H:
Функция 48H отводит блок памяти.
Функция 49H - освобождает блок памяти.
Третья функция (4Ah) меняет размер памяти, отведенной для программы; эта функция должна быть использована перед двумя остальными. После ее выполненияможно спокойно отводить и освобождать блоки памяти.
Программа должна освободить все отведенные ею блоки перед завершением, иначе эта память будет недоступной для последующего использования.
Все три функции распределения памяти прерывания 21H используют 16-битный адрес начала блока памяти, с которым они оперируют. Этот адрес соответствует номеру 16-ти байтного напараграфа с которого начинается требуемый блок памяти.
Для всех трех
функций, BX содержит число
параграфов, которые будут
отводиться или освобождаться.
Адрес блока, параметры которого
изменяются помещается в регистр EX.
Если функция не может быть
выполнена, то устанавливается флаг
переноса, а в AX возвращается код
ошибки, объясняющий причину.
Возможны три кода ошибки:
7 разрушен управляющий блок памяти
8 недостаточно памяти для выполнения функции
9 неверный адрес блока памяти
;---освобождение памяти (ES имеет значение при старте равное PSP)
; ES - блок памяти, параметры которого меняем
; BS - новый размер
MOV BX,ZSEG ;получаем # параграфа конца программы + 1
MOV AX,ES ;получаем # параграфа начала программы
SUB BX,AX ;вычисляем размер программы в параграфах
MOV AH,4AH ;номер функции
INT 21H ;освобождаем память
JC ERROR1 ;проверяем на ошибку
;при ошибке: AX - код ошибки, BX - максимальновозможный размер
;---отведение блока размером 1024 байта
; BX - размер требуемого блока
MOV AH,48H ;номер функции
MOV BX,64 ;требуем 64 параграфа
INT 21H ;пытаемся отвести блок
JC ERROR2 ;обрабатываем ошибку в случае неудачи
MOV BLOCK_SEG,AX;иначе сохраняем адрес блока
;при ошибке: AX - код ошибки, BX - размер максимальнодоступного блока
;без ошибок: AX - адрес выделенного блока (номер параграфа)
;---освобождаем тот же блок
; ES - адрес (номер параграфа) освобождаемого блока
MOV AX,BLOCK_SEG ;получаем стартовый адрес блока
MOV ES,AX ;помещаем его в ES
MOV AH,49H ;номер требуемой функции
INT 21H ;освобождаем блок памяти
JC ERROR3
;при ошибке: AX - код ошибки
;---фиктивный сегмент для определения фактической длины программы
ZSEG SEGMENT
ZSEG ENDS
Запуск одной программы из другой.
MS DOS обеспечивает функцию EXEC (номер 4BH прерывания 21H), реализующую вызов одной программы из другой. Первая программа называется "родителем", а загружаемая и запускаемая - "потомком".
Функция 4BH требует выполнения следующих подготовительных шагов:
1. Подготовить в памяти место, доступное программе (освободить память).
2. Создать блок параметров:
DW
сегментный адрес строки среды
(Строка состоит из одной или
более спецификаций, которым
следует MS DOS при выполнении
программы. Элементы строки
разделяются символом ASCII 0, за
последним элементом должны
следовать два символа ASCII 0.
Строка должна начинаться на
границе параграфа. Если строка
будет пустой, то новая
программа может работать с той
же строкой среды, что и
программа "родитель".)
DD сегмент и смещение командной строки (Аргументы для новой программы. Командная строка должна начинаться байтом, содержащим длину этой строки, и завершаться символом ASCII 0Dh.)
DD сегмент и смещение первого FCB
DD сегмент и смещение второго FCB (Управляющие блоки файлов (FCB). FCB содержит информацию об одном или двух файлах, указанных в командной строке. Если открываемых файлов нет, то надо заполнить все 8 байт символом ASCII 0. Начиная с версии MS DOS 2.0, использование FCB необязательно. Адрес блока параметров должен быть помещен в ES:BX.
3. Построить
строку, содержащую накопитель, путь
и имя программы - обычная строка ASCII,
завершаемая кодом ASCII 0.
Адрес строки должен быть загружен в
DS:DX.
4. Сохранить значения регистров SS и SP в переменных (дочерняя программа создаст свой PSP и стек.
5. Выполнить:
MOV AH,4BH ;функция EXEC
MOV AL,0 ;выбираем "загрузку и запуск"
INT 21H ;запускаем задачу
MS DOS предоставляет возможность программе потомку передать родителю код возврата, таким образом могут быть переданы ошибки и статус.
Что касается самой функции запуска, то при возникновении ошибки устанавливается флаг переноса, а регистр AX в этом случае будет возвращать:
01h - неверный номер функции,
02h - файл не найден,
03h - маршрут не найден,
05h - доступ запрещен,
08h - при отсутствии достаточной памяти,
0Ah - ошибка в блоке параметров среды,
0Bh - ошибка в формате.
;---в сегменте данных
FILENAME DB 'A:TRIAL.EXE',0 ;загружаем TRIAL.EXE
PARAMETERS DW 7DUP(0) ;нулевой блок параметров
KEEP_SS DW 0 ;переменная для SS
KEEP_SP DW 0 ;переменная для SP
;---перераспределение памяти
MOV BX,ZSEG ;получить # параграфа конца
MOV AX,ES ;получить # параграфа начала
SUB BX,AX ;вычислить размер программы
MOV AH,4AH ;номер функции
INT 21H ;перераспределение
;---указываем на блок параметров
MOV AX,SEG PARAMETERS ;в ES - сегмент
MOV ES,AX ;
MOV BX,OFFSET PARAMETERS ;в BX - смещение
;---сохранить копии SS и SP
MOV KEEP_SS,SS ;сохраняем SS
MOV KEEP_SP,SP ;сохраняем SP
;---указываем на строку имени файла
MOV DX,OFFSET FILENAME ;смещение - в DX
MOV AX,SEG FILENAME ;сегмент - в DS
MOV DS,AX ;
;---загрузка программы
MOV AH,4BH ;функция EXEC
MOV AL,0 ;выбираем "загрузку и запуск"
INT 21H ;запускаем задачу
;---впоследствии, восстанавливаем регистры
MOV AX,DSEG ;восстанавливаем DS
MOV DS,AX ;
MOV SS,KEEP_SS ;восстанавливаем SS
MOV SP,KEEP_SP ;восстанавливаем SP
;---в конце программы создаем фиктивный сегмент
ZSEG SEGMENT
ZSEG ENDS
Использование команд интерфейса с пользователем из программы.
Программа может вызвать любую команду DOS, воспользовавшись материалом, приведенным выше. Но при этом в ОП будет загружаться новая копия COMMAND.COM, что приведет к непроизводительным затратам памяти.
Можно сэкономить память, обращаясь к уже имеющемуся COMMAND.COM, если в блоке параметров указать ссылку на командную строку, содержащую:
1 Байт, соответствующий длине строки;
2 Накопитель на котором наодится COMMAND.COM;
3 /C - признак обращения к COMMAND.COM;
4 Команду MS DOS.
Сохранение программы в памяти после завершения.
Программы, оставленные резидентными в памяти, могут служить в качестве утилит для других программ. Обычно такие программы вызываются через неиспользуемый вектор прерывания. MS DOS рассматривает такие программы как часть операционной системы, защищая их от наложения других программ, которые будут загружены впоследствии.
Резидентные
программы обычно пишутся в форме COM.
Завершение программы прерыванием
27H оставляет ее резидентной в
памяти.
CS должен
указывать на начало PSP, а DX должен
содержать смещение конца
программы, отсчитываемое от начала
PSP для того, чтобы эта функция
работала правильно.
В программах COM, CS сразу
устанавливается соответствующм
образом.
При размещении резидентных программ желательно минимизировать затраты памяти это можно сделать:
1 Поместив процедуру в начало программы, исключив установочную часть кода из резидентной порции;
2 Переслав код процедуры вниз в неиспользуемую часть PSP, начиная со смещения 60H, что освободит 160 байт памяти.
;---здесь процедура прерывания
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 ;завершение
Оставить программу резидентной можно с помощью функции 31H прерывания 21H, которая работает аналогично, за исключением того, что в DX должно содержаться число 16-байтных параграфов, требуемых процедуре. Преимуществом этой функции является то, что она передает родительской программе код выхода, дающий информацию о статусе процедуры. Родительская программа получает этот код с помощью функции 4DH прерывания 21H.
Коды выхода:
AL - код из дочерней программы;
AH - признак завершения:
00 нормальное (не принудительное) завершение,
01 завершение по Ctrl-C^
02 остановка средствами ОС по критической ошибке,
03 нормальное завершение без освобождения памяти (программа осталась резидентной).
Загрузка и запуск программных оверлеев.
Оверлеи - это части программы, которые остаются на диске, в то время как тело программы резидентно в памяти. Когда требуется функция, выполняемая каким-либо оверлеем, то он загружается в память и программа вызывает его как процедуру. Различные оверлеи могут загружаться в одно и то же место памяти, перекрывая предыдущий код. Эта техника используется для экономии памяти.
MS DOS использует функцию EXEC для загрузки оверлеев. Эта функция, номер 4BH прерывания 21H, используется также для загрузки и запуска одной программы из другой, если поместить код 0 в AL. Если в AL поместить код 3, то тогда будет загружен оверлей. В этом случае не создается PSP, поэтому оверлей не устанавливается как независимая программа. Такая процедура просто загружает оверлей, не передавая ему управления.
Кроме кода 3, засылаемого в AL, необходимо установить для этой функции еще два параметра:
DS:DX должны указывать на строку, дающую путь к файлу оверлея, завершаемую байтом ASCII 0.
ES:BX должны указывать на 4-байтный блок параметров, который содержит:
2-байтный номер параграфа, куда будет загружаться оверлей,
2-байтный фактор привязки, который будет использоваться для привязки адресов в оверлее (для формата EXE).
Если при возврате установлен флаг переноса, то была ошибка и ее код будет возваращен в AX (см. выше).
Передача управления оверлею осуществляется как к далекой процедуре, адрес вызова вычисляется исходя из значений параграфов материнской и дочерней программы. Возврат - обычным образом.