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

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

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

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

2.4. Блоки управления памятью в MS-DOS

Вся оперативная память в MS-DOS разделена на фрагменты, перед которыми распложены блоки MCB . Как мы уже говорили в первой главе, эти блоки описывают фрагменты памяти.

Поле векторной таблицы связи mcb_seg содержит сегментный адрес первого блока управления памятью MCB . Блок MCB всегда начинается на границе параграфа, поэтому полный адрес первого блока будет равен mcb_seg:0.

В этом разделе мы научим вас просматривать цепочку блоков MCB и определять тип соответствующих этим блокам фрагментов памяти.

Распределение памяти в MS-DOS

Для лучшего понимания механизма управления памятью вспомним распределение памяти в MS-DOS:

Диапазон адресов Содержимое
0000:0000 Векторы прерываний
0000:0400 Область данных BIOS
0000:0500 Область данных MS-DOS
xxxx:0000 Область программ MS-DOS.В ней находится расширение BIOS , обработчики прерываний MS-DOS, буферы, внутренние структуры данных MS-DOS, загружаемые драйверы устройств
xxxx:0000 Резидентная порция командного процессора command.com
xxxx:0000 Резидентные программы
xxxx:0000 Запущенные прикладные программы типа COM или exe
xxxx:0000 Транзитная порция command.com
A000:0000 Память EGA , используемая в некоторых видеорежимах
B000:0000 Память монохромного видеоконтроллера
B800:0000 Память видеоконтроллера CGA
C800:0000 Внешнее ПЗУ
F600:0000 ПЗУ интерпретатора BASIC
FE00:0000 ПЗУ BIOS

Первый килобайт памяти занимает таблица векторов прерываний . Она содержит 256 элементов, имеющих размер 4 байта. Это дальние адреса обработчиков прерываний, состоящие из компонент сегмента и смещения. Подробно формат и использование этой таблицы будет обсуждаться в главе, посвященной прерываниям .

Адреса 0000:0400 - 0000:04FF (или от 0040:0000 до 0050:0000) занимает область данных BIOS . Это так называемые внутренние переменные BIOS . К ним можно обращаться для получения различной информации. При этом необходимо только помнить, что формат этой области может быть различным для различных версий BIOS.

Начиная с адреса 0000:0500 (или с адреса 0050:0000, что одно и то же) следует область данных MS-DOS. Здесь MS-DOS хранит свои внутренние таблицы, переменные и структуры данных. Формат этой области (и ее размер) зависит от версии операционной системы.

Далее следует большая область памяти, используемая MS-DOS. Здесь находятся:

  • система ввода-вывода MS-DOS (содержимое файла io.sys );
  • обработчики прерываний MS-DOS, в частности, обработчик прерывания INT 21h (эти обработчики входят в состав файла msdos.sys );
  • внутренние буферы MS-DOS и внутренние структуры данных;
  • загружаемые драйверы (перечисленные в файле config.sys ).

После драйверов располагается резидентная порция командного процессора 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 :

Смещение, байт Размер, байт Имя поля Описание
0 1 type Тип блока MCB (M или Z)
1 2 owner Сегментная компонента адреса владельца блока; этот блок всегда выровнен на границу параграфа (если 0, то блок описывает сам себя)
3 2 size Число параграфов в этом блоке
5 11 reserve Зарезервировано

Напомним, что параграф имеет размер 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 различает четыре типа блоков памяти:

  • системный (Sys), его владельцем является MS-DOS;
  • свободный (Free), обычно тоже принадлежит MS-DOS;
  • программный (Prog) - его занимает запущенная программа;
  • среда (Env) - содержит переменные среды MS-DOS.

Откуда программа mi.com берет информацию о типе блока памяти и имени программы? Системный блок распознается по занимаемым адресам, программный - по наличию правильного префикса программного сегмента (будет описан ниже).

Блок переменных среды находится перед программным блоком и содержит кроме собственно переменных среды еще и полный путь к файлу запущенной программы. Если блок не системный, программный, или не является блоком среды и если в поле владельца этого блока записан нуль, программа отмечает такой блок памяти как свободный.

Видно, что для каждой запущенной программы создается два блока памяти - блок среды и программный блок. Среда формируется при загрузке операционной системы с помощью команд SET и содержит строки вида:

SET LIB=D:\C600\LIB

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

Блок памяти типа Prog (программный) независимо от формата загрузочного модуля (загруженного из файла с расширением имени .com или .exe) начинается с префикса программного сегмента PSP , за которым следует сама программа.

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

  • MCB для блока памяти переменных среды;
  • блок памяти переменных среды;
  • MCB программного блока памяти;
  • префикс программного сегмента 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 (&regs, &regs, &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);
}

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