СвязываниеВнешние ссылки и точки входа
ВНЕШНЯЯ ССЫЛКА -- обращение к переменной или вызов функции во внутреннем представлении модуля, которые определены в другом модуле и отсутствуют в текущем ТОЧКА ВХОДА -- адрес переменной или функции во внутреннем представлении модуля, к которым возможно обращение из других модулей
ОБЪЕКТНЫЙ МОДУЛЬ -- файл данных, содержащий оттранслированные во внутреннее представление собственные функции и переменные, а также информацию о внешних ссылках и точках входа модуля в символьном виде
КОМПОНОВЩИК, линкер (LINK) -- программа, составляющая из объектных модулей и библиотек загрузочный модуль программы и выполняющая взаимное увязывание (разрешение) внешних ссылок и точек входа модулей
Объектный модуль, полученный в результате трансляции модуля Си-программы, содержит как двоичные, так и символьные данные. Последнее касается, очевидно, тех объектов, которые транслятор оказался не в состоянии оттранслировать, то есть перевести в двоичное представление: команды -для операций и операторов и адреса памяти -для переменных. Рассмотрим, в каком виде присутствуют в объектном модуле переменные и функции различных типов:
-автоматические и статические переменные преобразуются в двоичный код (адреса) без сохранения дополнительной символьной информации;
-операции над переменными, расположенными в данном модуле, аналогично преобразуются в двоичный код (команды);
-при трансляции обращений к внешним переменным и вызовов внешних функций, расположенных в других модулях, транслятор генерирует команды, адресная часть которых не может быть определена. Вместо нее транслятор создает внешнюю ссылку к соответствующему объекту (переменная или функция), в которой в исходном текстовом виде указано имя этого объекта;
-при трансляции внешних переменных и внешних функций, к которым можно обращаться из других модулей, транслятор формирует точку входа, которая содержит адрес данного объекта (переменной или функции) в текущем модуле и его имя в символьном виде.
Таким образом, объектный модуль содержит двоичные данные оттранслированной программы, внешние ссылки и точки входа для внешних объектов.
На заключительном этапе трансляции программа -компоновщик (линкер), составляет из объектных модулей загрузочный модуль программы (исполняемый программный файл), производя при этом следующие действия:
-составление загрузочного модуля из двоичных данных объектных модулей с определением начального адреса каждого объектного модуля в файле (компоновка);
-связывание внешних ссылок и соответствующих точек входа (редактирование связей);
-подключение необходимых объектных модулей из библиотек с выполнением над ними вышеуказанных действий.
Рассмотрим подробнее алгоритм работы компоновщика:
-двоичные данные объектных модулей размещаются в загрузочном модуле друг за другом, так что каждый модуль получает в нем свой начальный адрес. Если объектный модуль имеет точку входа, то ее адрес теперь складывается из начального (абсолютного) адреса модуля и собственного (относительного) адреса точки входа;
-для каждой внешней ссылки ищется точка входа с таким же именем. Если она найдена, то ее адрес в загрузочном модуле подставляется на место внешней ссылки;
-если в загрузочном модуле остаются неразрешенные внешние ссылки, для которых не нашлось соответствующих точек входа, то компоновщик просматривает указанные библиотеки;
-библиотека представляет собой файл, в котором объединены несколько обычных объектных модулей (с общим каталогом в начале). Если в одном из объектных модулей компоновщик находит необходимую точку входа, то он читает весь объектный модуль и размещает его в загрузочном модуле программы. Затем повторяются действия по связыванию внешних ссылок и точек входа;
-объектные модули из библиотек могут в свою очередь содержать внешние ссылки к другим объектным модулям как в собственной, так и других библиотеках, поэтому процесс компоновки является итерационным.
.
Исходные модули Объектные модули
a.c pp a.obj
extern double f(); 0000
double g() {} 1000 код функции g()
... внешняя ссылка
f(); 2000 CALL (0000) "f"
g(); 300 0 CALL 1000
4000
b.c pp b.obj
double f() { 1200 точка входа f=1200
код функции f()
... внешняя ссылка
printf("%d",n); 1400 CALL (0000) "printf"
} код функции f()
1600
.
Загрузочный модуль a.exe
.
0000 a.obj
1000 код функции g()
внешняя ссылка
2000 CALL (5200) - адрес точки входа f
3000 CALL 1000
4000 b.obj
5200 Точка входа f= 4000 + 1200 = 5200
код функции f()
внешняя ссылка
5400 CALL (6600) - адрес точки входа printf
код функции f()
5600 библиотечный модуль
Точка входа printf = 1000 + 5600 = 6600
6600 Код функции printf