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










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

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

Назначение и использование локального ЗУ в памяти

Имеется три способа распределения памяти для переменных. Будем рассматривать локальное ЗУ (локальную память) в оперативной памяти и локальную память в стеке. Сейчас рассмотрим локальное ЗУ в распределяемой памяти. Распределяемая память должна получаться из неиспользуемой памяти системы (часто называемой пулом памяти). MS-DOS поддерживает функции, которые могут быть использованы для распределения, перераспределения и установки размера блоков системной памяти. После распределения памяти программист может реализовать свою личную (персональную) схему управления памяти для управления памятью в узком участке. Однако сейчас сконцентрируем свое внимание на возможностях MS-DOS, начиная с функции 48h - "распределить память".


После получения блока памяти, программа должна иметь возможность его адресации. Память, распределяемая MS-DOS, предоставляется в "кусках" по 16 байтов, называемых "paragraph" (параграфом). MS-DOS возвращает указатель на эту память, которая содержит 16-битовый адрес памяти блока. Сегменты адресуются как параграфы, при этом указатель должен быть загружен в один из регистров сегмента (но не в регистр CS!). Обычно для повторного доступа к блоку памяти используется либо сегмент данных, либо внешний сегмент. Если подпрограмма, которая распределяла память, не является главной подпрограммой программы, то старое значение регистра сегмента должно сохраняться и восстанавливаться перед выходом из подпрограммы. Кроме того, перед выходом из подпрограммы распределенная память должна быть возвращена в систему. Для возврата распределенной памяти блока в систему используется функция 49h MS-DOS - "освободить распределенную память". В листинге 2-11 показано, как подпрограмма исполняемой программы .EXE будет распределять, использовать и освобождать память, используемую как локальную память (локальное ЗУ).



          Листинг 2-11. Распределение локальной памяти посредством MS-DOS
         -----------------------------------------------------------------

                     common   SEGMENT ; общие данные, используемые всеми
                     com_1   dw     ?
                     com_2   db     14 DUP (?)
                     common    ENDS
                     dummy_dat  STRUC      ; описание структуры,
                     dummy_1 dw     ?      ; используемой с
                     dummy_2 db     14 DUP (?) ; распределенной памятью
                     dummy_dat ENDS
                             ASSUME ds:common ; доступ к данным COMMON
                     local_example  PROC    NEAR ; процедура example
                     push    ds        ; сохранение предыдущего DS
         B8 ---- R   mov     ax,common ; COMMON настраиваемая MS-DOS
                     mov     ds,ax
                     push    es        ; сохранение предыдущего ES
                     mov     ah,048h   ; распределение памяти
                     mov     bx,1      ; запрос 1 блока (16 байт)
                     int     21h       ; вызов MS-DOS
                     jc      not_alloc ; перенос означает сбой распред-я
                     mov     es,ax     ; если распределена, то ее адрес
         ;
         ;                 три примера адресации
         ;
         A1 0000 R   mov     ax,com_1 ; надлежащий сег.-предполагается DS
         B8 0000     mov     ax,dummy_1 ; ошибочный сег.-непосредственный
         26: A1 0000 mov     ax,es:dummy_1 ; надлежащий сег.-замещаемый
                     ;
                     mov     ah,049h   ; освобождение распредел. памяти
                     int     21h       ; вызов MS-DOS
                     jnc     free_ok   ; нет переноса т.е. хорошо
                     not_alloc:
                     ; Сообщение об ошибке, если сбой, распр-я или удал-я
                     free_ok
                     pop     es        ; восстановление ES
                     pop     ds        ; восстановление DS
                     ret
                     local_example   ENDP  ; конец примера
         -----------------------------------------------------------------

Листинг 2-11 содержит оба вызова функций MS-DOS "Распределить память" и "Освободить память". Вместо регистра DS для указания на только что распределенную память, был использован регистр ES, а регистр DS зарезервирован для доступа к области общих переменных программы. Заметим, что в отличие от примера стека, для выполнения доступа к используемой структуре, определенной здесь, требуется оператор замещения сегмента (:). Без замещения сегмента инструкция mov ax,dummy_1 не выполняет генерацию ссылки на память, используя регистр ES, но взамен этого генерирует загрузку смещения (в нашем случае нуль) в регистр AX. При добавлении замещения сегмента к инструкции mov ax,es:dummy_1 макроассемблер MASM генерирует передачу памяти из смещения dummy_1 во внешний сегмент. Замещение сегмента в листинге 2-11 показано с байтом префикса 26:.


При использовании в программе нескольких сегментов данных программист несет ответственность за управление используемыми областями данных. Например, если программа X распределяет локальную память и обновляет регистр DS для доступа к этой области, то программист должен помнить о том, что эта область данных по умолчанию принимается областью данных для всех программ, вызываемых программой X. Общая область данных, которая была определена в программе, доступна еще путем загрузки либо регистра DS, либо регистра ES из переменной сегмента, как показано в листинге 2-6. Программы, изменяющие содержимое своих регистров сегмента, должны сохранять и восстанавливать первоначальные значения регистров сегмента для предотвращения своих порождаемых задач от ошибок.


Всякий раз, когда в программе используется более одного сегмента данных или внешних сегментов, программист должен быть очень внимателен к директивам ASSUME (присвоить), используемым в программе. При ассемблировании обычных ссылок на память макроассемблер MASM сначала ищет их таблицу внешних символов для имен переменных, к которым осуществляется доступ. Если MASM найдет переменную в таблице символов, он пытается создать ссылку, используя сегмент, в котором определена эта переменная. Если этот сегмент отсутствует (т.е. отсутствует соответствующее предложение ASSUME), то MASM генерирует сообщение об ошибке "Can't reach with segment reg" (нельзя найти регистр сегмента).


Если MASM не может найти переменную в таблице символов, то он предполагает, что она находится в сегменте данных. Если и это предположение окажется неудачным, то MASM пытается исправить ошибку во время второй передачи путем присоединения к инструкции префикса замещения сегмента. При неудаче, получение этого байта вызывает другое сообщение об ошибке "Phase error between passes" (ошибка фазы между передачами).


В случае неудачи или ссылки "вперед", т.е. когда имя переменной еще не находится в таблице символов, программист должен использовать оператор замещения сегмента (:) для более чистого определения макроассемблером MASM используемого сегмента. Для управления доступом в программе также полезен оператор SEG. Этот оператор позволяет программисту получать значение сегмента (базовый адрес сегмента) для любой определенной переменной. Ссылки, создаваемые с помощью предложения SEG, настраиваются MS-DOS и полезны для создания настраиваемых ссылок вместо абсолютных ссылок.


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

Hosted by uCoz