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










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

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

Введение в управление памятью в MS-DOS

Пример, приведенный в листинге 2-11, зависит от имеющейся свободной памяти внутри системы. По умолчанию MS-DOS вырабатывает распределение всей памяти для себя при загрузке. Вызов распределения памяти будет неудачным, т.к. процесс уже имеет всю память, даже если он не знает про это. Если программа желает использовать функцию распределения памяти, то некоторая память, полученная во время загрузки, должна быть возвращена в систему. Обычно процесс будет стремиться вернуть всю память , которую он не занял программным кодом или буферами.


Функция, обеспечиваемая MS-DOS для обработки возврата части распределенной памяти программы в систему, является функцией 4Ah - "Модификация блока распределенной памяти". Она позволяет процессу "вырезать" память из его блока распределения памяти, принятого по умолчанию.


Заметим, что имеются способы предотвращения процесса от распределения всей памяти при загрузке, но их рассмотрение отложим до главы 3, где тема загрузки программ и программных файлов MS-DOS будет обсуждаться более подробно.


Параметры, требующиеся для функции "Модифицировать блок распределения памяти", это адрес сегмента блока, который необходимо модифицировать, и новый размер блока. Адрес сегмента блока, который содержит программу (размер которой нужно модифицировать), передается через PSP (Program Segment Prefix - сегмент программного префикса). PSP является разделом памяти, которым начинается каждая программа MS-DOS. Подробно содержимое PSP описывается в главе 3. Сейчас же для нас важно только то, что адрес сегмента PSP является адресом сегмента блока, который необходимо модифицировать, и нам необходим этот адрес.


Что касается определения этого параметра, то оно различно для файлов типа .COM и файлов типа .EXE. Рис. 2-3 показывает расположение памяти для файлов типа .COM и типа .EXE. PSP является первым элементом для каждого типа файлов. В программе типа .COM PSP содержится в первых 256 байтах программного сегмента и адрес программного сегмента (во всех регистрах сегмента) является адресом сегмента PSP.


Для файлов типа .EXE PSP располагается в его собственном сегменте. Однако, всякий раз при загрузке программы типа .EXE и получении управления от MS-DOS, оба регистра DS и ES содержат адрес сегмента PSP. Таким образом, для программы любого типа адрес PSP можно будет получить, по крайней мере, из регистра DS или регистра ES. Кроме того, пользователи MS-DOS версии 3.0 (или выше) могут использовать программу получения адреса сегмента программного префикса (PSP) - функцию 62h. MS-DOS возвращает значение адреса сегмента программного префикса в регистре BX.


Т.к. функция "Модифицировать блок распределенной памяти" предполагает адрес блока в регистре ES, то функция может быть вызвана непосредственно при выполнении запуска программы, поскольку регистр ES уже имеет адрес PSP.



                |\/\/\/\/\/|                         |\/\/\/\/\/|
                |  Память  |                         |  Память  |
                |файла типа|                         |файла типа|
                |   .COM   |                         |   .EXE   |
           0000 |----------|           PSP           |----------|
                |    PSP   |<----------------------->|    PSP   |
           0100 |----------|                         |----------|
                |   Коды   |                         | Сегмент A|
                |    или   |                         |----------|
                |  данные  |                         | Сегмент B|
                |----------|     Конец программы     |----------|
                |   Стек   |<----------------------->| Сегмент C|
           FFFE |----------|                         |----------|
            или | Неисполь-|                         | Неисполь-|
          более |  зуемая  |                         |  зуемая  |
         высокая|  память  |   более высокая память  |  память  |
          память ---------- <-----------------------> ----------

                  Рис.2-3. План памяти программы MS-DOS и сегмента
                           программного префикса

