- •Раздел 9. Управление информацией в операционных системах
- •9.1. Общая характеристика связывания объектов
- •9.2. Загрузка абсолютной программы
- •9.3. Загрузка перемещаемой программы
- •9.4. Редактирование связей
- •9.5. Динамическое связывание
- •9.5.1. Организация оверлейных программ
- •9.5.2. Общая характеристика динамического связывания
- •9.5.3. Механизмы динамического связывания
- •Раздел 9
9.2. Загрузка абсолютной программы
Этот вид загрузки является наиболее простым из рассматриваемых видов, и мы его будем рассматривать как введение в более сложные алгоритмы загрузки.
Здесь мы рассмотрим, что же собой представляет объектный код, являющийся результатом трансляции.
Реальная структура объектного кода может быть различной в зависимости от системы. Мы будем рассматривать некую абстрактную систему, тем не менее, считая, что в реальной системе обязательно должна присутствовать та же самая информация, но может быть в несколько иной форме.
Будем считать, что объектная программа представляет собой совокупность записей трех типов:
запись-заголовок;
запись-тело;
запись-окончание.
Запись-заголовок имеет следующий вид: Н.Имя_программы.Размер_программы
Запись-тело имеет следующий вид: T.Начальный_адрес_записи.Размер_записи.Коды_команд_и_данных
Запись-окончание имеет следующий вид: Е.Адрес_первой_исполняемой_команды
Пример. Напишем программу PROG, имеющую следующий код:
push ds 1E
mov ax, 0 B8 00 00
push ax 50
ret CB
Считая, что программа должна располагаться с нулевого адреса, в соответствие с нашим определением объектная программа будет иметь следующий вид:
H PROG 6
T 0000 1 1E
T 0001 3 B80000; B8 00 00
T 0004 1 50
T 0005 1 CB
E 0000
Или H PROG 6
T 0000 6 1EB8000050CB; 1E B8 00 00 50 CB
E 0000
Алгоритм работы загрузчика для такой программы достаточно прост:
Просматриваем запись-заголовок и сравниваем размер программы с имеющейся свободной памятью. Если памяти не хватает, то не грузим программу, если памяти хватает, то переходим к пункту 2.
Последовательно считываем записи-тела и располагаем коды команд и данных из этих записей в памяти по указанным адресам. Делаем это, пока не дойдем до записи-окончания.
Дойдя до записи-окончания, делаем переход на адрес, указанный в этой записи, т.е. к первой выполняемой инструкции программы.
9.3. Загрузка перемещаемой программы
В предыдущем примере говорилось о случае, когда заранее известно место в памяти, куда будет загружаться программа. Это случай нетипичный. Наиболее типичным является случай, когда начальный адрес программы не известен до момента загрузки.
Рассмотрим простейший пример.
Предположим, что наша программа может быть загружена с начального адреса 0000, по адресу 0000 у нас находятся данные, и мы хотим загрузить их в регистр ах. Мы напишем инструкцию, подобную следующей:
mov ax, [0000]
Запись-тело для такой инструкции будет выглядеть следующим образом:
Т 0007 4 8A260000 ; 8А 26 0000 (0007 - адрес инструкции)
Теперь предположим, что мы хотим загрузить нашу программу не с адреса 0000, а с адреса 2000. Смотрим правую карту памяти.
Помимо того, что адресная часть записей объектного кода (второй столбец записей с признаками Т и Е) должна измениться с 000Х на 200Х, должна измениться и информация внутри записей, а именно, там, где в записи-теле есть адрес 0000, должен стоять адрес 2000. Т. е. записи должны подвергнуться модификации, для того чтобы программа стала перемещаемой.
Поэтому в объектном коде перемещаемой программы существуют записи еще и другого, кроме Н, Т и Е, типа. Эти записи называются записями-модификаторами.
Т. о. имеем следующий общий список записей:
Запись-заголовок имеет следующий вид:
Н.Имя_программы.Размер_программы
Запись-тело имеет следующий вид:
T.Начальный_адрес_записи.Размер_записи.Коды_команд_и_данных
Запись-окончание имеет следующий вид:
Е.Адрес_первой_исполняемой_команды
Записиь-модификатор имеет следующий вид:
М.Адрес_модифицируемого_поля.Значение_модификации
В нашем конкретном примере запись-модификатор, относящийся к инструкции mov ax, [0000], будет иметь вид:
М 0009 2000
Для каждого перемещаемого данного должна существовать запись-модификатор.
Есть и другие способы хранения данных для модификации, но в информационном плане они не отличаются от приведенного.
Например. Добавление в запись-тело признака модификации.
Запись:
Т 0007 4 8А260000
может быть изменена следующим образом:
Т 0007 2 8А26
Т 0009 2 0000
После длин поля добавляется признак модификации 1 - перемещаемый код, 0 - неперемещаемый код.
Т 0007 2 0 8А26
Т 0009 2 1 0000
Загрузчик анализирует это поле записи в процессе загрузки и добавляет при необходимости к данным начальный адрес.
А в общем плане перемещение - это (пока) довольно несложная процедура, заключающаяся в прибавлении константы - начального адреса загрузки к некоторым полям данных записей объектного кода программы.
Отметим, что сегментация - это один из путей решения задачи перемещения. Внутри программы почти ничего не надо перемещать, достаточно настроить сегментные регистры на некоторые начальные адреса и перемещение будет происходить автоматически.
Алгоритм перемещающего загрузчика похож на алгоритм абсолютного загрузчика, приведенный выше, но в пункт 2 необходимо добавить анализ признака модификации кода перед загрузкой.