для оверлея формата .COM
Так как файлы формата .EXE имеют нулевое начало, то какую
инструкцию CALL или JMP использовать для перехода к адресу заг-
рузки? Это будет зависеть от того, как написана программа. Для
файлов типа .EXE, созданных из одного исходного файла, компонов-
щик LINK и MS-DOS загружают сегменты в память в том же самом по-
- 3-54 -
рядке, в котором они появляются в исходной программе! Общим по-
рядком для определения сегментов является следующий: стековый
сегмент, затем сегмент данных, затем программный сегмент. (По
причине минимизации ссылок вперед в программном сегменте). Для
возможности вызова программ формата .EXE по инструкции CALL по
адресу их загрузки, программный сегмент должен быть первым сег-
ментом в файле .ASM, а точка входа должна быть первой инструкцией
в программном сегменте. Макроассемблер MASM и компоновщик LINK не
имеют с этим никаких проблем, хотя в некоторых случаях для MASM
может появиться необходимость использования директив замещения
для разрешения ссылок вперед.
Листинг 3-10 показывает как должна появляться последователь-
ность загрузки и вызова, когда используется функция загрузки
оверлея для файлов формата .COM. Последовательность для программ
формата .EXE проще. Не нужно перемещение от адреса загрузки к ад-
ресам при выполнении. Мы предположили, что все регистры сегментов
в порождающей программе уже инициализированы и что уже была выз-
вана функция модификации распределения памяти для освобождения
достаточного пространства для загрузчика файла COMMAND.COM.
Листинг 3-10. Загрузка и доступ к программе типа .COM
с помощью функции 4Bh (AL = 3)
-----------------------------------------------------------------
... ...
; Распределение памяти для оверлея
mov ah,48h ; функция распределения памяти
mov bx,1000h ; предполагается сегмент в 64 кбайт
int 21h ; вызов MS-DOS
jc error ; переход, если произошла ошибка
mov params,ax ; сохранение адреса памяти
; Загрузка оверлея
mov dx,offset params ; доступ к блоку параметров
mov bx,offset filename ; доступ к имени файла в ASCIIZ
mov ax,4B03h ; функция загрузки оверлея
int 21h ; вызов MS-DOS
jc error ; переход, если произошла ошибка
; Вызов оверлея
mov ax,params ; получение адреса загрузки
sub ax,10h ; трансляция для адреса выполнения
mov run_seg,ax ; и сохранение его
push ds ; сохранение сегмента данных
call dword ptr run_adr ; вызов оверлея
; Освобождение памяти, которая использована для оверлея
pop ds ; восстановление сегмента данных
mov ah,49h ; функция освобождения памяти
mov as,params ; получение адреса блока памяти
int 21h ; вызов MS-DOS
jc error ; переход, если произошла ошибка
... ...
params dw ? ; адрес загрузки
dw 0 ; значение настройки
run_adr dw 0100h ; новый указатель инструкции
run_seg dw ? ; новое значение кодового сегмента
-----------------------------------------------------------------
- 3-55 -
Пример программы распределяет память для размещения програм-
много кода оверлея. Он резервирует эту область памяти так, что
если и оверлей распределяет память, то получается чистая область.
Напротив, оверлей может распределить память, которую он уже зани-
мает, и перезаписать сам себя. Действительное резервируемое
пространство памяти может быть установлено для фактического раз-
мера оверлея.
Оверлей может изменяться так часто, как необходимо для выпол-
нения программы. При различных вариантах использования функции
загрузки оверлея следует иметь в виду, что MS-DOS ничего не
предпринимает для предотвращения загрузки оверлея в верхней части
текущего выполнения программы или в другом месте памяти, включая
саму систему! Хотя отдельные программисты могут найти такой трюк
полезным, его применение не рекомендуется, и более того необходи-
мо следить за тем, чтобы он не мог возникнуть случайно.
Загрузка резидентных программ
Резидентные подпрограммы и библиотека исполняющей системы RTL
для установки из другой программы лучше загружаются посредством
функции загрузки и выполнения программы, так что новая подпрог-
рамма имеет свой собственный блок памяти. В этих случаях вызываю-
щая (порождающая) программа получает управление после того, как
инициализированная ею секция резидентной программы выполнит зап-
рос "завершить и оставить резидентной".
Если была загружена автономная резидентная подпрограмма, то
порождающая программа завершается, оставляя резидентную подпрог-
рамму на месте в памяти. Это приводит к разбиению свободной памя-
ти на "куски", но операционная система MS-DOS не рискует загру-
жать последующие подпрограммы на резидентную подпрограмму. Если
была бы загружена RTL, то порождающая программа была бы готова к
вызову RTL, когда это необходимо. При завершении порождающая
подпрограмма имеет возможность оставить RTL в памяти для последу-
ющего использования или удалить ее путем сброса ее вектора преры-
вания в исходное состояние и освобождения ее блока памяти.
Так как функция загрузки и выполнения программы не информиру-
ет вызывающую подпрограмму об адресе загрузки резидентной подп-
рограммы и в связи с тем, что этот адрес не может быть передан
обратно в порождающую программу в единственном байте, резервируе-
мом для кода выхода программы (смотри функцию с кодом 31h "завер-
шить и оставить резидентной"), то для определения ячейки удаляе-
мого блока памяти порождающая подпрограмма должна обратиться к
тактике, обсужденной в предшествующем тексте.
Специальный случай: библиотеки исполняющей системы (RTL)
с неполным временем работы
Одной из многих возможностей, которые могут быть реализованы
с представленными функциями, является неполное время работы биб-
лиотеки исполняющей системы (RTL). Программы неполного времени
работы RTL являются резидентными только тогда, когда это необхо-
димо, а остальное время располагаются на диске. Эта возможность
реализуется путем установки части заголовков RTL точно также,
как описывалось в этой главе. Однако, эти заголовки не содержат
- 3-56 -
программных кодов для выполнения функций библиотеки; т.е. они не
содержат подпрограммы своей библиотеки, которые остались на диске
в другом файле. Последовательность событий, происходящих при вы-
полнении программ неполного времени работы RTL, показана в
блок-схеме 3-1.
____________________
| Загрузка |
| заголовков |
|____________________|
|
.--------------->|<---------------------------.
| __________V_________ |
| | | |
| | Прием запроса | |
| |____________________| |
| | |
| | |
| / \ |
| /Ко-\ |
| /манда\ __________|__________
| /освобо-\ ДА | Освобождение распре-|
| | ждения |----------->| деленной памяти |
| \памяти / |_____________________|
| \RTL ?/
| \ /
| \ /
| НЕТ |
| V
| / \
| / \
| / \ ____________________
| / RTL \ НЕТ |Распределение памяти|
| |установ- |------------>| для загрузки RTL |
| \ лена ?/ |____________________|
| \ / |
| \ / |
| \ / |
| | |
| ДА |<----------------------------
| __________V_________
| | |
-----| Функция выполнения |
|____________________|
Блок-схема 3-1. Последовательность загрузки RTL с неполным
временем работы
Когда одна из подпрограмм библиотеки доступна (через прерыва-
ние), то часть заголовков подпрограмм загружает файл библиотеки в
память, используя функцию 4Bh (AL=3) "Загрузить оверлей" и "запи-
рает" его в своей собственной памяти. Затем вызывается требуемая
подпрограмма библиотеки для выполнения запрашиваемой функции. Ли-
бо часть заголовков, либо конкретные подпрограммы библиотеки мо-
гут содержать инструкцию IRET для возврата в вызывающую програм-
му. С этого момента библиотеке доступен вызов всей последователь-
ности без ожидания времени на загрузку, поскольку RTL осталась
резидентной в памяти.
Когда главная программа завершается или требует пространство
памяти RTL, она передает в точку входа RTL код для освобождения
памяти, распределенной для RTL. Поскольку часть заголовков знает
адрес загрузки подпрограмм библиотеки после их загрузки, и пос-
- 3-57 -
кольку их блоком памяти владеет часть заголовков, освобождение
памяти не вызывает проблем. После этого выполняется перевод части
заголовков обратно в положение "спячки" для ожидания последующего
вызова.
Переключение контекста и переключение стека
В связи с тем, что большинство тем, обсужденных в этой главе,
относятся к операциям между отдельными программами с отдельными
стеками, процесс переключения заслуживает некоторого внимания.
Переключение стека, или переход от одного стека к другому являет-