На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 3 / Цепочки памяти MS-DOS Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Цепочки памяти MS-DOS

Управление памятью MS-DOS начинается при загрузке MS-DOS. Все блоки памяти MS-DOS либо свободны, либо распределены, начиная с блока управления памятью (MCB - memory control block). Эти блоки управления, показанные на Рис.3-3, идентифицируют тип и размер блока памяти и программу (или процесс), которая владеет им.


Два типа блоков управления памятью являются цепочками блоков, тип которого есть 4Dh, и конечный блок цепочки - тип 5Ah. Тип блока хранится в первом байте блока MCB.


Следующие два байта в блоке MCB являются словом, которое идентифицирует владельца блока памяти. Значение нуль указывает, что блок нераспределен или свободен. Если поле владельца ненулевое, то это значит, что блок распределен. Это слово содержит идентификатор владельца процесса (PID - process identifier). PID для процесса пользователя получается от адреса сегмента, взятого из сегмента программного префикса (PSP - program segment prefix) данного процесса.


Четвертый и пятый байты в MCB являются словом, которое содержит размер блока памяти, следующего за этим блоком. Этот размер выражается в параграфах (блоки по 16 байт) и не включает размер самого блока MCB. Оставшиеся 11 байтов MCB не определены.


Несмотря на то, что полный список блоков управления часто относят к цепочке распределения памяти, блоки MCB, на самом деле, не редактируются вместе, MCB только указывает на распределенный блок памяти. Вернее, каждый блок MCB непосредственно следует в памяти перед блоком, которым он управляет. Если MCB и соответствующий ему блок памяти не последние в цепочке, то за ними непосредственно следуют другой MCB и блок памяти.


Начиная от данного MCB, адрес сегмента следующего MCB в цепочке получается путем сложения размера (в параграфах) текущего блока с текущим адресом сегмента MCB, плюс 1. При этом способе может быть просмотрена вся цепочка MCB, но только в прямом направлении. Начиная от данного MCB, можно определить адрес предыдущего MCB. Как затем можно узнать, какие блоки находятся в памяти?


Функция MS-DOS с номером 52h (прерывание int 21h) является недокументируемой функцией, которая возвращает указатель на список внутренних значений MS-DOS. Указатель возвращается в паре ES:BX. Как раз перед этим списком в слове, указываемом значением ES:[BX - 2], находится адрес первого MCB. Из этой начальной точки может быть определена вся цепочка MCB.


Эти способы использованы в программе SHOWMEM (отобразить память), приведенной в листинге 3-1.



                      Адрес  Тип  Владелец  Размер
                      0А00:0.---------------------------------------.
                            | 4D |  0008  |  1600  |                |
                      0A01:0|---------------------------------------|
                            |                                       |
                            | Распределенный блок, владельцем кото- |
                            |         рого является MS-DOS          |
                      2001:0|---------------------------------------|
                            | 4D |  2013  |  0010  |                |
                      2002:0|---------------------------------------|
                            |                                       |
                            | Распределенный блок, владельцем кото- |
                            |       рого является процесс 2013      |
                      2012:0|---------------------------------------|
                            | 4D |  2013  |  0500  |                |
                      2013:0|---------------------------------------|
                            |                                       |
                            | Распределенный блок, владельцем кото- |
                            |       рого является процесс 2013      |
                      2513:0|---------------------------------------|
                            | 5A |  0000  |  7AEC  |                |
                      2514:0|---------------------------------------|
                            |                                       |
                            |  Cвободный блок (владелец - MS-DOS).  |
                            |Содержит остаток в верхней части памяти|
                            |                                       |
                      9FFF:F ---------------------------------------
                     Рис. 3-3. Блоки управления памятью MS-DOS

Листинг 3-1 содержит как исходный файл SHOWMEM.ASM, так и заголовок файла PCP.INC (который мы рассмотрим несколько подробней). Рис.3-4 изображает результаты работы программы SHOWMEM. Подпрограмма ShowMCBInfo в программе SHOWMEM.ASM отображает содержимое блока MCB. Процедура main содержит коды для размещения начального блока и, после метки show_mem, вычислительные операции для нахождения следующего блока в цепочке. Дополнительные коды в подпрограмме ShowMCBOwner могут совсем не иметь смысла. Эти коды используются для отображения имени процесса, который владеет блоком памяти, и поясняются в следующих разделах.


