1.3.1 Манипуляции с памятью.

Error message

Notice: Undefined index: add term path in hansel_get_breadcrumbs() (line 524 of /data/sites/msdosworld.ru/www/sites/all/modules/hansel/hansel.module).

  Когда MS DOS загружает  программу, то она помещается в младшую
область  памяти, сразу же за COMMAND.COM и установленными драйве-
рами устройств или другими утилитами,  которые резидентны в памя-
ти.  В этот момент времени вся память за программой отведена этой
программе. Если программе нужна  память для создания области дан-
ных, то она может приближенно вычислить где в памяти кончается ее
код и затем поместить требуемую  область  данных в любое место за
концом  кода.  Для определения адреса конца программы поместите в
конце программы псевдосегмент типа:

   ZSEG    SEGMENT
           ;
   ZSEG    ENDS

   В ассемблере IBM PC ZSEG  будет  последним  сегментом, так как
сегменты располагаются в алфавитном порядке.  С другими ассембле-
рами нужно действительно  поместить эти строки в конце программы.
В самой программе достаточно  поставить оператор MOV AX,ZSEG и AX
будет указывать на первый свободный сегмент памяти за программой.
   Такой  подход  будет  работать до тех пор, пока  программа  не
будет предполагать о наличии  памяти,  которой на самом деле нет.
Он  не будет также работать в многопользовательской среде,  когда
несколько программ могут делить  между собой одну и ту же область
адресов.  Для решения этой проблемы MS DOS имеет возможность отс-
леживать 640K системной памяти и отводить по требованию программы
блоки памяти любого размера. Блок памяти - это просто непрерывная
область памяти,  его  максимальный  размер  определяется размером
доступной  памяти, в частности, он может быть больше одного  сег-
мента (64K). Если затребован  слишком большой блок, то DOS выдает
сообщение об ошибке. Любая возможность перекрытия блоков исключе-
на. Кроме того MS DOS  может  освобождать,  урезать или расширять
существующие  блоки.  Хотя программа не обязана использовать  эти
средства, но удобно  и  предусмотрительно  делать  это. Некоторые
функции DOS требуют, чтобы были использованы средства  управления
памятью DOS, например,  завершение  резидентной программы [1.3.4]
или вызов другой программы из данной [1.3.2].
   Прежде  чем отвести память, существующий блок (вся  память  от
начала программы до конца)  должен  быть обрезан до размера прог-
раммы.  Затем, при создании блока, DOS создает 16-байтный  управ-
ляющий блок  памяти,  который  расположен  непосредственно  перед
блоком памяти. Первые 5 байтов этого блока имеют следующее значе-
ние:

   байт 0     ASCII 90 - если последний блок в цепочке, иначе
              ASCII 77.
   байты 1-2  0 если блок освобожден
   байты 3-4  размер блока в 16-байтных параграфах

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


и т.д., как показано на рис.  1-4. Как только Вы начали использо-
вать  систему  распределения памяти DOS, то Вы обязаны  придержи-
ваться ее.  Если программа изменит содержимое управляющего блока,
то  цепочка  будет разорвана и DOS начнет выдавать  сообщения  об
ошибке.
   MS DOS обеспечивает три  функции  распределения памяти, номера
от 48H до 4AH прерывания 21H.  Функция 48H отводит блок памяти, а
49H - освобождает блок памяти.   Третья  функция ("SETBLOCK") ме-
няет  размер памяти, отведенной для программы; эта функция должна
быть использована перед  двумя  остальными.  После  ее выполнения
можно  спокойно отводить и освобождать блоки  памяти.   Программа
должна  освободить  все  отведенные  ею  блоки перед завершением.
Иначе  эта память будет недоступной для последующего  использова-
ния.

   Средний уровень.

   Все три функции распределения памяти прерывания 21H используют
16-битный  адрес  начала блока памяти, с которым  они  оперируют.
Этот адрес  соответствует  сегменту,  с  которого начинается блок
(блок  всегда начинается со смещения 0 данного сегмента).   Таким
образом реальный адрес  ячейки  начала  блока равен этому адресу,
умноженному  на  16.  Также, для всех трех функций,  BX  содержит
число 16-байтных  разделов  памяти  (параграфов),  которые  будут
отводиться или освобождаться. Если функция не может быть выполне-
на, то устанавливается  флаг  переноса,  а  в AX возвращается код
ошибки, объясняющий причину. Возможны три кода ошибки:

   7   разрушен управляющий блок памяти
   8   недостаточно памяти для выполнения функции
   9   неверный адрес блока памяти

Функция отведения блока использует коды 7 и 8, а освобождения - 7
и 9, в то время как  функция  изменения  блока использует все три
кода.  В следующем примере сначала отводится блок, размером  1024
байта. При этом BX содержит  требуемое  число 16-байтных парагра-
фов,  а  при завершении стартовый адрес блока  равен  AX:0  (т.е.
смещение 0 в сегменте со  значением,  содержащимся в AX).  Вторая
часть  примера освобождает этот же блок, как и требуется при  за-
вершении программы.  В  данном  случае  значение  полученное в AX
помещается в ES. DOS следит за размером блока и знает какое коли-
чество параграфов надо освободить.

;---отведение блока размером 1024 байта
   MOV   AH,48H      ;номер функции
   MOV   BX,64       ;требуем 64 параграфа
   INT   21H         ;пытаемся отвести блок
   JC    ERROR       ;обрабатываем ошибку в случае неудачи
   MOV   BLOCK_SEG,AX;иначе сохраняем адрес блока
    .
;---освобождаем тот же блок
   MOV   AX,BLOCK_SEG ;получаем стартовый адрес блока
   MOV   ES,AX        ;помещаем его в ES
   MOV   AH,49H       ;номер требуемой функции
   INT   21H          ;освобождаем блок памяти


   Наконец, приведем пример использования функции 4AH.  ES содер-
жит  значение сегмента PSP, т.е.  самого первого байта памяти,  с
которого загружена программа.  Это  значение присваивается ES при
старте задачи.  Для использования SETBLOCK надо либо вызывать эту
функцию в самом начале  программы  (прежде чем ES будет изменен),
либо сохранить его начальное значение для последующего  использо-
вания.
   BX содержит требуемый  размер  блока  в 16-байтных параграфах.
Для определения этого размера поместите добавочный "искуственный"
сегмент в конец программы.  В  макроасссемблере  IBM  PC сегменты
располагаются  в алфавитном порядке, поэтому Вы можете  поместить
его в любое место программы, при условии,  что его имя это что-то
вроде  "ZSEG".  В других ассемблерах действительно помещайте фик-
тивный сегмент в конец программы. Программа может прочитать пози-
цию этого сегмента и, сравнивая ее со стартовым сегментом,  полу-
чить количество памяти, требуемое самой программе.  В момент заг-
рузки программы и ES и DS содержат номер параграфа самого  начала
программы в  префиксе  программного  сегмента;  для COM файлов CS
также указывает на эту позицию, но для EXE файлов это не так.
;---освобождение памяти (ES имеет значение при старте)
   MOV   BX,ZSEG      ;получаем # параграфа конца программы + 1
   MOV   AX,ES        ;получаем # параграфа начала программы
   SUB   BX,AX        ;вычисляем размер программы в параграфах
   MOV   AH,4AH       ;номер функции
   INT   21H          ;освобождаем память
   JC    MEMORY_ERROR ;проверяем на ошибку

;---
   ZSEG      SEGMENT
   ZSEG      ENDS


 

Вы находитесь в разделе: 

Добавить коментарий