Операционная система MS DOS

       

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


Теперь займемся вплотную префиксом программного сегмента PSP. Формат PSP уже был описан ранее, для удобства приведем его еще раз вместе со структурой из файла sysp.h:



(0) 2 int20h двоичный код команды int 20h (программы могут использовать эту команду для завершения своей работы)
(+2) 2 mem_top нижняя граница доступной памяти в системе в параграфах
(+4) 1 reserv1 зарезервировано
(+5) 5 call_dsp команда вызова FAR CALL диспетчера MS-DOS
(+10) 4 term_adr адрес завершения (Terminate Address)
(+14) 4 cbrk_adr адрес обработчика Ctrl-Break
(+18) 4 crit_err адрес обработчика критической ошибки
(+22) 2 parn_psp сегмент PSP программы, запустившей данную программу (программы-родителя)
(+24) 20 file_tab таблица открытых файлов, если здесь находятся байты 0FFH, то таблица не используется
(+44) 2 env_seg сегмент блока памяти, содержащего переменные среды
(+46) 4 ss_sp адрес стека SS:SP программы
(+50) 2 max_open максимальное число открытых файлов
(+52) 4 file_tba адрес таблицы открытых файлов
(+56) 24 reserv2 зарезервировано
(+80) 3 disp диспетчер функций DOS
(+83) 9 reserv3 зарезервировано
(+92) 16 fcb1 форматируется как стандартный FCB, если первый аргумент командной строки содержит правильное имя файла
(+108) 20 fcb2 заполняется для второго аргумента командной строки аналогично fcb1
(+128) 1 p_size число значащих символов в неформатированной области параметров, либо буфер обмена с диском DTA, назначенный по умолчанию
(+129) 127 parm неформатированная область параметров, заполняется при запуске программы из командной строки

#pragma pack(1)

typedef struct _PSP_ { unsigned char int20h[2]; unsigned mem_top; unsigned char reserv1; unsigned char call_dsp[5]; void far *term_adr; void far *cbrk_adr; void far *crit_err; unsigned parn_psp; unsigned char file_tab[20]; unsigned env_seg; void far *ss_sp; unsigned max_open; void far *file_tba; unsigned char reserv2[24]; unsigned char disp[3]; unsigned char reserv3[9]; unsigned char fcb1[16]; unsigned char fcb2[20]; unsigned char p_size; unsigned char parm[127]; } PSP;


#pragma pack()

Программы могут получить из PSP такую информацию, как параметры командной строки при запуске, размер доступной памяти, найти сегмент области переменных среды и т.д.

Как программе узнать адрес своего PSP? Очень просто сделать это для программ, написанных на языке ассемблера: при запуске программы этот адрес передается ей через регистры DS и ES. То есть этот адрес равен DS:0000 или ES:0000 (для COM-программ на PSP указывают также регистры CS и SS).

Для программ, составленных на языке Си, доступна глобальная переменная _psp типа unsigned. Эта переменная содержит сегментный адрес PSP.

В качестве примера приведем текст программы на языке ассемблера, которая выводит на экран передаваемые ей через PSP параметры запуска:

.MODEL tiny DOSSEG

.STACK 100h

.DATA

parm_msg DB "Укажите параметры", 13, 10, "$"

.CODE .STARTUP

mov cl,ds:80h ; количество символов ; в командной строке cmp cl,0 je ask_parm ; нет параметров - просим ; задать параметры

mov si,81h ; со смещением 81h ; начинается область ; параметров cld

get_parm:

lods BYTE PTR es:[si] ; загружаем в al ; очередной ; символ строки ; параметров

mov ah,2 ; выводим его на экран mov dl,al int 21h

loop get_parm jmp end_progr

ask_parm:

mov ah, 9h mov dx, OFFSET parm_msg int 21h

end_progr: .EXIT 0

END

Приведенная ниже программа, составленная на языке Си, определяет адрес своего PSP, затем показывает содержимое некоторых полей из PSP:

#include <stdio.h> #include <stdlib.h> #include <dos.h> #include "sysp.h"

void main(void);

void main(void) {

PSP far *psp_ptr;

psp_ptr = FP_MAKE(_psp,0); // Конструируем указатель // на PSP printf("PSP расположено по адресу: %Fp\n" "Доступно памяти, байт: %ld\n" "PSP родительской программы: %Fp\n" "\n", psp_ptr, (long)(psp_ptr->mem_top)*16L, FP_MAKE(psp_ptr->parn_psp,0)); exit(0); }

Используя поле parn_psp, можно определить адрес PSP родительской программы, то есть программы, запустившей Вашу программу.



Немного о назначении полей term_adr, cbrk_adr, crit_err.

Поле term_adr содержит значение, полученное из таблицы векторов прерываний для вектора 22h. Это адрес программы, которая получает управление, когда текущая программа завершает свою работу. Это может быть, например, COMMAND.COM. Программа может создать свою собственную подпрограмму, которая будет получать управление при завершении работы основной программы. Она может записать свой собственный адрес в вектор 22h, затем запустить другую программу. В таком случае в запущенной программе это поле в ее PSP будет содержать адрес родительской программы. Когда основная программа завершает свою работу, DOS восстанавливает адрес программы завершения в векторе 22h из поля term_adr PSP.

Поле cbrk_adr содержит адрес программы обработки прерывания по нажатию Ctrl-Break из вектора 23h таблицы векторов прерываний. Так как программа может устанавливать свою собственную программу обработки прерывания по Ctrl-Break, DOS при завершении работы программы восстанавливает оригинальное значение из поля cbrk_adr.

Аналогично поле crit_err предназначено для восстановления содержимого вектора 24h - адреса обработчика критических ошибок.

Способы переназначения векторов будут приведены в разделе, посвященном прерываниям.

Конечно, программы, составленные на языке Си, не обязательно должны использовать PSP для доступа к параметрам командной строки и переменным среды. Для этого есть параметры функции main и набор функций типа getenv, putenv и т.п., предназначенных для работы со средой. Но ведь PSP содержит и другую информацию!


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