



                          ГЛАВА 13

                          Оверлеи

     Оверлеи (которые называют также перекрытиями или  нало-
жениями)  представляют  собой  части программы, которые сов-
местно используют общую область памяти. В один и тот же  мо-
мент  времени  резидентно  размещаться в памяти может та или
иная часть программы, необходимая  для  выполнения  заданной
функции. В процессе выполнения эти части программы могут за-
мещать друг друга.
     Оверлеи могут значительно сократить объем памяти, необ-
ходимый  для выполнения программы. Фактически, так как в лю-
бой момент времени в памяти  резидентно  размещаются  только
части  программы,  с  помощью  оверлеев  вы можете выполнять
программы, значительно превосходящие по объему доступную па-
мять.
     Турбо-Паскаль управляет оверлеями  на  уровне  модулей,
которые  являются  наименьшей  частью  программы, образующей
оверлей. При компияции программы, имеющей оверлейную  струк-
туру,  Турбо-Паскаль  генерирует наряду с выполняемым файлом
(который имеет расширение  .EXE)  оверлейный  файл  (имеющий
расширение  .OVR) Файл с расширением .ЕХЕ содержит статичес-
кие (не оверлейные) части программы, а  файл  с  расширением
.OVR  содержит все оверлейные модули, которые при выполнении
программы будут подкачиваться в  память  или  выводиться  из
нее на диск.
     За исключением нескольких правил  его  программирования
оверлейный  модуль полностью идентичен неоверлейному модулю.
Фактически, если вы соблюдаете эти правила, у вас нет  необ-
ходимости перекомпилировать модуль, чтобы образовать из него
оверлей. Решение о том, будет  модуль  оверлейным  или  нет,
принимается программой, которая использует данный модуль.
    При загрузке оверлеев в память они помещаются в оверлей-
ный буфер, который размещается в памяти между сегментом сте-
ка и динамически распределяемой областью памяти. По  умолча-
нию  для оверлейного буфера выбирается минимальный возможный

                                - 2 -


размер, но во время выполнения программы  его  размер  может
быть  легко  увеличен путем выделения дополнительной области
памяти из  динамически  распределяемой  области.  Аналогично
сегменту данных и минимальному размеру динамически распреде-
ляемой области, оверлейный буфер принятого по умолчанию раз-
мера  выделяется при загрузке файла .ЕХЕ. При отсутствии па-
мяти необходимого объема модулем Dos или диалоговой програм-
мной средой будет  выводиться  сообщение  об ошибке (Program
too big to fit in memory -  программа слишком велика,  чтобы
разместиться в памяти) или (Not enough memory to  run  prog-
ram - для запуска программы не хватает памяти).
     Одной из очень важных возможностей подсистемы  управле-
ния  оверлеями является возможность при наличии достаточного
пространства загружать оверлейный файл в расширенную память.
Для этой цели в Турбо-Паскале поддерживается средство расши-
рения  памяти  EMS  (Lotus/Intel/Microsoft  Expanded  Memory
Specification).  При  размещении оверлейного файла в EMS все
последующие загрузки оверлеев сводятся  к  быстрой  передаче
информации из памяти в память.

                     Модуль Overlay

     Подсистема управления оверлеями Турбо-Паскаля  реализу-
ется с помощью стандартного модуля Overlay. В модуле Overlay
используются усовершенствованные методы управления буферами,
что обеспечивает оптимальное выполнение программы в имеющей-
ся области памяти. Например, подсистема управления оверлеями
сохраняет в оверлейном буфере столько оверлеев, сколько воз-
можно. Это позволяет уменьшить частоту считывания оверлев  с
диска. Послу загрузки оверлея вызов одной из его подпрограмм
выполняется также быстро, как обращение к неоверлейной прог-
рамме.  Кроме  того, когда у подсистемы управления оверлеями
возникает необходимость вывести один оверлей, чтобы  освобо-
дить место для другого,  она  сначала  пытается  вывести  те
оверлеи, которые не являются активными (то есть  те, которые
в данный момент времени не содержат активных программ).
     Для реализации улучшенных методов управления  оверлеями