Рассмотрев Рис.3-4, можно усвоить несколько интересных моментов. В частности, можно увидеть, что автор программы загрузил в память три резидентные программы: RETRIEVE (восстановление), MODE (режим) и SWITCH (переключатель). На Рис.3-4 можно также увидеть, что программа SHOWMEM имеет очень большой выделенный для нее блок памяти - 555 Кбайт! Кроме того, можно также увидеть, что каждая загруженная программа имеет два распределенных для нее блока памяти. Вот это последнее обстоятельство мы первым и объясним.



         1   SM-ShowMem, Version 1.00  c  Copyright 1988

         2   MCB    Size   Owner  Command Line
             -----------------------------------------------------------
             0A01   08D7   0008   DOS
             12D9   00D3   12DA   [ SHELL ]
             13AD   0003   0000   [ available ]
             13B1   0032   12DA   [ SHELL ]
             13E4   0004   13EA   c:\bin\RETRIEVE.COM
             13E9   00A9   13EA   c:\bin\RETRIEVE.COM
             1493   000F   14A4   S:\MODE.COM\*
             14A3   0017   14A4   S:\MODE.COM\*
             14BB   0010   14CD   c:\ws2000\SWITCH.COM
             14CC   0018   14CD   c:\ws2000\SWITCH.COM
             14E5   0011   14F8   c:\GUIDE\EXAMPLES\SHOWMEM.EXE
             14F7   8B08   14F8   c:\GUIDE\EXAMPLES\SHOWMEM.EXE

             <<<------------- End of Memory Block List ------------->>> 3

             Рис. 3-4. Пример отображения результатов работы программы
                                     SHOWMEM:

