Системное программное обеспечение персональных ЭВМ

Программный сегмент и программный идентификатор


11.1. Программный сегмент и программный идентификатор

Для программы, вызванной на выполнение, DOS выделяет блок памяти, называемый программным сегментом. Программный сегмент всегда начинается на границе параграфа. В начале программного сегмента DOS строит PSP (Program Segment Prefix - Префикс Программного Сегмента), который занимает 256 байт. (Для построения PSP в DOS имеются функции 0x26, 0x55, но это чисто внутренние функции DOS, мы оставим их без внимания). Директива ORG 100h, которой часто начинаются Ассемблерные программы, как раз учитывает смещение начала программы относительно начала программного сегмента, равное длине PSP. При передаче программе управления сегментный адрес PSP находится в регистрах DS и ES.

Формат PSP описывается структурой struct PSP программного примера 11.1. Некоторые поля PSP "остались в наследство" от ранних версий DOS и даже от операционной системы CP/M и в современных версиях DOS не используются, хотя и исправно формируются операционной системой. Это прежде всего поле ret _op, используемое для возможного завершения программы по команде RET 0, а также поле old_call_dos, содержащее команду вызова диспетчера функций DOS. Обращение к этому полю в программе может использоваться вместо команды INT 21h, но в современных версиях DOS для этих целей лучше обращаться к полю new_call_dos. Поле end_of_mem содержит сегментный адрес конца доступной памяти в системе. В три поля: term_ptr, ctrlbrk_ptr, criterr_ptr DOS при загрузке программы копирует содержимое векторов прерываний: 0x22, 0x23, 0x24, представляющее собой адреса обработчиков: завершения программы, комбинации клавиш Ctrl+Break, критической ошибки - соответственно. Предполагается, что программа может свободно перенаправить эти векторы на собственные обработчики соответствующих ситуаций, но от забот по восстановлению векторов программа избавляется, так как при ее завершении DOS сама восстанавливает векторы из соответствующих полей PSP завершаемой программы. Для аналогичных целей предназначено и поле stack_ptr - в нем сохраняется (а при завершении - из него восстанавливается) адрес стека, использовавшегося до вызова программы.
Поле, именуемое father_psp, содержит сегментный адрес PSP родителя - программы, запустившей данную программу, обычно родителем является COMMAND.COM.

При загрузке программы DOS, кроме программного сегмента, создает для нее еще и сегмент окружения (environment). Сегмент окружения содержит ASCIIZ-строки, задающие значения некоторых глобальных переменных, эти значения могут устанавливаться командой DOS SET, они доступны командным файлам и - через PSP - программам. Набор строк окружения заканчивается пустой ASCIIZ-строкой (нулем). В DOS 3.0 и выше за ним следует еще 2-байтное число строк вызова (обычно 1) и далее - строка (или строки) вызова программы. Обычно в первую (до строк вызова) часть порождаемой программы копируется содержимое окружения программы-родителя. Программа имеет доступ к своему сегменту окружения через поле env_seg PSP, содержащее сегментный адрес окружения.

Поле JFT (Job File Table - Таблица Файлов Задачи) представляет собой массив из 20 однобайтных элементов. При открытии программой файла DOS формирует для него блок-описатель в системной таблице файлов и помещает ссылку на него (его номер) в свободный элемент JFT. Дескриптор файла, возвращаемый программе DOS при открытии файла, является номером элемента в JFT. При запуске программы первые пять элементов создаваемой для нее JFT содержат ссылки на системные файлы, остальные свободны - содержат код 0xFF. В описаниях DOS часто можно встретить упоминание об ограничении на число одновременно открытых в программе файлов, при этом обычно называется число 20 (включая 5 системных файлов). Первым объяснением этого ограничения является размер JFT. Ограничение это, однако, не является непреодолимым. В самом PSP зарезервированы пути для его обхода: при обработке JFT DOS использует не прямое обращение к полю JFT PSP, а косвенное - через поле JFT_ptr, а в качастве ограничителя размера JFT - не константу 20, а значение поля JFT_size PSP. Таким образом, программа может в другом месте выделить память для размещения JFT большего размера и, изменив поля JFT_ptr, JFT_size в своем PSP, обеспечить работу с новой таблицей файлов.


DOS, начиная с версии 3.30, поддерживает эти операции функцией 0x67, которая выделяет память для новой JFT (требуемый размер JFT задается в BX), копирует в выделенную область старую JFT и исправляет поля PSP. Следует иметь в виду, что даже если в CONFIG.SYS значение параметра FILES больше 20, JFT в PSP формируется все равно 20-байтной, и программа сама должна позаботиться о ее расширении. Действия по увеличению размера JFT являются необходимыми, но не всегда достаточными для снятия ограничения на число открытых файлов - возможно, для этого еще потребуется расширить системную таблицу файлов (см. главу 13). Непреодолимым ограничением представляется размер элемента JFT - 1 байт, который позволяет представить число от 0 до 254 (255 - признак свободного элемента). Трудно, впрочем, представить себе программу, в которой необходимо иметь одновременно открытыми 250 файлов.

Вернемся к описанию формата PSP. Еще 36 бит, следующих за полями, описанными struct PSP, отводятся для двух блоков FCB, которые DOS строит для файлов, имена которых, возможно, являются параметрами программы.

Остальные 128 байт PSP - неформатированная его часть. При вызове программы в ней, начиная со второго ее байта, располагается остаток командной строки - часть строки вызова после имени программы, то есть, параметры, переданные программе при вызове. Эта строка не закрывается кодом 0, поэтому первый байт неформатированной области содержит число символов в остатке командной строки. Неформатированная область PSP после загрузки программы назначается DOS в качестве исходной DTA загруженной программы.
Программа может получить доступ к своему PSP либо из начального содержимого регистров DS или ES, либо при помощи функций DOS 0x51 или 0x62 (обе функции возвращают в BX сегментный адрес PSP). По некоторым источникам функция 0x51 (и родственная ей 0x50) в версиях DOS до 3.0 работала не во всех ситуациях надежно, функция же 0x62 является документированной. Мы в наших примерах используем обе эти функции.
После всего, сказанного выше, программа примера 11.1 не нуждается в комментариях.Эта программа извлекает из своего PSP всю или почти всю полезную информацию. Читатель может усовершенствовать ее, добавив в struct PSP описание полей блоков FCB. Иллюстрация обращения к остатку командной строки есть в примере 11.5.

Содержание раздела