Турбо-Паскаль  требует от вас при написании программы, в ко-

                                - 3 -


торой используются оверлеи, соблюдать два важных правила:

     1.  Все оверлейные модули  должны  содержать  директиву
         {$O+},  приводящую к тому, что компилятор обеспечи-
         вает гененирование оверлейного кода.
     2.  При каждом  обращении  к  оверлейной процедуре  или
         функции  вы  должны  обеспечить использование всеми
         активными процедурами и функциями вызовов типа  FAR
         (дальний тип вызова).

     Оба правила будут поясняться далее в разделе под  заго-
ловком  "Разработка  оверлейных  программ". Сейчас мы просто
отметим, что вы можете легко удовлетворить эти правила,  по-
местив  в  начале  оверлейных  модулей директиву компилятора
{$O+,F+}, а в начале всех других модулей и основной програм-
мы - директиву {$F+}.

           Примечание: Несоблюдение  требование  обеспечения
      дальнего  типа  вызова  в оверлейной программе вызовет
      непредсказуемые и возможно катастрофические результаты
      при выполнении программы.

     Директива компилятора {$O  имя_модуля}  используется  в
программе  для указания того, какой  из  модулей будет овер-
лейным. Эта директива дожна размещаться за предложением  ис-
пользования  программы,  в котором перед именами всех других
оверлейных модулей должно указываться имя стандартного моду-
ля Overlay. Приведем следующий пример:

  program Editor;
  {F+}              { Все процедуры и функции будут
 использовать
                      дальний тип вызова }
  uses
   Overlay, Crt, Dos, EdInOut, EdFormat, EdPrint, EdFind,
 EdMain
  {$O EdInOut }
  {$O EdFormat }

                                - 4 -


  {$O EdPrint }
  {$O EdFind }
  {$O EdMain }

           Примечание: Если вы пытаетесь  использовать,  как
      оверлейный,  модуль,  при  компиляции которого не была
      указана директива {$O+}, то компилятор выведет сообще-
      ние  об  ошибке.  Что касается стандартных модулей, то
      оверлейным может быть только модуль Dos. Другие  стан-
      дартные  модули  (System, Crt, Overlay, Graph, Turbo3,
      Graph3) не могут использоваться в качестве оверлейных.
      К  тому  же  программы,  содержащие оверлейные модули,
      должны компилироваться на диск. Если вы пытаетесь  вы-
      полнить компиляцию таких программ в память,  то компи-
      лятор выводит сообщение об ошибке.

                   Константы и переменные

     В этом разделе кратко описываются константы и  перемен-
ные, определенные в модуле Overlay.

                    Переменная OvrResult

     Перед возвратом управления каждая  процедура  в  модуле
Overlay   сохраняет   свой   код   результата  в  переменной
OvrResult.

     var OvrResult : integer;

     Возможные коды возврата определены в описании  констант
в следующем разделе. В общем случае нулевое значение говорит
об успешном завершении.
     Переменная  OvrResult  напоминает  стандартную  функцию
IOResult,  за исключением того, что переменная OvrResult при
обращении к ней не устанавливается в значение 0. Таким обра-
зом,   отпадает   необходимость   в  копировании  переменной
OvrResult перед ее проверкой в локальную переменную.


                                - 5 -


                      Коды результата

     Ошибки, возникающие в модуле Overlay, сообщаются с  по-
мощью переменной OvrResult. Определены следующие коды:

  const
    ovrOk = 0;           { успешное завершение }
    ovrError = -1;       { ошибка подсистемы управления
                           оверлеями }
    ovrNotFound = -2;    { не найден оверлейный файл }
    ovrNoMemory = -3;    { не хватает памяти для оверлей-
                           ного буфера }
    ovrIOError = -4;     { ошибка ввода-вывода оверлейно-
                           го файла }
    ovrNoEMSDriver = -5;  { не установлен драйвер EMS }
    ovrNoEMSMemory = -6;  { не хватает расширенной памяти }

                    Процедуры и функции

     В  оверлейном  модуле  Overlay   определены   процедуры
