1.3.5 Загрузка и запуск программных оверлеев.

Error message

Notice: Undefined index: add term path in hansel_get_breadcrumbs() (line 524 of /data/sites/msdosworld.ru/www/sites/all/modules/hansel/hansel.module).

   Оверлеи - это части программы, которые остаются на диске, в то
время  как  тело программы резидентно в памяти.  Когда  требуется
функция,  выполняемая  каким-либо  оверлеем,  то он загружается в
память и программа вызывает его как процедуру.  Различные оверлеи
могут загружаться в одно и то же место  памяти, перекрывая преды-
дущий  код.  Например, программа ведения базы данных может загру-
зить процедуру сортировки, а затем  перекрыть ее процедурой гене-
рации отчетов.  Эта техника используется для экономии памяти.  Но
она хороша только для тех процедур,  которые не используются пос-
тоянно, иначе частые обращения к диску приведут к тому, что прог-
рамма будет выполняться слишком медленно.

   Средний уровень.

   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

 

Вы находитесь в разделе: 

Добавить коментарий