MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 18, М.: Диалог-МИФИ, 1995, 254 стр. 2.4. Блоки управления памятью в MS-DOSВся оперативная память в MS-DOS разделена на фрагменты, перед которыми распложены блоки MCB . Как мы уже говорили в первой главе, эти блоки описывают фрагменты памяти. Поле векторной таблицы связи mcb_seg содержит сегментный адрес первого блока управления памятью MCB . Блок MCB всегда начинается на границе параграфа, поэтому полный адрес первого блока будет равен mcb_seg:0. В этом разделе мы научим вас просматривать цепочку блоков MCB и определять тип соответствующих этим блокам фрагментов памяти. Распределение памяти в MS-DOSДля лучшего понимания механизма управления памятью вспомним распределение памяти в MS-DOS:
Первый килобайт памяти занимает таблица векторов прерываний . Она содержит 256 элементов, имеющих размер 4 байта. Это дальние адреса обработчиков прерываний, состоящие из компонент сегмента и смещения. Подробно формат и использование этой таблицы будет обсуждаться в главе, посвященной прерываниям . Адреса 0000:0400 - 0000:04FF (или от 0040:0000 до 0050:0000) занимает область данных BIOS . Это так называемые внутренние переменные BIOS . К ним можно обращаться для получения различной информации. При этом необходимо только помнить, что формат этой области может быть различным для различных версий BIOS. Начиная с адреса 0000:0500 (или с адреса 0050:0000, что одно и то же) следует область данных MS-DOS. Здесь MS-DOS хранит свои внутренние таблицы, переменные и структуры данных. Формат этой области (и ее размер) зависит от версии операционной системы. Далее следует большая область памяти, используемая MS-DOS. Здесь находятся:
После драйверов располагается резидентная порция командного процессора command.com . Она, в частности, обрабатывает прерывания INT 22h, INT 23h и INT 24h . Следующая область памяти занимается резидентными программами. После резидентных программ находится выполняющаяся в настоящий момент программа (запущенная из файла с расширением имени .com или .exe). Она может занимать всю оставшуюся память до адреса A000:0000 или только ее некоторую часть. Нижнюю часть адресного пространства (до адреса A000:0000) занимает транзитная часть command.com . Она может перекрываться выполняющейся программой. Если программа перекроет транзитную часть command.com, то после завершения выполнения программы эта часть командного интерпретатора будет загружена заново. Область адресов от A000:0000 до C800:0000 используется видеоконтроллерами. Каждый тип видеоконтроллера использует эту часть памяти по-своему. Далее и до конца границы первого мегабайта оперативной памяти идет область ПЗУ. Там расположено ПЗУ базовой системы ввода/вывода BIOS , ПЗУ интерпретатора BASIC (если такое ПЗУ есть, что совсем не обязательно), расширение BIOS (например, расширение для видеоконтроллера или контроллера диска). Кроме того, в этой области могут находиться порты ввода/вывода некоторых устройств, обращение к которым выполняется аналогично обращению к памяти (устройства, имеющие ввод/вывод, отображенный на память). Диапазон адресов свыше первого мегабайта используется для машин класса не ниже AT. Это так называемая расширенная память (Extended Memory). Она используется операционной системой MS-DOS для организации "электронного" диска, кэш -памяти для дисков, для загрузки резидентных программ и драйверов (совместно с драйвером emm386.exe ). Некоторые прикладные программы хранят в этой области свои данные. Непосредственная адресация расширенной памяти возможна только в защищенном режиме работы процессора. Этот режим используется в операционных системах Windows, Windows NT , OS/2, UNIX и т. п. С расширенной памятью не следует путать дополнительную память (Expanded Memory ). Эта память отображается с помощью специальной аппаратуры и драйверов в область адресного пространства, лежащую ниже границы первого мегабайта основной оперативной памяти. MS-DOS может использовать эту память аналогично расширенной памяти. Зона памяти, начиная с области программ MS-DOS и до видеопамяти разбита на фрагменты. Перед каждым таким фрагментом находится блок управления памятью MCB . Сегментный адрес первого блока MCB , как мы уже говорили, находится в векторной таблице связи в поле mcb_seg. Формат блока MCBВнутри блока MCB хранится длина описываемого данным MCB фрагмента памяти. Следующий фрагмент памяти начинается сразу за предыдущим. Все блоки управления памятью связаны в список. Блоки MCB бывают двух типов - M и Z. M-блоки - это промежуточные блоки. Блок типа Z является последним блоком в списке и может быть только один. Приведем формат блока MCB :
Напомним, что параграф имеет размер 16 байт. Для удобства работы с блоком MCB определим тип MCB: typedef struct { unsigned char type; unsigned owner; unsigned size; char reserve[11]; } MCB ; Просмотр распределения блоков памятиВы можете получить обширную информацию о распределении фрагментов памяти с помощью внешней команды MS-DOS с именем mem. Запустите ее с параметрами /d и /p. На экране вы увидите примерно следующее: Conventional Memory Detail: Segment Total Name Type ------- ---------------- ----------- -------- 00000 1 039 (1K) Interrupt Vector 00040 271 (0K) ROM Communication Area 00050 527 (1K) MS-DOS Communication Area 00070 2 752 (3K) IO System Data CON System Device Driver AUX System Device Driver PRN System Device Driver CLOCK$ System Device Driver A:-D: System Device Driver COM1 System Device Driver LPT1 System Device Driver LPT2 System Device Driver LPT3 System Device Driver COM2 System Device Driver COM3 System Device Driver COM4 System Device Driver 0011C 104 (5K) MSDOS System Data 0025B 16 496 (16K) IO System Data 576 (1K) SETVERXX Installed Device=SETVER 1 152 (1K) XMSXXXX0 Installed Device=HIMEM 4 128 (4K) EMMQXXX0 Installed Device=EMM386 4 432 (4K) FILES=80 256 (0K) FCBS=4 512 (1K) BUFFERS=15 2 288 (2K) LASTDRIVE =Z 3 008 (3K) STACKS=9,256 00662 80 (0K) MSDOS System Program 00667 48 (0K) COMMAND Data 0066A 2 656 (3K) COMMAND Program 00710 80 (0K) MSDOS -- Free -- 00715 1 040 (1K) COMMAND Environment 00756 224 (0K) NC Environment 00764 28 288 (28K) MSCDEX Program 00E4C 30 368 (30K) SMARTDRV Program 015B6 272 (0K) MOUSE Program 015C7 12 912 (13K) NC Program 018EE 224 (0K) COMMAND Data 018FC 2 656 (3K) COMMAND Program 019A2 272 (0K) COMMAND Environment 019B3 224 (0K) MEM Environment 019C1 88 992 (87K) MEM Program 02F7B 460 864 (450K) MSDOS -- Free -- Upper Memory Detail: Segment Region Total Name Type ------- ------ ------------- ----------- -------- 0C94A 1 82 256 (80K) IO System Data 82 224 (80K) MITSUMI Inst. Device=SGCDM 0DD5F 1 8 320 (8K) IO System Data 8 288 (8K) CON Inst. Device=DISPLAY 0DF67 1 224 (0K) SWAKEYB Environment 0DF75 1 848 (1K) SWAKEYB Program 0DFAA 1 24 336 (24K) MOUSE Data 0E59B 1 9 776 (10K) MSDOS -- Free -- 0EC01 2 3 888 (4K) IO System Data 3 856 (4K) IFS$HLP$ Inst. Device=IFSHLP 0ECF4 2 4 288 (4K) MSDOS -- Free -- Memory Summary: Type of Memory Total = Used + Free ---------------- ---------- ---------- ---------- Conventional 655 360 105 424 549 936 Upper 133 984 119 920 14 064 Reserved 393 216 393 216 0 Extended (XMS) 15 594 656 2 335 904 13 258 752 ---------------- ---------- ---------- ---------- Total memory 16 777 216 2 954 464 13 822 752 Total under 1 MB 789 344 225 344 564 000 Memory accessible using Int 15h 0 (0K) Largest executable program size 549 840 (537K) Largest free upper memory block 9 776 (10K) MS-DOS is resident in the high memory area. XMS version 3.00; driver version 3.16 Программа подробно расписывает распределение фрагментов памяти с указанием их начального сегментного адреса и размера. С помощью программы mem.exe вы можете определить назначение каждого фрагмента памяти. Например, в начале памяти по адресу 0000 располагается таблица векторов прерываний (Interrupt Vector). Она занимает 1 Кбайт памяти. Начиная с адреса 0011Ch находится область системных данных MS-DOS. В ней, в частности, находится векторная таблица связи. С помощью программы mem.exe вы можете определить расположение в памяти резидентных программ и драйверов, а также размер занимаемый ими памяти. Например, программе SMARTDRV отведен фрагмент памяти с начальным адресом 00E4Ch, причем размер этого фрагмента равен 30 Кбайт. Мы уже отмечали, что при использовании драйвера emm386.exe пользователь может переместить часть резидентных программ и драйверов в верхнюю область памяти, освободив место в пределах первых 640 Кбайт адресного пространства. В приведенном выше примере драйвер устройства чтения компакт-дисков MITSUMI загружен в верхнюю область памяти начиная с адреса 0C94Ah. В разделе Memory Summary отображается общий, использованный и свободный размер стандартной памяти (Conventional), верхней области памяти (Upper), зарезервированной, например, для организации "теневого" ПЗУ в оперативной памяти (Reserved), а также расширенной памяти (Extended). Существует несколько других удобных программ для просмотра списка блоков MCB . Вот какую информацию выдает известная программа mi.com из пакета PCSHELL при запуске с параметром /A: Memory Info v5.8 Copyright 1989 Central Point Software, Inc. All rights reserved. Conventional memory. Total: 640k Largest executable program: 485k Type Paragraphs Bytes Owner ---- ---------- ----- ------------- Sys 0BA4-18C5h 53792 0008h < MS-DOS > Free 18C7-18CFh 144 0000h < MS-DOS > Env 18D1-18D2h 32 18D4h JYRKEYB Prog 18D4-1904h 784 18D4h JYRKEYB C:\MS-DOS\JYRKEYB.COM C Prog 1906-1A69h 5696 1906h COMMAND Env 1A6B-1A7Dh 304 1906h COMMAND 1A7F-1A82h 64 1906h COMMAND Free 1A84-1A93h 256 0000h < MS-DOS > Prog 1A95-1DD8h 13376 1A95h MOUSE Env 1DDA-1DEDh 320 1ED8h NS Prog 1DEF-1ED6h 3712 1DEFh SHELLB DOSSHELL Prog 1ED8-21EBh 12608 1ED8h NS f:\norton\NS.EXE Env 21ED-2200h 320 2202h NC Prog 2202-2527h 12896 2202h NC f:\norton\NC.EXESocha 2529-253Ch 320 253Eh COMMAND Prog 253E-26A1h 5696 253Eh COMMAND /a Env 26A3-26B5h 304 253Eh COMMAND Env 26B7-26CAh 320 26CCh MI Prog 26CC-9FFFh 485k 26CCh MI c:\dos\MI.COM /a Программа сообщает размер стандартной оперативной памяти (640 Кбайт), максимальный размер области памяти, доступной для запускаемой программы (485 Кбайт). Затем она выводит на экран список блоков памяти с указанием типа, сегментных адресов занимаемых параграфов памяти, размера в байтах и имени владельца блока памяти. Программа mi.com различает четыре типа блоков памяти:
Откуда программа mi.com берет информацию о типе блока памяти и имени программы? Системный блок распознается по занимаемым адресам, программный - по наличию правильного префикса программного сегмента (будет описан ниже). Блок переменных среды находится перед программным блоком и содержит кроме собственно переменных среды еще и полный путь к файлу запущенной программы. Если блок не системный, программный, или не является блоком среды и если в поле владельца этого блока записан нуль, программа отмечает такой блок памяти как свободный. Видно, что для каждой запущенной программы создается два блока памяти - блок среды и программный блок. Среда формируется при загрузке операционной системы с помощью команд SET и содержит строки вида: SET LIB=D:\C600\LIB Строки хранятся в формате ASCIIZ , т. е. закрыты двоичным нулем. Вся таблица переменных среды также закрыта двоичным нулем. После переменных среды в блоке памяти, отведенном для среды, содержится путь к файлу программы в виде строки ASCIIZ. Блок памяти типа Prog (программный) независимо от формата загрузочного модуля (загруженного из файла с расширением имени .com или .exe) начинается с префикса программного сегмента PSP , за которым следует сама программа. Таким образом, при загрузке для программы выделяются блоки памяти, располагающиеся в следующей последовательности:
Приведем фрагмент дампа оперативной памяти, полученные при отладке программы mi.com с помощью отладчика Microsoft CodeView. Дамп памяти начинается с адреса 6D47:0000. Первая строка дампа (смещение 000-00F) - это MCB блока памяти переменных среды. Это не последний блок памяти, поэтому MCB имеет тип M. В поле владельца блока памяти находятся нули, следовательно, MCB принадлежит сам себе. Поле длины содержит значение 0014 - это количество параграфов в блоке памяти переменных среды. Со смещением 010 начинается блок переменных среды. Из дампа видно, что строки определения переменных среды закрыты двоичным нулем. Таблица переменных среды также закрыта нулем (смещение 13B). Со смещением 13C записано слово 0001 (количество слов в последующей строке), после которого расположен полный путь к файлу запущенной программы. 000 4D00 0014 0000 0000 0000 0000 0000 0000 M............... 010 434F 4D53 5045 433D 433A 5C43 4F4D 4D41 COMSPEC=C:\COMMA 020 4E44 2E43 4F4D 0054 4D50 3D67 3A5C 7465 ND.COM.TMP=g:\te 030 6D70 0050 4154 483D 673A 5C3B 643A 5C71 mp.PATH=g:\;d:\q 040 6332 5C62 696E 3B65 3A5C 6336 3030 5C62 c2\bin;e:\c600\b 050 696E 623B 653A 5C63 3630 305C 6269 6E3B inb;e:\c600\bin; 060 633A 5C64 6F73 3B63 3A5C 6172 633B 663A c:\dos;c:\arc;f: 070 5C6E 6F72 746F 6E3B 653A 5C77 6F72 643B \norton;e:\word; 080 004C 4942 3D65 3A5C 7163 325C 4C49 4200 .LIB=e:\qc2\LIB. 090 494E 434C 5544 453D 673A 5C69 6E63 6C75 INCLUDE=g:\inclu 0A0 6465 3B65 3A5C 7163 325C 494E 434C 5544 de;e:\qc2\INCLUD 0B0 453B 653A 5C63 746F 6F6C 735C 696E 636C E;e:\ctools\incl 0C0 7564 653B 0048 454C 5046 494C 4553 3D65 ude;.HELPFILES=e 0D0 3A5C 4336 3030 5C48 454C 505C 2A2E 484C :\C600\HELP\*.HL 0E0 503B 0049 4E49 543D 653A 5C43 3630 305C P;.INIT=e:\C600\ 0F0 494E 4954 0044 4D41 4B45 3D67 3A5C 646D INIT.DMAKE=g:\dm 100 616B 653B 0056 4547 413D 653A 5C76 6567 ake;.VEGA=e:\veg 110 613B 004E 4152 4348 454C 503D 663A 5C61 a;.NARCHELP=f:\a 120 7263 5C6E 6172 633B 0048 454C 5050 4154 rc\narc;.HELPPAT 130 483D 643A 5C68 656C 703B 0000 0100 433A H=d:\help;....C: 140 5C44 4F53 5C6D 692E 636F 6D00 6D00 7016 \MS-DOS\mi.com.m.p. Далее начинается MCB программного блока памяти (смещение 150). Это последний блок памяти, поэтому MCB имеет тип Z. Непосредственно за MCB располагается префикс программного сегмента PSP (смещение 160). Размер PSP - 256 байт, его формат будет описан в третьей главе. И, наконец, со смещением 260 расположена сама программа mi.com. 150 5A00 00A3 3216 0000 6D69 0000 0000 0000 Z...2...mi...... 160 CD20 00A0 009A F0FE 1DF0 3D09 B22E 340A . ........=...4. 170 B22E 850E B22E CD26 FFFF FFFF FFFF FFFF .......&........ 180 FFFF FFFF FFFF FFFF FFFF FFFF 486D 92B3 ............Hm.. 190 FD4B 1400 1800 5D6D FFFF FFFF 0000 0000 .K....]m........ 1A0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 1B0 CD21 CB00 0000 0000 0000 0000 0020 2020 .!........... 1C0 2020 2020 2020 2020 0000 0000 0020 2020 ..... 1D0 2020 2020 2020 2020 0000 0000 0000 0000 ........ 1E0 0320 2F61 0038 0F00 2C09 0001 0000 4005 . /a.8..,.....@. 1F0 7808 0000 9000 0100 04B3 0D07 ED2F 14B3 x............/.. 200 7501 4A36 0000 0000 0000 4003 A308 3F00 u.J6......@...?. 210 FD4B FD4B 0100 2ABA 0000 0000 026F 5718 .K.K..*......oW. 220 3800 0500 3800 CF08 DD26 2D09 FD4B FD4B 8...8....&-..K.K 230 E408 0000 4200 A308 3F00 FD4B FD4B E408 ....B...?..K.K.. 240 1304 0000 5718 C000 0500 C000 CE02 CE03 ....W........... 250 5718 8400 0500 8400 CE02 CE03 973A 92B3 W............:.. 260 E9BB 000D 0A4D 656D 6F72 7920 496E 666F .....Memory Info 270 2076 352E 380D 0A43 6F70 7972 6967 6874 v5.8..Copyright 280 2031 3938 3920 4365 6E74 7261 6C20 506F 1989 Central Po 290 696E 7420 536F 6674 7761 7265 2C20 496E int Software, In 2A0 632E 2020 416C 6C20 7269 6768 7473 2072 c. All rights r 2B0 6573 6572 7665 642E 0D0A 0A00 4279 2047 eserved.....By G 2C0 5744 2030 312F 3036 2F38 391A 2D2D 2D2D WD 01/06/89.---- 2D0 5041 5443 4820 4152 4541 2D2D 2D2D 2D2D PATCH AREA------ 2E0 2D2D FF90 5601 4102 0000 0290 5D6D 5C6D --..V.A.....]m\m Программа MCBLISTС помощью программы MCBLIST (листинг 2.2) вы сможете просмотреть весь список блоков MCB . Для каждого блока программа выводит его адрес, тип, адрес владельца и размер. Все перечисленные выше параметры считываются непосредственно из блоков MCB. Листинг 2.2. Файл mcblist\mcblist.cpp #include <dos.h> #include <stdio.h> #include <conio.h> typedef struct { unsigned char type; unsigned owner; unsigned size; char reserve[11]; } MCB ; typedef MCB far* LPMCB; typedef struct { unsigned mcb_seg; void far *dev_cb; void far *file_tab; void far *clock_dr; void far *con_dr; unsigned max_btbl; void far *disk_buf; void far *drv_info; void far *fcb_tabl; unsigned fcb_size; unsigned char num_bdev; unsigned char lastdriv; } CVT ; typedef CVT far* LPCVT ; LPMCB get_nmcb(LPMCB); void main(void) { union REGS regs; struct SREGS sregs; LPCVT lpCVT; LPMCB lpMCB; // Получаем адрес векторной таблицы связи regs.h.ah = 0x52; intdosx (®s, ®s, &sregs); // Передвигаем указатель на поле msb_seg lpCVT = (LPCVT )MK_FP (sregs.es, regs.x.bx - 2); // Получаем указатель на первый блок MCB lpMCB = (LPMCB)MK_FP (lpCVT->mcb_seg, 0); printf("\nБлоки управления памятью MCB " "\n(C) Фролов А.В., 1995\n" "\nАдрес MCB Тип Владелец Размер" "\n--------- --- -------- ------" "\n"); for(;;) { // Если последний блок MCB , выходим // из цикла if(lpMCB == NULL) break; // Выводим информацию о блоке MCB printf("%Fp %c %04X %04X\n", lpMCB, lpMCB->type, lpMCB->owner, lpMCB->size); // Получаем адрес следующего блока MCB lpMCB=get_nmcb(lpMCB); } printf("\nНажмите любую клавишу..."); getch(); } // ------------------------------------------ // get_nmcb // Функция возвращает адрес следующего блока // MCB или NULL, если это последний блок // ------------------------------------------ LPMCB get_nmcb(LPMCB mcb) { unsigned seg, off; // Проверяем тип блока if(mcb->type == 'M') { // Вычисляем адрес следующего MCB seg = FP_SEG (mcb) + mcb->size + 1; off = FP_OFF (mcb); return((MCB far *) MK_FP (seg,off)); } else return((LPMCB)NULL); } |