1 - программа показа памяти - ShowMem, версия 1.00, авторское право 1988; 2 - блок управления памятью, размер, владелец, командная строка; 3 - конец списка блоков памяти.


         Листинг 3-1. SHOWMEM - программа отображения блоков памяти MS-DOS
         ----------------------------------------------------------------

                                  SHOWMEM.ASM
         PAGE    60,132
         ; **** SHOWMEM *************************************************
         ; ShowMem - Отображение блоков управления памятью, отредактиро-
         ;           ванных MS-DOS
         ; Этот файл создает программу SM.EXE
         ;
         ;***** ВКЛЮЧЕНИЯ ИЛИ ЭКВИВАЛЕНТЫ *******************************
         ;
         INCLUDE stdmac.inc
         INCLUDE psp.inc
         ;
         BlocMCB EQU 4Dh                     ; тип цепочечного MCB
         LastMCB EQU 5Ah                     ; тип последнего MCB
         FreeMCB EQU 0000h                   ; владелец свободного MCB
         ;
         NameSig EQU 0001h                   ; сигнатура имени процесса
         ;
         ; **** КОМПОНЕНТЫ СЕГМЕНТОВ DGROUP (ДАННЫЕ) ********************
         ;
         _DATA   SEGMENT BYTE PUBLIC 'DATA'
         _DATA   ENDS
         ;
         STACK   SEGMENT PARA STACK
                 dw      1024 dup (?)        ; стек 2 Кбайт
         STACK   ENDS
         ;
         DGROUP  GROUP   _DATA, STACK
         ;
         ;**** ПАМЯТЬ ДАННЫХ ИЛИ ШАБЛОНЫ ********************************
         ;
         _DATA   SEGMENT BYTE PUBLIC 'DATA'
         ;
         ; Текстовые сообщения для отображения формата в виде:
         ;
         ; "MCB     Size    Owner    Coommand Line"
         ; "------------------------------------------------------------"
         ; "xxxx    xxxx    xxxx     cccccccc..."
         ; "<<<--------------- End of Memory Block List ------------->>>"
         ;
         $Title  db  CR,LF
                 db  'SM-ShowMem, Version 1.00,  c  Copyright 1988'
                 db  CR,LF,CR,LF
                 db  'MCB    Size   Owner   Command Linr'
                 db  '--------------------------------------------'
                 db  '----------------'
                 db  CR,LF,'$'
         $Space  db  '   $'
         $Free   db  '[ available ]$'
         $DOS    db  'DOS$'
         $shell  db  '[ SHELL ]$'
         $MCBad  db  CR,LF
                 db  '********** Error in MCB Chains : Aborting List'
                 db  ' **********'
         $End    db  CR,LF
                 db  '<<< ************ End of Memory Block List'
                 db  ' ------------ >>>'
         $Crlf   db  CR,LF,'$'
         ;
         ; Шаблоны структур
         mcb     STRUC               ; структура блока управления памятью
                 TypeMCB  db     ?   ; тип блока
                 OwnerMCB dw     ?   ; владелец блока
                 SizeMCB  dw     ?   ; размер блока
         mcb     ENDS
         ;
         _DATA   ENDS
         ;
         ; **** Здесь начинается код программы **************************
         ;
         _TEXT   SEGMENT byte public 'code'
                 ASSUME  cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP
         ;
                 EXTRN   bin2hex:NEAR ; шестнадцатиричное отображение
         main    PROC    FAR
                 mov     ax,DGROUP    ; установка сегмента данных
                 mov     ds,ax
         ;
         ; Отображение заголовка для списка блоков памяти
                 @DisStr $Title
         ;
         ; Нахождение начала очереди блоков памяти
                 mov     ah,52h       ; получение параметров DOS
                 int     21h          ; возврат указателя в ES:BX
                 sub     bx,2         ; указывает на 1-й адрес MCB
                 mov     ax,word ptr es:[bx] ; получение начального блока
                 mov     es,ax
                 xor     di,di        ; очистка индекса
                 cmp     byte ptr es:[di].TypeMCB,BlocMCB
                 jne     bad_chain    ; выход, если не начало цепочки
         ;
         ; Цикл для нахождения и отображения каждого блока памяти
         show_mem:
                 call    ShowMCBInfo  ; дамп содержимого MCB
                 cmp     byte ptr es:[di].TypeMCB,LastMCB
                 je      done         ; выход, если конец цепочки
                 mov     ax,es        ; вычисление следующего адреса
                 add     ax,es:[di].SizeMCB ; добавление размера блока
                 inc     ax           ; плюс 1 для себя
                 mov     es,ax        ; начало нового блока
                 cmp     byte ptr es:[di].TypeMCB,LastMCB
                 je      show_mem     ; продолжение, если правильный тип
                 cmp     byte ptr es:[di].TypeMCB,BlocMCB
                 je      show_mem     ; продолжение, если правильный тип
         ;
         bad_chain:                   ; ошибка в MCB "chains"
                 @DisStr $MCBad       ; завершающее сообщение
                 @DisStr $Crlf
                 mov     al,1         ; завершение без ошибки
                 @ExitToDOS           ; завершение программы
         ;
         done:   @DisStr $End         ; завершающее сообщение
                 @DisStr $Crlf
                 mov     al,0         ; нормальное завершение
                 @ExitToDOS           ; завершение программы
         ;
         main    ENDP
         ;
         ; **** ShowMCBInfo *********************************************
         ; ShowMCBInfo отображает блоки, адресуемые с помощью ES:DI как
         ; блоки управления памятью MS-DOS. Формат отображения показан
         ; выше.
         ;
         ShowMCBInfo PROC    NEAR
                 mov     ch,04        ; отображение числовых данных
                 mov     ax,es        ; адрес MCB
                 call    bin2hex
                 @DisStr $Space
                 mov     ax,es:[DI].SizeMCB ; связанный блок
                 call    bin2hex
                 @DisStr $Space
                 mov     ax,es:[DI].OwnerMCB ; владелец
                 push    ax           ; сохранение владельца
                 call    bin2hex
                 @DisStr $Space
                 pop     ax
                 cmp     ax,FreeMCB   ; блок освобожден?
                 je      is_free      ; да, выполнять имя не надо
                 call    ShowMCBOwner ; нет, отображение владельца
                 jmp     Info_Exit
         ;
         is_free:
                 @DisStr $Free        ; отметить блок как свободный
         Info_exit:
                 @DisStr $Crlf
                 ret
         ShowMCBInfo ENDP
         ;
         ; **** ShowMCBOwner ********************************************
         ; ShowMCBOwner извлекает и отображает владельца MCB DOS из
         ; соответствующей строки среды. ES:DI указывает на допустимый
         ; MCB с ненулевым полем владельца.
         ;
         ShowMCBOwner PROC   NEAR
                 push    es           ; сохранение адреса MCB
                 push    di           ; сохранение для приборки
         ;
         ; Получение PID (адреса PSP), который владеет этим блоком памяти
                 mov     ax,es:[di].OwnerMCB ; адрес PSP владельца
                 mov     es,ax
               cmp     es:[di].PSPExitInt,PSPSignature ; допустимый PSP?
                 je      Owner_PID    ; да, владелец имеет PID
         ;
         ; Без PSP владелец должен быть ядром DOS
         Owner_DOS:
                 @DisStr $DOS         ; владелец MS-DOS
                 jmp     Owner_Exit   ; все выполнено
         ;
         ; Извлечение сегмента среды процесса из PSP
         Owner_PID:
                 mov     ax,es:[di].PSPEnvironment ; да, получ. адр.среды
                 push    ax           ; сохранение сегмента среды
         ;
         ; Получение размера сегмента среды
                 dec     ax           ; MCB среды
                 mov     es,ax
                 mov     cx,es:[di].SizeMCB ; получение размера среды
                 shl     cx,1               ; преобразование параграфов
                 shl     cx,1               ; в байты
                 shl     cx,1
                 shl     cx,1
         ;
         ; Продолжение поиска имени процесса по ES:DI, длине CX
         ; Каждая переменная среды завершается нулевым байтом.
         ; Список переменных завершается другим нулевым байтом
                 cld                  ; поиск вперед
                 pop     es           ; восстановление среды
                 xor     al,al        ; поиск значения
         search:
                 repne   scasb        ; поиск для ASCIIZ
                 jne     Owner_DOS    ; останов, если выход за границу
                 scasb                ; конец списка строк
                 jne     search       ; продолжить, если больше
         ;
         ; Проверка наличия "Сигнатуры", продолжающей (возможные) имена
                 mov     si,di        ; передача в SI
                 push    ds           ; сохранение сегмента строк
                 push    es           ; передача ES в DS
                 pop     ds
                 lodsw                ; чтение предшествующего слова
                 cmp     al,NameSig   ; проверка действительного имени
                 je      show_name    ; имя допустимое
         ;
         ; Без действительного имени владелец должен иметь имя SHELL
                 pop     ds
                 @DisStr $Shell       ; владелец имеет имя shell
                 jmp     Owner_Exit
         ; ES:DI указывает на допустимое (0 завершенное) имя процесса
         show_name:
                 lodsb                ; чтение символа,
                 cmp     al,0         ; одновременно проверка
                 je      Owner_POP    ; окончания, и
                 @DisStr al           ; отображение
                 loop    show_name
         Owner_Pop:
                 pop     ds
         Owner_Exit:
                 pop     di
                 pop     es
                 ret
         ShowMCBOwner ENDP
         ; ***** КОНЕЦ ПРОГРАММЫ : КОНЕЦ ФАЙЛА **************************
         ;
         _TEXT   ENDS
                 END     main
                                      ; PSP.INC
         ;***************************************************************
         ; ФАЙЛ ВКЛЮЧЕНИЯ ОПИСАНИЙ PSP
         ;***************************************************************
         ;
         PSPSignature   EQU   020cdh  ; слово, начинающее все PSP
         ;
         ProgramSegmentPrefix STRUC
         PSPExitInt     dw    ?       ; прерывание выход int 20h
         PSPMemTot      dw    ?       ; вершина памяти
         PSPResvr1      db    ?
         PSODOSCall     db    5 dup (?) ; вызов MS-DOS
         PSPTerminate   db    ?       ; адрес завершения
         PSPControlC    dd    ?       ; адрес control-C
         PSPCritical    dd    ?       ; адрес критической ошибки
         PSPParent      dw    ?       ; владелец PSP
         PSPHandleTable db   20 dup (?);таблица описателей по умолчанию
         PSPEnvironment dw    ?       ; адрес среды
         PSPStack       dd    ?       ; начальные значения стека
         PSPHandleSize  dw    ?       ; размер таблицы описателей
         PSPHandlePntr  dd    ?       ; адрес таблицы описателей
         PSPResvr2      db   24 dup (?)
         PSPDOSInt      db    3 dup (?) ; прерывание 21h или возврат
         PSPResvr3      db    9 dup (?)
         PSPFCB1        db   16 dup (?) ; блок управления файлом
         PSPFCB2        db   16 dup (?) ; блок управления файлом
         PSPResvr4      db    4 dup (?)
         PSPCommandLen  db    1       ; длина командной строки
         PSPCommandBuf  db  127 dup (?) ; текст командной строки
         ProgramSegmentPrefix ENDS
         ________________________________________________________________

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz