Динамическое управление памятью
Перед началом выполнения задачи DOS выделяет для нее всю свободную часть пространства обычной памяти. Задача может произвольно распоряжаться выделенным пространством ОЗУ, но она не должна выходить за его пределы, т. к. это приведет к непредсказуемым результатам. В данном разделе будет описан один из способов работы задачи с обычной памятью.
Блок задачи
Пространство, выделенное DOS для выполнения задачи, в технической документации принято называть блоком задачи. Он состоит из трех основных частей. Первые юоь (256) байтов блока занимает специальная структура данных – префикс программного сегмента (PSP). В нем хранятся величины, которые могут быть нужны при выполнении задачи. Сразу после PSP в памяти расположены сегменты, описанные в исходном тексте программы.
Как уже говорилось, порядок расположения сегментов в блоке задачи зависит от их имен и от наличия директив .Alpha, .seq или Dosseg, которые могут указываться в начале исходного текста программы. После последнего сегмента в блоке задачи находится свободное пространство, которым задача может распоряжаться по своему усмотрению (по усмотрению программиста). Но для доступа к этому пространству надо знать его размер и адрес начала, точнее, сегмент, с которого оно начинается. При составлении программы эти величины неизвестны, поскольку их формирует DOS, исходя из реально имеющихся ресурсов на момент загрузки задачи для выполнения.
Адрес свободного пространства
Для определения адреса свободного пространства надо знать, где заканчивается последний сегмент задачи. Для этого, в свою очередь, необходимо выяснить, какой из сегментов, описанных в исходном тексте программы, окажется последним в теле задачи.
Иногда рекомендуют включать в исходный текст задачи пустой сегмент, имя которого начинается на букву z, например:
Zero Segment; начало сегмента Zero Zero Ends; конец сегмента Zero
Если при этом задана директива .Alpha, т. е. надежда, что сегмент zero будет расположен в теле задачи последним. В таком случае он и является началом свободного пространства в блоке задачи.
Несмотря на очевидную простоту, этот способ не универсален, поскольку сегмент zero не всегда оказывается последним. Напомним, что имена могут состоять не только из букв. Например, если кодовый сегмент имеет имя _text, то сегмент Zero будет расположен перед ним. Поэтому нужен более надежный способ определения последнего сегмента.
Если указана директива Dosseg, то последним в теле задачи будет расположен стековый сегмент. Тот же результат получается при использовании специальных директив, показанных в примере Б.2. Учитывая, что они рекомендованы разработчиками в качестве основных, имеет смысл исходить из допущения, что последним в теле задачи расположен стековый сегмент.
Стековый сегмент имеет определенный размер, который надо учесть при вычислении первого свободного сегмента в блоке задачи. При входе в задачу регистр SP содержит адрес верхушки, который равен размеру стека, выраженному в байтах. Его надо преобразовать в параграфы (разделить на 16) и сложить с кодом стекового сегмента, хранящимся в регистре ss. Таким образом, адрес начала свободного пространства (код свободного сегмента) вычисляется по формуле:
freeseg = [ss] + ([sp] /16) + 1
В этой формуле квадратные скобки указывают на то, что используется содержимое регистров ss и sp. При программировании деление [sp] на 16 заменяется сдвигом на 4 разряда вправо. Для того чтобы не потерять один параграф, размер стека должен быть кратен 16-ти, в противном случае его надо округлить в сторону увеличения. Прибавление 1 нужно потому, что свободный сегмент должен начинаться после стекового, не перекрывая его.
Замечание
Какой бы сегмент вы не выбрали в качестве точки отсчета, советуем при построении задачи обязательно задать файл листинга (карту памяти) и убедиться в том, что выбранный сегмент расположен в теле задачи последним.
Размер свободного пространства
В PSP слово со смещением 2 содержит последний доступный для задачи адрес оперативной памяти, выраженный в параграфах, т. е. это код последнего доступного сегмента. После загрузки задачи DOS помещает код сегмента, содержащего PSP в регистры es и ds.
Содержимое регистра ds изменяется первыми командами задачи, а ев можно использовать для чтения указанной величины. Если ее уменьшить на freeseg, то получится размер свободного пространства, выраженный в параграфах. Теперь надо проверить, достаточно ли выделенное пространство для нужд задачи, и если да, то его можно использовать.