Скачиваний:
10
Добавлен:
01.05.2014
Размер:
164.86 Кб
Скачать

8.4. Редактирование связей

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

Для того чтобы понять, о чем здесь будет идти речь, вернемся сначала к одномодульной программе.

Рассмотрим простейший пример:

mov ax, Mem

где Mem - символическое описание некоторой ячейки памяти.

Одной из задач транслятора является замена символического имени Mem на машинный адрес. Транслятор не сможет этого сделать, пока не узнает, какой адрес будет присвоен метке Mem.

Отсюда появляются два прохода при трансляции. На первом проходе ищутся все символические имена и им назначаются адреса. На втором проходе в тексте программы вместо символических имен подставляются адреса.

Результатом первого прохода является таблица имен переменных с их адресами.

Теперь представим себе ситуацию, когда мы хотим составить единую программу из нескольких (минимум из двух) модулей.

В каждом модуле могут существовать данные трех видов:

1) данные, описанные в этом модуле, и используемые только этим модулем; с данными этого вида проблем не возникает, ссылки на них организуются так, как было рассмотрено выше.

2) данные, описанные в этом модуле, но которые могут быть доступны и в других модулях;

3) данные, в этом модуле не описанные, но на которые этот модуль ссылается.

Простой пример.

Модуль 1 Модуль 2

M1 db 0 M2 db 0

mov ax, M1 mov ax, M2

mov ax, M2 mov ax, M1

Здесь в модуле 1 описана переменная М1, а используются переменные М1 и М2, последняя описана в другом модуле.

В модуле 2 описана переменная М2, а используются переменные М2 и М1, последняя описана в модуле 1.

В общем случае каждый модуль может содержать ссылки на объекты из других модулей и содержать объекты, на которые могут ссылаться другие модули.

Мы сказали, что результатом первого прохода при трансляции является таблицасоответствия имен переменных их адресам.

Так вот, результатом трансляции одиночного модуля многомодульной программы являются две таблицы:

1) Таблица определения символов, содержащая имена переменных, которые описаны в данном модуле и доступны для других модулей. Эту таблицу называют таблицей внешних определений;

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

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

А таблица внешних ссылок содержит только имена переменных и не содержит никаких адресов этих переменных, поскольку их адреса выделяются в других модулях.

Структуру объектного модуля многомодульной программы можно изобразить следующим образом:

Заголовок

Имя модуля

Размер

Таблица внешних ссылок

Внешний идентификатор

Таблица

внешних

определений

...

Идентификатор, Адрес_внутри_модуля

...

Тело модуля

...

Адрес, Размер, Признак_перемещения, Код

...

Данную таблицу можно представить и в виде записей, использованных выше.

Признак_перемещения - это параметр, который раньше имел два значения 1 или 0 - перемещаемый код или нет. Теперь он становится более сложным:

0 - неперемещаемая информация;

1 - перемещаемая информация внутренняя, т.е. перемещение относительно адреса загрузки данного модуля ;

< 0 - перемещаемая информация внешняя (обычно модуль этого числа - это номер строки в таблице внешних ссылок).

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

...

Идентификатор Адрес

...

где Адрес - это сумма адреса внутри модуля, где описан идентификатор, и суммы размеров всех модулей, загружаемых перед данным модулем.

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

Адрес D4 = 0 + Size1 + Size2 + Size3 + Offset D4

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

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

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

Если признак перемещения меньше 0, т.е. перемещаемая информация - внешняя, то используется один из двух способов:

1) в таблицу внешних ссылок модуля записываются адреса идентификаторов, а обращение к данному идентификатору в коде происходит по принципу косвенной адресации через соответствующий номер строки в таблице; для этого номер строки в таблице и указывался как значение признака перемещения;

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

2) во все участки кода, подлежащие внешнему перемещению, подставляются адреса соответствующих идентификаторов. Для ускорения подстановки могут быть использованы списковые структуры: в строке таблицы внешних ссылок находится указатель на начало списка из адресов кода, куда надо подставить адрес идентификатора.

Если редактирование связей и загрузка разделены во времени, то результатом редактирования является загрузочный модуль, загрузка которого осуществляется так же, и как загрузка одномодульной программы, рассмотренная выше.

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

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

Преимуществами статического связывания являются:

1) быстрое выполнение;

2) меньше модулей, т.к. все они уже слинкованы в отдельный EXE-файл.

Недостатками статического связывания являются:

1) больший размер ЕХЕ-файла.

2) неразделяемый код.

Преимуществами динамического связывания являются:

1) меньший размер ЕХЕ-файла;

2) разделяемый код.

Недостатками динамического связывания являются:

1) более медленный запуск из-за поиска и загрузки DLL во время выполнения;

2) больше шансов на ошибки, связанные с выполнением соглашений между вызывающей программой и DLL.

Соседние файлы в папке Материалы к курсу