- •Раздел 8. Управление информацией в операционных средах
- •8.1. Общая характеристика связывания объектов
- •8.2. Загрузка абсолютной программы
- •8.3. Загрузка перемещаемой программы
- •8.4. Редактирование связей
- •8.5. Динамическое связывание
- •8.5.1. Организация оверлейных программ
- •8.5.2. Общая характеристика динамического связывания
- •8.5.3. Механизмы динамического связывания
8.5. Динамическое связывание
В начале рассмотрения принципов динамического связывания напомню особенности реализации программ с оверлейной структурой, поскольку такие программы являются как бы предвестником программ с динамической компоновкой.
8.5.1. Организация оверлейных программ
Главная цель организации оверлейных программ состоит в экономии оперативной памяти за счет загрузки различных модулей в одни и те же участки памяти по мере необходимости этих модулей.
Часто оверлейные программы описываются древовидными структурами. Рассмотрим пример.
┌───┐
│ А │ 1000
└─┬─┘1
┌────────────┼────────────┐
┌─┴─┐ ┌─┴─┐ ┌─┴─┐
│ B │ 500 │ C │ 1000 │ D │ 700
└─┬─┘2 └───┘3 └─┬─┘4
┌────┴────┐ ┌────┴────┐
┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐
│ E │ 500 │ F │ 800 │ G │ 400 │ H │ 1000
└───┘5 └───┘6 └───┘7 └───┘8
Узлы дерева называют секциями или сегментами.
Буквами обозначены имена секций, числами - размеры секций.
Корневой сегмент (А - в примере) загружается в начале выполнения программы и находится в памяти до завершения ее выполнения. Остальные сегменты вызываются тогда, когда к ним происходит обращение. Как правило, они записываются в виде, готовом к исполнению, в специальный файл SEGFILE.
Секция А может вызывать секции B, C и D во время выполнения. Секция B может вызывать секции E и F, а секция D - секции G и H.
Секция В называется ОТЦОМ секций E и F, а секция D - ОТЦОМ секций G и H.
Если секция А вызвала секцию В, а та в свою очередь вызвала секцию F, то в памяти окажутся загруженными эти перечисленные секции A, B, F.
Если секция А вызвала секцию D, а та в свою очередь вызвала секцию G, то в памяти окажутся загруженными эти перечисленные секции A, D, G.
Поскольку сегменты одного уровня могут вызываться только из сегмента вышестоящего уровня, то они не могут потребоваться одновременно и, соответственно, могут загружаться в одну и ту же область памяти по мере необходимости.
Знание размеров сегментов позволяет определить адреса их загрузки во время вызовов.
Предположим, что сегмент А загружается с адреса 0000. Тогда следующая таблица дает начальные адреса загрузки сегментов:
Сегмент Размер Адрес загрузки
A 1000 0000
B 500 1000
C 1000 1000
D 700 1000
E 500 1500
F 800 1500
G 400 1700
H 1000 1700
Эта таблица показывает, что все адреса могут быть определены рассмотренными методами раннего связывания, отличие состоит в том, что "отец" может передать управление сегменту, который в этот момент не находится в оперативной памяти.
Если программа - оверлейная, то загрузчик добавляет к ней (точнее, к корневому, постоянно находящемуся в памяти сегменту) специальный сегмент, называемый менеджером оверлеев - OVLMGR, и специальную таблицу сегментов SEGTAB.
Команда обращения к процедуре некоторой секции транслируется в команду обращения к строке таблицы SEGTAB, описывающей эту секцию.
Таблица SEGTAB содержит для каждого сегмента:
начальный адрес загрузки сегмента;
адрес точки входа в процедуру сегмента;
адрес сегмента в файле SEGFILE;
команду передачи управления (признак загружен сегмент в память или нет).
Характер команды передачи управления определяется тем, загружен ли сегмент в оперативную память или нет.
Если сегмент загружен, то команда передачи управления - это команда перехода на точку входа в процедуру сегмента.
Если сегмент не загружен, то команда передачи управления - это команда перехода на точку входа специальной процедуры менеджера оверлеев.
Эта специальная процедура выполняет следующие действия:
1) из файла SEGFILE считывает содержимое нужного сегмента и располагает его по заданному адресу;
2) корректирует команду передачи управления данного сегмента в SEGTAB таким образом, чтобы обращение к ней вызывало не процедуру менеджера оверлеев, а осуществляло переход на требуемую точку входа процедуры сегмента (помечает сегмент как загруженный);
3) корректирует команду передачи управления сегмента, который затерт загрузкой нового вызванного сегмента, на команду вызова менеджера оверлеев (помечает сегмент как незагруженный);
4) повторяет действие 3) для всех загруженных потомков затертого сегмента, т. е. помечает их как незагруженные.
Ниже представлены карты памяти в состояниях, когда уже загружены сегменты В и Е (строки 2 и 5 таблицы помечены как загруженные, а повторный вызов В производится сразу через строку 2 таблицы ).
В это время происходит вызов сегмента С. Вызов производится через процедуру OVLMGR. Сегмент С загружается на место В, строки 2 и 5 помечаются как незагруженные, а строка 3 помечается как загруженная.
┌──────────┐ ┌──────────┐
│ OVLMGR ├<─┐ ┌─────┤ OVLMGR ├<─┐
├──────────┤ │ │ ├──────────┤ │
┌─────>┤ /////// 2├──┼─┐ │ │ 2│ │
│ ├──────────┤ │ │ │ ├──────────┤ │
│ ┌─>┤ 3├──┘ │ │ ┌─>┤ /////// 3├──┘
│ │ ├──────────┤ │ │ │ ├──────────┤
│ │ │ 4│ │ │ │ │ 4│
│ │ ├──────────┤ │ │ │ ├──────────┤
│ │ │ /////// 5│ │ │ │ │ 5│
│ │ ├──────────┤ │ │ │ ├──────────┤
│ │ │ 6│ │ │ │ │ 6│
│ │ ├──────────┤ │ │ │ ├──────────┤
│ │ │ 7│ │ │ │ │ 7│
│ │ ├──────────┤ │ │ │ ├──────────┤
│ │ │ 8│ │ │ │ │ 8│
│ │ ├──────────┤ │ │ │ ├──────────┤
└───┼──┤ CALL B A│ │ │ │ │ A│
└──┤ CALL C │ │ │ └──┤ CALL C │
├──────────┤ │ │ ├──────────┤
│ B├<───┘ └────>┤ C│
├──────────┤ └──────────┘
│ E│
└──────────┘