Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

MS-DOS для программиста

© Александр Фролов, Григорий Фролов
Том 18, М.: Диалог-МИФИ, 1995, 254 стр.

[Назад] [Содеожание] [Дальше]

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

Префикс программного сегмента всегда создается при загрузке программы в память и имеет следующий формат:

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

Формат PSP

Формат блока PSP и описание назначения всех его полей приведены ниже:

Смещение, байт Размер, байт Имя поля Описание
0 2 int20h Двоичный код команды INT 20h (программы могут использовать эту команду для завершения своей работы)
2 2 mem_top Нижняя граница доступной памяти в системе в параграфах
4 1 reserv1 Зарезервировано
5 5 call_dsp Команда 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 Диспетчер функций MS-DOS
83 9 reserv3 Зарезервировано
92 16 fcb1 Если первый аргумент командной строки содержит правильное имя файла, поле форматируется как стандартный блок FCB
108 20 fcb2 Заполняется для второго аргумента командной строки аналогично fcb1
128 1 p_size Количество значащих символов в неформатированной области параметров, либо буфер обмена с диском DTA , назначенный по умолчанию
129 127 parm Неформатированная область параметров, заполняется при запуске программы из командной строки

Для обращения к полям PSP мы определим тип данных PSP:

typedef struct
{
  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 ;

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

Поле term_adr содержит значение, полученное из таблицы векторов прерываний для прерывания INT 22h. Это адрес программы, которая получает управление, когда текущая программа завершает свою работу. Такой программой может быть, например, программа command.com .

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

Поле cbrk_adr содержит адрес программы обработки прерывания, которое возникает, когда пользователь нажимает комбинацию клавиш <Ctrl+Break>. При запуске программы этот адрес переписывается из ячейки таблицы векторов прерываний, соответствующей прерыванию INT 23h .

Программа может устанавливать свою собственную функцию обработки прерывания по комбинации клавиш <Ctrl+Break>. Поэтому при завершении работы программы MS-DOS восстанавливает оригинальное значение из поля cbrk_adr.

Поле crit_err предназначено для восстановления содержимого вектора прерывания INT 24h (адреса обработчика критических ошибок).

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

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

Определение адреса PSP

Как программе определить адрес своего PSP ?

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

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

Программа PARM

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


Листинг 3.2. Файл parm\ parm.asm


  .MODEL  tiny
  DOSSEG
  .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:

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

  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

Для трансляции и редактирования программы PARM вы можете использовать пакетный файл, приведенный в листинге 3.3.


Листинг 3.3. Файл parm\mk.bat


tasm parm
tlink parm /t

Программа PSPLIST

Программа PSPLIST (листинг 3.4), составленная на языке С, определяет адрес своего блока PSP , затем показывает содержимое некоторых полей PSP.


Листинг 3.4. Файл psplist\psplist.cpp


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

typedef struct
{
  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 ;

void main(void)
{
  PSP  far *psp_ptr;

  // Конструируем указатель на PSP 
  psp_ptr = (PSP  far *)MK_FP (_psp, 0);

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

[Назад] [Содеожание] [Дальше]