OvrInit,  OvrInitEMS, OvrSetBuf и OvrclearBuf, а также функ-
ция OvrGetBuf. Далее приведено краткое  описание  каждой  из
них. Более подробная информация дается в Главе 8 ("Процедуры
и функции").

                     Процедура OvrInit

     procedure OvrInit(имя_файла : string);

     Эта  процедура  инициализирует  подсистему   управления
оверлеями   и   открывает  оверлейный  файл.  Если  параметр
"имя_файла" не задает дисковод или  каталог,  то  подсистема
управления оверлеями выполняет поиск файла в текущем катало-
ге, каталоге, содержащем файлы .ЕХЕ (при работе в операцион-
ной системе ДОС 3.х) и в каталогах, заданных с помощью пере-
менной операционной среды ДОС PATH. Возможными кодами  возв-
рата  по  ошибке  являются  коды ovrError или ovrNotFound. В
случае ошибки подсистема управления оверлеями остается неус-

                                - 6 -


тановленной,  и попытка вызывать оверлейную программу приве-
дет к ошибки времени выполнения 208.

           Примечание: Процедура OvrInit  должна  вызываться
      перед  любой  другой  процедурой подсистемы управления
      оверлеями.

                    Процедура OvrInitEMS

     procedure OvrInitEMS;

     Данная процедура, если это возможно, загружает оверлей-
ный файл в расширенную память (EMS).  При этом все последую-
щие загрузки оверлеев сводятся к быстрой передаче информации
из памяти  в память.  Возможными кодами  возврата по  ошибке
являются     ovrError,     ovrIOError,     ovrNoEMSError   и
ovrNoEMSMemory. Подсистема управления оверлеями  будет  про-
должать работу, но оверлеи будут считываться с диска.

           Примечание: Использование для размещения оверлеев
      в  памяти  процедуры OvrInitEMS не устраняет необходи-
      мости работы с оверлейным буфером. Оверлеи тем не  ме-
      нее перед их выполнением должны копироваться из памяти
      EMS в обычную память  (в  оверлейный  буфер).  Однако,
      поскольку  передача  из памяти в память осуществляется
      значительно быстрее, чем чтение с диска, необходимость
      увеличения размера оверлейного буфера становится менее
      очевидной.

                    Процедура OvrSetBuf

     procedure OvrSetBuf(размер : longint)

     Данная процедура задает размер оверлейного буфера. Ука-
занный размер должен быть больше или равен начальному разме-
ру оверлейного буфера  и  быть  больше  или  равен  значению
MemAvail,  плюс текущий размер оверлейного буфера. Если ука-
занный размер больше текущего размера, то с  начальной  гра-

                                - 7 -


ницы динамически распределяемой области памяти отводится до-
полнительное пространство (таким образом, размер динамически
распределяемой области уменьшается). Если же заданный размер
меньше текущего размера, то избыточное пространство  возвра-
щается в динамически распределяемую область памяти. Процеду-
ра OvrSetBuf требует, чтобы динамически  распределяемая  об-
ласть  памяти  была  пустой. Если с помощью процедур New или
GetMem уже были образованы динамические переменные, то возв-
ращается  ошибка. Возможными кодами возврата по ошибке явля-
ются ovrError и ovrNoMemory. Если процедура OvrSetBuff возв-
ращает ошибку, то подсистема управления оверлеями будет про-
должать работу, однако размер оверлейного  буфера  останется
неизмененным.

                    Процедура OvrGetBuf

     function OvrGetBuf:longint;

     Возвращает текущий размер оверлейного буфера.  Первона-
чально  оверлейный  буфер имеет наименьший возможный размер,
соответствующий размеру наибольшего оверлея. При  выполнении
оверлейной программы буфер такого размера выделяется автома-
тически. (Примечание: Начальный размер буфера  может  превы-
шать  64К,  так  как он включает в себя код и дополнительную
информацию для самого большого оверлея.)

                   Процедура OvrClearBuf

     procedure OvrClearBuf;

     Данная процедура очищает оверлейный буфер.  Все  загру-
женные  в  настоящий момент оверлеи удаляются из оверлейного
буфера, вынуждая при  всех  последующих  вызовах  оверлейных
программ  выполнять  загрузку  оверлеев из оверлейного файла
(или из памяти EMS). Если процедура  OvrClearBuf  вызывается
из  оверлея, то этот оверлей будет немедленно загружен, пока
не завершится выполнение процедуры  OvrClearBuf.  Подсистема
управления оверлеями никогда не требует от вас вызова проце-

                                - 8 -


дуры OvrClearBuf. Фактически, обращение к  данной  процедуре
уменьшит производительность вашей прикладной задачи, так как
это приводит к перезагрузке оверлеев. Поэтому данная  проце-
дура  предназначена для использования в особых случаях, нап-
ример для временного освобождения памяти,  занимаемой  овер-
лейным буфером.

              Разработка программ с оверлеями

     В этом разделе дается наиболее  важная  информация  про
разработке программ с оверелями. Просмотрите ее внимательно:
для хорошей работы прикладных программ, в которых  использу-
ются  оверлеи,  многие обсуждаемые вопросы являются жизненно
важными.

                 Генерация оверлейного кода

     Турбо-Паскаль допускает использование модуля в качестве
оверлейного только в том случае, если он генерировался с ди-
рективой {$O+}. Когда задана эта директива, генератор выпол-
няемого  кода при передаче строки из одной оверлейной проце-
дуры в другую и задании постоянных параметров  предпринимает
особые  меры  предосторожности.  Например, если модуль UnitA
содержит процедуру со следующим заголовком:

  procedure WriteStr(s: string);

и модуль UnitB содержит оператор:

  WriteStr('Hello word...');

то  Турбо-Паскаль  помещает   строковую   константу   'Hello
word...' в сегмент кода модуля UnitB и передает указатель на
него процедуре WriteStr. Однако, если  оба  модуля  являются
оверлейными, то это работать не будет, поскольку при обраще-
нии в WriteStr сегмент кода модуля UnitB может быть перекрыт
модулем UnitA, и ссылка на строку окажется недопустимой. Для
того, чтобы избежать эти  проблемы,  используется  директива

                                - 9 -


{$O+}. Каждый раз, когда Турбо-Паскаль встречет обращение из
одного модуля, скомпилировнного с директивой {$O+}, к друго-
му  модулю, скомпилированному с директивой {$O+}, компилятор
перед передачей ссылок на них обеспечивает временное копиро-
вание всех размещенных в сегменте кода констант в стек.
     Использование в модуле директивы {$O+} не обязывает вас
использовать  этот модуль, как оверлейный. Она просто указы-
вает Турбо-Паскалю на необходимость  обеспечения,  если  это
нужно,  использования данного модуля в качестве оверлейного.
Если вы разрабатываете модули, которые планируете  использо-
вать  как  в  оверлейных,  так  и  в неоверлейных прикладных
программах, то компиляция их с директивой {$O+} обеспечивает
использование одной версии модуля для обоих случаев.

       Требование использования дальнего типа вызовов

     Как уже упоминалось ранее, при любом обращении к  овер-
лейной  процедуре  или  функции  из другого модуля вы должны
обеспечить для всех активных процедур и функций вызовы  типа
FAR (дальний тип вызова).
     Это можно хорошо проиллюстрировать на следующем  приме-
ре.  Предположим,  что  OvrA  представляет собой процедуру в
оверлейном модуле, а процедуры MainC и MainD -  процедуры  в
основной  программе. Если основная программа вызывает MainC,
которая вызывает процедуру MainB, которая в свою очередь об-
ращается к процедуре OvrA, то во время обращения к процедуре
OvrA процедуры MainC и MainB являются активными (они еще  не
выполнили  возврат управления), поэтому необходимо использо-
вать для них дальний тип вызова. Описанные в основной  прог-
рамме, процедуры MainC и MainB в обычной ситуации используют
ближний тип вызовов (NEAR). С помощью директивы  компилятора
{$F+} необходимо задать дальний тип вызовов.
     Самый легкий способ удовлетворения требования использо-
вания  дальнего  типа  вызовов состоит в размещении в начале
основной программы  и  в  начале  каждого  модуля  директивы
{$F+}. Альтернативный способ состоит в изменении принятой по
умолчанию установки $F на {$F+} с помощью  директивы  коман-
дной  строки  /$F+  (ТРС.ЕХЕ)  или  с  помощью  меню  команд

                                - 10 -


O/C/Force Far Calls в среде интерактивного  компилятора.  По
сравнению со смешанным  использованием  вызовов  ближнего  и
дальнего типа использование вызовов только типа FAR не  при-
водит к особенно большим дополнительным затратам памяти: для
этого требуется одно дополнительное слово пространства стека
на активную процедуру и один дополнительный  байт на  каждый
вызов.

       Инициализация подсистемы управления оверлеями

     Здесь мы рассмотрим некоторые примеры того, как инициа-
лизируется  подсистема управления оверлеями. Код инициализа-
ции должен быть помещен перед первым обращением к оверлейной
программе. Инициализацию обычно следует делать в операторной
части программы.
     Следующая часть программы показывает, как немного  тре-
буется  для того, чтобы инициализировать подсистему управле-
ния оверлеями.

  begin
    OvrInit('EDITOR.OVR');
  end;

     Проверка на ошибки не делается. Поэтому если для  овер-
лейного буфера не хватает памяти или оверлейный файл не най-
ден, то при попытке вызова оверлейной  программы  произойдет
ошибка  208  (Overlay manager not installed - подсистема уп-
равления оверлеями не установлена).
     Приведем другой небольшой пример, являющийся расширени-
ем предыдущего.

  begin
    OvrInit('EDITOR.OVR');
    OvrInitEMS;
  end;

     В этом случае, если предположить, что  для  оверлейного
буфера  имеется достаточно памяти и что можно найти оверлей-

                                - 11 -


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

  const
    OvrMaxSize = 80000;
  begin
    OvrInit('EDITOR.OVR');
    OvrInitEMS;
    OvrSetBuf(OvrMaxSize);
  end;

     Для определения идеального размера  оверлейного  буфера
общих рекомендаций нет. Подходящее значение можно определить
только имея  некоторую  информацию  о  прикладной  задачи  и
экспериментальным путем.

           Примечание:  Использование  процедуры  OvrInitEMS
      для  размещения оверлейного файла в расширенной памяти
      не устраняет необходимости работы с  оверлейным  буфе-
      ром.  Ведь  оверлеи  перед  выполнением  тем  не менее

                                - 12 -


      должны копироваться из расширенной  памяти  в  обычную
      (то  есть в оверлейный буфер). Однако, поскольку такие
      передачи из памяти в  память  выполняются  значительно
      быстрее, чем чтение с диска, то необходимость увеличе-
      ния размера оверлейного буфера становится  менее  оче-
      видной.  Нужно  также  помнить  о  том,  что процедура
      OvrSetBuf увеличивает  размер  оверлейного  буфера  за
      счет уменьшения размера динамически распределяемой об-
      ласти памяти. Таким образом, динамически  распределяе-
      мая   область  должна  быть  пустой,  иначе  процедура
      OvrSetBuf не окажет никакого действия. Если вы исполь-
      зуете  модуль  Graph, убедитесь в том, что вы обращае-
      тесь к процедуре  OvrSetBuf  перед  вызовом  процедуры
      InitGraph, которая выделяет память в динамически расп-
      ределяемой области.

     Приведем теперь более исчерпывающий пример  инициализа-
ции  подсистемы управления оверлеями, включающей в себя пол-
ную проверку на возможное возникновение ошибок.

  const
    OvrMaxSize = 80000;
  var
    OvrName: string[79];
    Size: Longint;
  begin
    OvrName:='EDITOR.OVR';
    repeat
      OvrInit(OvrName);
      if OvrResult=ovrNotFound then
      begin
        WriteLn('Оверлейный файл не найден');
        WriteLn('Введите правильное имя оверлейного
 файла:');
        ReadLn(OvrName);
      end;
     until OvrResult<>ovrNotFound;
     if OvrResult<>ovrOk then

                                - 13 -


     begin
       WriteLn('Ошибка опдсистемы управления оверлеями.')
       Halt(1);
     end;
     OvrInEMS;
     if OvrResult<>OvrOk then
     begin
       case OvrResult of
         ovrIOError:      Write('Ошибка ввода-вывода
                                 оверлейного файла');
         ovrNoEMSDriver:  Write('Драйвер EMS не
                                 установлен');
         ovrNoEMSMemory:  Write('Не хватает расширенной
                                 памяти');
     end;
     Write('. Нажмите клавишу Enter...');
     ReadLn;
   end;
   OvrSetBuf(OvrMaxSize);
  end;

     Сначала, если принятое  по  умолчанию  имя  оверлейного
файла было неверным, пользователю будет выводиться подсказка
на введение правильного имени файла.
     Далее проверяются другие ошибки, которые могут произой-
ти  при инициализации. В случае обнаружения ошибки программа
останавливается, так как ошибки в OvrInit являются фатальны-
ми.  (Если они игнорируются, то при первом обращении к овер-
лейной программе во время выполнения произойдет ошибка.)
     Если предположить, что инициализация проходит  успешно,
далее  для  загрузки  оверлейного файла в расширенную память
(если  это  возможно)  выполняется  обращение  к   процедуре
OvrInitEMS. В случае ошибки на экран выводится диагностичес-
кое сообщение, однако программа не  останавливается.  Вместо
этого она просто продолжает считывать оверлеи с диска.
     Наконец, для задания значения размера оверлейного буфе-
ра,  определенного с помощью анализа или эксперимента с кон-
кретной   приклажной   программой,   вызывается    процедура

                                - 14 -


OvrSetBuf.  Ошибки,  которые могут возникнуть при выполнении
данной процедуры, игнорируются, хотя OvrResult может возвра-
щать  код  возврата  по ошибке -3 (OvrNoMemory). Если памяти
недостаточно, подсистема управления оверлеями  будет  просто
продолжать использовать буфер минимального размера, выделен-
ный при запуске программы.

         Разделы инициализации в оверлейных модулях

     Аналогично статическим модулям оверлейные модули  могут
содержать  раздел инициализации. Хотя оверлейный код инициа-
лизации не отличается от обычного кода  инициализации,  под-
система  управления оверлеями должна быть первоначально ини-
циализирована таким образом, чтобы она могла загружать и вы-
полнять оверлейные модули.
     Взяв в качестве примера ранее  рассмотренную  программу
Editor,  предположим,  что  модули EdInOut и EdMain содержат
код  инициализации.  При  этом  требуется,  чтобы  процедура
OvrInit вызывалась перед кодом инициализации модуля EdInOut,
и единственный способ осуществить это  состоит  во  введении
дополнительного  неоверлейного модуля, который следует перед
EdInOut и вызывает в своем разделе  инициализации  процедуру
OvrInit.

  unit EdInit;
  interface
  implementation
  uses Overlay;
  const
    OvrMaxSize = 80000;
  begin
    OvrInit('EDITOR.OVR');
    OvrInitEMS;
    OvrSetBuf(OvrMaxSize);
  end.

     В предложении  использования  программы  модуль  EdInit
должен следовать перед всеми оверлейными модулями:

                                - 15 -



  program Editor;
  {$F}
  uses
   Overlay,Crt,Dos,EdInit,EdInOut,EdFormat,EdPrint,EdMain;
  {$O EdInOut }
  {$O EdFormat }
  {$O EdPrint }
  {$O EdFind }
  {$O EdMain }

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

      Что не должно использоваться в качестве оверлеев

     Отдельные модули не могут использоваться, как  оверлей-
ные. В частности, не пытайтесь использовать в качестве овер-
лейных модулей следующие:

     1.  Модули, скомпилированные с директивой  {$O-}.  Если
         вы  пытаетесь  использовать  как оверлейный модуль,
         который не был скомпилирован с директивой {$O+}, то
         компилятор  выдает сообщение об ошибке. Такими нео-
         верлейными модулями являются модули  System,  Over-
         lay, Turbo3 и Graph3.
     2.  Модули, которые содержат драйверы прерываний. Из-за

                                - 16 -


         того,  что сама операционная система ДОС имеет нео-
         верлейную структуру, модули, реализующие  процедуры
         прерываний (interrupt), не должны быть оверлейными.
         В качестве примера  такого  модуля  можно  привести
         стандартный  модуль  Crt, реализующий драйвер обра-
         ботки прерывания, возникающего при  нажатии  клавиш
         Ctrl-Break.

     Подсистемой управления оверлеями Турбо-Паскаля  полнос-
тью поддерживается вызов оверлейных процедур с помощью  ука-
зателей процедур. В качестве примеров использования указате-
лей процедур можно привести процедуры завершения и драйверы
устройств для текстовых файлов.
     Аналогично, полностью поддерживается передача  оверлей-
ных  процедур  и  функций в качестве параметров процедурного
типа и присваивание оверлейных процедур и функций переменным
процедурного типа.

                      Отладка оверлеев

     Большинство отладчиков  обладают  весьма  ограниченными
возможностями отладки оверлеев, если они вообще обладают та-
кими средствами.  Этого нельзя  сказать  о  Турбо-Паскале  и
Турбо-отладчике.  Интергированный отладчик полностью поддер-
живает при работе с оверлеями пошаговый режим и точки  оста-
нова,  используя  при  этом  метод, полностью прозрачный для
пользователя. С помощью оверлеев вы легко можете конструиро-
вать и отлаживать прикладные пакеты большого объема. Все это
можно делать как с помощью Турбо-отладчика, так и  из  инте-
рактивной интерактивной среды компилятора.

                Внешние программы в оверлеях

     Аналогично обычным процедурам и функциям  Турбо-Паскаля
при  искользовании  внешних программ на языке ассемблера для
обеспечения корректной работы подсистемы управления оверлея-
ми должны соблюдаться определенные правила программирования.
     Если в программе на языке ассемблера осуществляется об-

                                - 17 -


ращение к любой оверлейной процедуре или функции, то в прог-
рамме ассемблера должен использоваться дальний тип вызова  и
с помощью регистра ВР должны быть установлены границы стека.
Например, предположим,  что  OtherProc  является  оверлейной
процедурой   в   другом   модуле  и  ее  вызывает  программа
ExternProc на языке ассемблера. Тогда  программа  ExternProc
должна иметь дальний тип вызова и устанавливать границы сте-
ка следующим образом:

  ExternProc      PROC       FAR
        PUSH      bp         ; сохранить регистр ВР
        mov       bp,sp      ; установить границы стека
        SUB       sp,LocalSize ; выделить локальные
                             ;   переменные
        ...
        CALL      OtherProc  ; вызвать другой оверлейный
                             ; модуль
        ...
        mov       sp,bp      ; отменить локальные переменные
        pop       bp         ; восстановить регистр ВР
        RET       ParamSize  ; возврат управления
  ExternProc      ENDP

где LocalSize представляет собой размер  локальных  перемен-
ных,   а   ParamSize  -  размер  параметров.  Если  значение
LocalSize равно 0, то две строки,  в  которых  выделяются  и
уничтожаются локальные переменные, можно опустить.
     Если в программе ExternProc имеются косвенные ссылки на
оверлейные  процедуры  и функции, то эти требования остаются
теми же. Например, если процедура OtherProc  вызывает  овер-
лейные  процедуры  или функции, но сама не является оверлей-
ной, то программа ExternProc должна,  тем  не  менее,  иметь
дальний тип вызова и устанавливать границы стека.
     В том случае, если в программе на языке ассемблера  от-
сутствуют прямые или косвенные ссылки на оверлейные процеду-
ры или функции, то никаких специальных требований соблюдать-
ся  не должно: программа на языке ассемблера может использо-
вать ближний тип вызова и не устанавливать границ стека.

                                - 18 -


     Оверлейные программы на языке ассемблера не должны соз-
давать переменных в сегменте кода, поскольку при уничтожении
оверлея любые изменения, внесенные в оверлейный сегмент  ко-
да,  теряются. Аналогично, не следует считать, что указатели
на размещенные в оверлейном сегменте кода объекты  останутся
действительными  при  вызове других оверлеев, поскольку под-
система управления оверлеями  может  свободно  перемещать  и
уничтожать оверлейные сегменты кода.

