Страница 19 из 20 1.3.5 Загрузка и запуск программных оверлеев. Оверлеи - это части программы, которые остаются на диске, в то время как тело программы резидентно в памяти. Когда требуется функция, выполняемая каким-либо оверлеем, то он загружается в память и программа вызывает его как процедуру. Различные оверлеи могут загружаться в одно и то же место памяти, перекрывая преды- дущий код. Например, программа ведения базы данных может загру- зить процедуру сортировки, а затем перекрыть ее процедурой гене- рации отчетов. Эта техника используется для экономии памяти. Но она хороша только для тех процедур, которые не используются пос- тоянно, иначе частые обращения к диску приведут к тому, что прог- рамма будет выполняться слишком медленно. Средний уровень. MS DOS использует функцию EXEC для загрузки оверлеев. Эта функция, номер 4BH прерывания 21H, используется также для загруз- ки и запуска одной программы из другой, если поместить код 0 в AL [1.3.2]. Если в AL поместить код 3, то тогда будет загружен оверлей. В этом случае не создается PSP, поэтому оверлей не уста- навливается как независимая программа. Такая процедура просто загружает оверлей, не передавая ему управления. Имеется два способа обеспечить память для оверлея. Может быть использована либо область внутри тела программы, либо специально отведена область памяти за пределами головной программы. Функции EXEC передается только сегментный адрес, в качестве позиции, куда будет загружен оверлей. Когда оверлей загружается в тело головной программы, то программа должна вычислить номер параграфа, куда будет загружаться оверлей, сама. С другой стороны, при загрузке в специально отведенную память MS DOS обеспечивает программу номе- ром параграфа. В нижеприведенном примере используется загрузка в отведенную память. Поскольку DOS отводит программе всю доступную память, то сначала необходимо освободить память с помощью функции 4AH. Функ- ция 48H отводит блок памяти достаточно большой, чтобы он мог принять самый большой из оверлеев. Эта функция возвращает значе- ние сегмента блока в AX, и этот номер параграфа определяет куда будет загружен оверлей, а также по какому адресу оверлей будет вызываться головной программой. Эти функции детально обсуждаются в [1.3.1]. Кроме кода 3, засылаемого в AL, Вы должны установить для этой функции еще два параметра. DS:DX должны указывать на строку, даю- щую путь к файлу оверлея, завершаемую байтом ASCII 0. Необходимо указывать полное имя файла, включая расширение .COM или .EXE, поскольку DOS в данном случае не считает, что он ищет программный файл. Наконец, ES:BX должны указывать на 4-байтный блок параметров, который содержит (1) 2-байтный номер параграфа, куда будет загру- жаться оверлей и (2) 2-байтный фактор привязки, который будет использоваться для привязки адресов в оверлее (привязка объяс- няется в [1.3.6]). В качестве номера параграфа надо использовать число, возвращаемое в AX, для номера параграфа отведенного блока памяти. Фактор привязки дает смещение, по которому могут быть вычислены адреса требующих привязки параметров в оверлее. Исполь- зуйте номер параграфа, куда загружается оверлей. После того как он установлен, вызовите функцию и оверлей будет загружен. Просто изменяя путь к оверлейному файлу, можно вновь и вновь вызывать эту функцию, загружая все новые и новые оверлеи. Если при возвра- те установлен флаг переноса, то была ошибка и ее код будет возв- ращен в AX. Код равен 1, если указан неверный номер функции, 2 - если файл не найден, 5 - при дисковых ошибках и 8 - при отсутст- вии достаточной памяти. После того как оверлей загружен в память, к нему можно полу- чить доступ как к далекой (far) процедуре. В сегменте данных должен быть установлен двухсловный указатель, определяющий этот вызов. Сегментная часть указателя просто равна текущему кодовому сегменту. Смещение оверлея должно быть вычислено нахождением разницы между сегментами кода и оверлея и умножением результата на 16 (переводя величину из параграфов в байты). В нижеприведен- ном примере две переменные OVERLAY_OFFSET и CODE_SEG помещены одна за другой для правильной установки указателя. Однажды загру- женный, оверелей затем можем вызываться инструкцией CALL DWORD PTR OVERLAY_OFFSET. Оверлей может быть полной программой со своими сегментами данных и стека, хотя как правило используется стековый сегмент вызывающей программы. При вызове оверлея значение сегмента его собственного сегмента данных должно быть помещено в DS. ;---завершаем программу фиктивным сегментом (см. [1.3.1]): ZSEG SEGMENT ZSEG ENDS ;---в сегменте данных OVERLAY_SEG DW ? OVERLAY_OFFSET DW ? ;смещение оверлея CODE_SEG DW ? ;сегмент оверлея - должен PATH DB 'A:OVERLAY.EXE' ;следовать за смещением 0BLOCK DD 0 ;4-байтный блок параметров ;---освобождаем память MOV CODE_SEG,CS ;создаем копию CS MOV AX,ES ;копируем значение сегмента PSP MOV BX,ZSEG ;адрес сегмента конца программы SUB BX,AX ;вычисляем разность MOV AH,4AH ;номер функции SETBLOCK INT 21H ;освобождаем память JC SETBLK_ERR ;флаг переноса говорит об ошибке ;---отводим память для оверлея MOV BX,100H ;отводим для оверлея 1000H байт MOV AH,48H ;функция отведения памяти INT 21H ;теперь AX:0 указывает на блок JC ALLOCATION_ERR ;флаг переноса говорит об ошибке MOV OVERLAY_SEG,AX ;запасаем адрес сегмента оверлея ;---вычисление смещения оверлея в кодовом сегменте MOV AX,CODE_SEG ;вычитаем значение сегмента оверлея MOV BX,OVERLAY_SEG ;из значения сегмента кода SUB BX,AX ;BX содержит число параграфов MOV CL,4 ;сдвигаем это число на 4 бита влево SHL BX,CL ;чтобы получить величину в байтах MOV OVERLAY_OFFSET,BX ;запоминаем смещение ;---загрузка первого оверлея MOV AX,SEG BLOCK ;ES:BX указывает на блок параметров MOV ES,AX ; MOV BX,OFFSET BLOCK ; MOV AX,OVERLAY_SEG ;помещаем адрес сегмента оверлея в MOV [BX],AX ;первое слово блока параметров MOV [BX]+2,AX ;сегмент оверлея - фактор привязки LEA DX,PATH ;DS:DX указывает на путь к файлу MOV AH,48H ;номер функции EXEC MOV AL,3 ;код загрузки оверлея INT 21H ;загружаем оверлей JC LOAD_ERROR ;флаг переноса говорит об ошибке ;---теперь программа занимается своими делами . . CALL DWORD PTR OVERLAY_OFFSET ;вызов оверлея . ;нужно указывать DWORD PTR, так как оверлей - . ;далекая процедура ;---посмотрите эту структуру, когда будете писать оверлей DSEG SEGMENT ;как обычно, устанавливаем сегмент данных . ;опускаем стековый сегмент (используется . ;стек вызывающей программы) DSEG ENDS CSEG SEGMENT PARA PUBLIC 'CODE' OVERLAY PROC FAR ;всегда "далекая" процедура ASSUME CS:CSEG,DS:DSEG PUSH DS ;храним DS вызывающей программы MOV AX,DSEG;устанавливаем DS оверлея MOV DS,AX . . POP DS ;восстанавливаем DS при завершении RET OVERLAY ENDP CSEG ENDS END |