MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 18, М.: Диалог-МИФИ, 1995, 254 стр. 3.3. Префикс программного сегмента PSPПрефикс программного сегмента всегда создается при загрузке программы в память и имеет следующий формат: Программы могут получить из PSP такую информацию, как параметры командной строки при запуске, размер доступной памяти. Зная адрес PSP, легко найти сегмент области переменных среды и получить другую полезную информацию. Формат PSPФормат блока PSP и описание назначения всех его полей приведены ниже:
Для обращения к полям 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)); } |