|
|
|
|
Доступ к программному оверлею из порождающей программы
После загрузки программного оверлея порождающая программа должна осуществить к нему доступ. Так как порождающая программа знает адрес, по
которому был загружен программный оверлей, то для доступа к оверлею она может выдать инструкцию CALL или инструкцию перехода JMP. Обращаться к оверлею
по инструкции CALL рекомендуется по той причине, что оверлей затем сможет возвратиться в порождающую программу путем использования инструкции RET, чем
запоминать адрес возврата в порождающую программу для инструкции JMP. Если же возвращать управление в порождающую программу не нужно, то
предпочтительнее использование инструкции JMP. Оверлей, в таком случае, содержит вызов функции завершения программы.
Все способы доступа к оверлею (либо по инструкции CALL, либо по инструкции JMP) должны быть ссылками far (далекий). Программный код, загружаемый в
оверлей, является относительным по отношению к собственному адресу сегмента и не может располагаться в том же самом сегменте, что и порождающая
программа (хотя он может быть загружен в тот же самый участок памяти). Кроме того, с помощью функции "загрузить оверлей" не строится блок PSP. Так
как отсутствует дополнительная информация, помещаемая в память загрузчиком, программные коды и данные из оверлейного файла загружаются, начиная точно
с указанного адреса загрузки.
Рассмотрим простейший случай : оверлей, загружаемый из файлов формата .COM. Все файлы формата .COM имеют начало 100 (шестнадцатиричное значение).
Т.е. коды этих файлов начинаются с адреса 100 относительно их сегментов. Все ссылки, содержащиеся в программе, являются относительными к этому адресу.
Т.к. файл .COM загружается прямо по адресу загрузки, можно некорректно использовать адрес загрузки в качестве значения сегмента для оверлея. Рис.3-15
показывает, что если адрес загрузки используется в качестве адреса сегмента, то значения смещений в программном коде смещаются на 100
(шестнадцатиричное значение). Правильный адрес сегмента для использования есть адрес загрузки минус 10 (шестнадцатиричное значение), который
перемещает смещения программного кода на 100 (шестнадцатиричное значение).
Для программных файлов формата .EXE существуют другие проблемы. Когда файл формата .EXE загружается для выполнения, MS-DOS инициализирует
программный и стековый сегменты для указания на надлежащий сегмент и указатель инструкции для указания на первую инструкцию программы. Когда файл
формата .EXE загружается как оверлей, MS-DOS не обеспечивает эти значения. Как тогда порождающая программа узнает, куда вводить программу?
/\/\/\/\/\/\/\/\/\/\/\/\
| Младшие адреса памяти | АДРЕС СЕГМЕНТА
|-----------------------|<--- ОВЕРЛЕЯ
| ^ | Segment:CS_RUN
| | | CS_LOAD:10(hex)
| 100 (hex) |
| | |
АДРЕС ЗАГРУЗКИ | V | АДРЕСА ПАМЯТИ
Segment:CS_LOAD---->|-----------------------|<---
|Программный код оверлея| CS_LOAD:0000(hex)
| ... | CS_RUN: 0100(hex)
|-----------------------|
| Данные оверлея |
| ... |
|-----------------------|
| Старшие адреса памяти |
|/\/\/\/\/\/\/\/\/\/\/\/
Рис.3-15. Взаимосвязь адреса сегмента и адреса загрузки
для оверлея формата .COM
|
Так как файлы формата .EXE имеют нулевое начало, то какую инструкцию CALL или JMP использовать для перехода к адресу загрузки? Это будет зависеть
от того, как написана программа. Для файлов типа .EXE, созданных из одного исходного файла, компоновщик LINK и MS-DOS загружают сегменты в память в том
же самом порядке, в котором они появляются в исходной программе! Общим порядком для определения сегментов является следующий: стековый сегмент,
затем сегмент данных, затем программный сегмент. (По причине минимизации ссылок вперед в программном сегменте). Для возможности вызова программ
формата .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 ? ; новое значение кодового сегмента
-----------------------------------------------------------------
|
Пример программы распределяет память для размещения программного кода оверлея. Он резервирует эту область памяти так, что если и оверлей
распределяет память, то получается чистая область. Напротив, оверлей может распределить память, которую он уже занимает, и перезаписать сам себя.
Действительное резервируемое пространство памяти может быть установлено для фактического размера оверлея.
Оверлей может изменяться так часто, как необходимо для выполнения программы. При различных вариантах использования функции загрузки оверлея
следует иметь в виду, что MS-DOS ничего не предпринимает для предотвращения загрузки оверлея в верхней части текущего выполнения программы или в
другом месте памяти, включая саму систему! Хотя отдельные программисты могут найти такой трюк полезным, его применение не рекомендуется, и более того
необходимо следить за тем, чтобы он не мог возникнуть случайно.
|
|