0000:0000 --------------- ||| |---------------| 1010:0000
|Образ программы| ||| |Образ программы|
| | ||| | |
0000:0010 | START | || ->| START | 1010:0010
0003:1234 | CALL 0005:ABCD| | -->| CALL 1015:ABCD| 1013:1234
0005:ABCD | MOV AX,0007 | --->| MOV AX,1017 | 1015:ABCD
0007:0000 | Data Segment | | Data Segment | 1017:0000
--------------- ---------------
Рис.3-11. Процесс настройки для загрузки программы типа .EXE
Однако, этот адрес является относительным для мнимого нулевого
базового сегмента, а не для действительного образа программы в
памяти. Для нахождения действительной ссылки сегмента в памяти
указатель таблицы настройки сам должен быть обновлен с помощью
адреса начала сегмента. Действительная ссылка на сегмент является
адресом 1013:1237.
Слова, указываемые в памяти, увеличиваются затем на адрес
начала сегмента. Вызов far (далекий) для сегмента 0005 теперь
станет вызовом far для сегмента 1015 - действительное размещение
подпрограммы.
После завершения настройки, регистры ES и DS процесса уста-
навливаются на адрес сегмента PSP, а регистры CS:IP и SS:SP ини-
циализируются значениями, данными в заголовке программного файла
типа .EXE. Оба регистра CS и SS увеличиваются на адрес начала
сегмента образа программы. Например, на Рис.3-11 адрес начала
(START) 0000:0010 является смещением действительного адреса нача-
ла сегмента 1010, для формирования действительных значений CS:IP
1010:0010, используемых при запуске программы.
Перекрытия
Рано или поздно Вам придется писать программу, которая явля-
ется слишком большой, чтобы разместиться в отведенном для нее
месте памяти. Когда это произойдет, одним из возможных способов
выполнения таких программ является создание перекрытий (оверлеев
-overlays). Перекрытие является разделом программы, которому не
нужно все время находиться в памяти. Он загружается в память тог-
да, когда это необходимо, но после того, как он станет ненужным,
пространство памяти, занимаемое им, может быть использовано неко-
торым другим перекрытием. Остаток программы, который не может
быть помещен в перекрытие, называется корнем (root). Все данные
программы должны помещаться в корень, т.к. данные в перекрытии
теряются при загрузке в него очередной части программы. Перекры-
тия, в конце концов, являются только читаемыми.
- 3-31 -
Перекрытия являются очень полезными объектами, и MS-DOS под-
держивает их достаточно эффективно. Одним из назначений функции
EXEC (выполнить) является загрузка перекрытий в память. Но перед
рассмотрением этой опции, необходимо отметить, что компоновщик
LINK MS-DOS имеет возможность создавать перекрытия и автоматичес-
ки управлять ими!
Правила использования управления перекрытиями в MS-DOS прос-
ты. Оверлейные (перекрываемые) модули не могут содержать глобаль-
ные или статические данные, хотя постоянные данные допустимы.
Другое правило заключается в том, что перекрытие может быть выз-
вано только с помощью вызова far (далекий) либо корня, либо дру-
гого перекрытия. Перекрытие может вызвать корень через вызов near
(близкий).
Способ создания перекрытия (оверлея) очень прост: при вызове
команды LINK, объектные файлы, составляющие перекрытие, должны
заключаться в круглые скобки. Это все, что для них имеется. Сле-
дующая командная строка создает программный файл, использующий
три перекрытия:
C> link root + (init + read) + (work) + (save + exit) ,myprog ;
Этот пример использует один набор подпрограмм для чтения не-
которых данных и инициализации программы, другой набор для обра-
ботки данных и еще один набор подпрограмм для сохранения обрабо-
танных данных и выхода. Поскольку ни одна из этих операций не
выполняется одновременно, каждая их них выполняется в перекрытии,
и, таким образом, решается проблема гипотетической памяти.
Резидентные программы
При типовом использовании операционная система MS-DOS пред-
ставляет собой операционную систему с одной задачей. В любой мо-
мент времени в памяти выполняется только одна программа. Факти-
чески же, MS-DOS имеет возможность в любое время поддерживать
несколько программ в памяти. В действительности, в любое конкрет-
ное время выполняется только одна программа, потому что процессор
может выполнять в любой конкретный момент времени только одну ин-
струкцию, но программы могут быть сконфигурированы таким образом,
что создается видимость их одновременного выполнения. Эти не-
сколько программ создаются путем загрузки программы в память с
помощью MS-DOS и затем возврата управления к MS-DOS без удаления
программы из памяти. Поскольку программа не покидает память при
возврате управления операционной системе, то программа называется
резидентной. Первым шагом при выполнении резидентной программы
является установка программы в памяти. Одним из простейших типов
резидентных программ являются библиотеки исполняющей системы (RTL
- run-time library), которые будут использованы в качестве перво-
го примера.
Описание библиотеки исполняющей системы
Что такое библиотека исполняющей системы? Как известно, биб-
лиотека представляет из себя собрание полезных подпрограмм, ко-
торые могут быть вызваны из программы. Большинство библиотек яв-
- 3-32 -
ляются скомпонованными (отредактированными) библиотеками, в кото-
рых требуемые подпрограммы включаются в программный файл (.EXE
или .COM) во время компоновки. Т.к. они являются частью програм-
много файла, подпрограммы скомпонованной библиотеки загружаются
вместе с программой при загрузке программного файла. RTL непос-
редственно не компонуется с программой, но подключается во время
выполнения. RTL должна уже находиться в памяти, или она должна
быть занесена в память, когда это необходимо, но, в любом случае
RTL не является частью самого программного файла.
RTL непосредственно не объединяется с программой, так как же
программа выполняет ее вызов? Программа должна каким-либо образом
поставить в известность либо операционную систему, либо RTL о
поддержке процесса, с помощью которого запрашивается библиотека.
Это может быть выполнено через вызовы, внутренние прерывания, ис-
ключительные ситуации или прерывания, зависящие от комплекса ап-
паратных средств и операционной системы. В среде операционной
системы MS-DOS/8086 наиболее подходящим способом является способ
оповещения через прерывание.
Почему же используют библиотеки RTL, если они требуют допол-
нительных усилий: предварительной загрузки, вызова и т.д.?
Во-первых, библиотеки RTL часто используются при разработке при-
кладных программ, которые имеют большое количество программ, со-
вместно использующих общие подпрограммы или для обеспечения общи-
ми ресурсами всех пользователей отдельного языка программирова-
ния. При использовании библиотек RTL, разработчикам необходимо
сохранять только одну копию библиотеки, вместо того, чтобы каждая
программа содержала такую копию. Пока интерфейс между программами
и RTL остается неизменным, подпрограммы в RTL могут обновляться
без модификации или перекомпоновки программ, которые их вызывают.
Поэтому RTL может выглядеть как расширение операционной системы,
т.к. она обеспечивает такие средства, которые необходимы разра-
ботчикам, но которые не поддерживает операционная система.
Во-вторых, библиотеки RTL имеют дополнительные преимущества по
уменьшению дисковой памяти и ускорению времени загрузки програм-
мы, т.к. RTL не загружается с каждой программой в отдельности.
Загрузка резидентных подпрограмм из командной строки
В MS-DOS имеется несколько способов, которые могут быть ис-
пользованы для загрузки образа программы в память. Диапазон этих
способов простирается от загрузки программы из командной строки
до подпрограмм начальной загрузки нижнего уровня, передающих
программный код из абсолютного места на диске в фиксированные
ячейки памяти. Наиболее простым способом является способ исполь-
зования загрузчика командной строки MS-DOS, представляющий собой
простой запрос для выполнения программы. Резидентные программы,
такие как, например, RTL, загружаются в память подобно любой
другой программе. Однако, после того, как резидентная программа
загружена и начала выполняться посредством предложения ее инициа-
лизации, она завершается использованием специального выхода:
функции с кодом 31h ("сохранить процесс") или вектора прерывания
27h ("завершить, но оставить резидентной"). Рекомендуемой проце-
дурой является использование функции с кодом 31h прерывания 21h,
которая демонстрируется в листинге 3-4.
Функция с кодом 31h имеет два параметра: необязательный па-
раметр код возврата, используемый для указания состояния при вы-
- 3-33 -
ходе из подпрограммы, и обязательный параметр, представляющий со-
бой значение размера блока памяти в параграфах, которое остается
распределенным за процессом. При вызове функции MS-DOS резервиру-
ет запрошенное количество памяти, начиная с адреса PSP (сегмента
программого префикса). Это происходит почти также как и при вызо-
ве функции "Модифицировать блок распределенной памяти" с адресом
PSP и требуемым размером. В случае функции "сохранить процесс"
MS-DOS знает, что блок, размер которого должен быть модифициро-
ван, начинается с адреса PSP, так что параметр не требуется.
Листинг 3-4. Функция с кодом 31h - "Сохранить процесс"
----------------------------------------------------------------
; используемый тип .COM
program segment
ORG 0
seg_org equ $
ORG 0100h
start:
...
mov dx,(offset last_byte - seg_org + 15) shr 4
mov ah,31h ; сохранить процесс
int 21h ; вызов MS-DOS
...
last_byte:
program ends
end start
; используемый тип .EXE
...
mov ax,es ; получение адреса PSP
mov dx,seg end_addr ; получение адреса посл.сегм.