После того, как найден адрес блока памяти, необходимо определить общее количество памяти, необходимое для сохранения. Различия между программами .COM и программами .EXE здесь становятся уже более заметными. Для программы типа .EXE размер должен быть определен путем вычитания адреса начала сегмента PSP из адреса сегмента фиктивного сегмента, расположенного в конце программы, как показано в листинге 2-12. Почему используются адреса сегментов? Функция 4Ah ожидает размер в параграфах, а адрес сегмента обычно является адресом параграфа.



          Листинг 2-12. Функция 4Ah - "Модифицировать блок распределенной
                  памяти" - изменение размера программы типа .EXE
         -----------------------------------------------------------------

         resize PROC NEAR
                mov     ax,es           ; получение адреса PSP
                mov     bx,SEG end_addr ; получение адреса сл. сегмента
                sub     bx,ax           ; разность - размер программы
                mov     ah,04Ah         ; модификация распредел-й памяти
                int     21h             ; вызов MS-DOS
                jnc     short resize_ok ; нет переноса => хорошо
                mov     ax,04C00h       ; перенос => сбой--авар. заверш.
                int     21h
         resize_ok:
                ret
         resize ENDP
         ;
         ; Оставшаяся  часть программного кода в этой программе END_ADDR
         ; является последним  элементом  перед  предложением  END.  Это
         ; сделано для того,  чтобы предложение END_ADDR связалось бы как
         ; последний сегмент, если используется более одного исходного
         ; файла.
         ;
          end_addr  SEGMENT
          end_addr  ENDS
                  END
         -----------------------------------------------------------------

Для программы типа .COM требуется меньше хлопот. В отличие от программы типа .EXE, которая имеет определенный размер, установленный компоновщиком LINK, программы типа .COM могут изменять свой размер. Размещение стека в программе типа .COM, которое устанавливается MS-DOS, может изменяться от конца сегмента (FFFEh) на 256 байтов больше программы (минимальный размер, требуемый MSDOS для стека). Пользователь может выбирать первое, принимая, что MS-DOS обеспечила и изменила размер стека (установленный размер 64 кбайт (1000h) параграфов) или все, что осталось; или второе, пересылая стек и изменяя размер, основываясь на этом. Второй выбор освобождает больше памяти и, таким образом, является более предпочтительным и рекомендуемым фирмами "Майкрософт" и "ИБМ". Листинг 2-13 содержит пример программы .COM, который устанавливает свой собственный стек и изменяет размер своего начального блока распределения на более умеренный размер.



          Листинг 2-13. Функция 4Ah - "Модифицировать блок распределенной
                  памяти" - изменение размера программы типа .COM
         -----------------------------------------------------------------

         code_seg  SEGMENT
                   ASSUME  cs:code_seg
                   ORG     0000h
         seg_org   EQU     $
                   ORG     0100h
         main      PROC    FAR
         start:
                   mov     sp,offset stack
                   call    resize
         ;
         ; здесь может выполняться оставшаяся часть программы
         ;
         main      ENDP
         resize    PROC    NEAR
                   mov     bx,(offset last_byte - seg_org + 15) shr 4
                   mov     ah,04Ah        ; модификация распр-й памяти
                   int     21h            ; вызов MS-DOS
                   jnc     short resize_ok ; нет переноса => хорошо
                   mov     ax,04C00h      ; перенос => сбой--ав.заверш.
                   int     21h
         resize_ok:
                   ret
         resize    ENDP
                   db      32 DUP ('stack   ')
         stack:
         last_byte EQU     $
         code_seg  ENDS
                   END     start
         -----------------------------------------------------------------

Интересной частью этой программы является способ определения размера результирующей программы. Для преобразования количества байтов программы в количество параграфов по-существу посредством деления на 16, используется оператор SHR макроассемблера MASM. Что не является таким очевидным так это то, почему seg_org вычитается из смещения last_byte. Оператор SHR не выполняется, когда применяется для смещения, и он вырабатывает сообщение об ошибке "Constant was expected" (ожидалась константа). Однако, разность между двумя смещениями считается постоянной, делая выражение приемлемым для макроассемблера MASM. Заметим, что seg_org должна иметь нулевое смещение так, чтобы размер был относительно начала сегмента. Если бы использовалась метка start, то были бы потеряны последние 100 (шестнадцатиричное значение) байт программы. (Заметим, что last_byte: для вычислений работает также хорошо, как и last_byte equ $).


Кроме того, для успешного использования освобождения памяти прием вычитания двух смещений (либо метки, либо количества) для получения константы, может быть успешно использован для всех типов операций, где размер требуется в выражениях, использующих константы. Рассмотрение этого применения для задач выравнивания буферы данных на границу параграфа будет приведено в главе 6.


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

Hosted by uCoz