Разрешение внешних ссылок (собранная программа)
Рисунок 3.10. Разрешение внешних ссылок (собранная программа)
Кроме того, в объектных файлах может содержаться отладочная информация, формат которой может быть очень сложным. Следовательно, объектный файл представляет собой довольно сложную и рыхлую структуру. Размер собранной программы может оказаться в два или три раза меньше суммы длин объектных модулей.
Типичный объектный модуль содержит следующие структуры данных.
- Таблицу перемещений, т. е. таблицу ссылок на перемещаемые объекты внутри модуля.
- Таблицу ссылок на внешние объекты. Иногда это называется таблицей или списком импорта.
- Таблицу объектов, определенных в этом модуле, на которые можно ссылаться из других модулей. В некоторых случаях ее называют списком экспорта. Иногда таблицы экспорта и импорта объединяют и называют все это таблицей глобальных символов. В этом случае для каждого символа приходится указывать, определен он в данном модуле или нет, а если определен, то как.
- Различную служебную информацию, такую, как имя модуля, программу, которая его создала (например, строка "gcc compiled").
- Отладочную информацию.
- Собственно код и данные модуля.
Как правило, код и данные разбиты на именованные секции. В masm/tasm (MASM — Microsoft Assembler, Tasm — Turbo Assembler) такие секции называются сегментами, в DЕС'овских и UNIX'oвых ассемблерах — программными секциями (psect). В готовой программе весь код или данные, описанный в разных модулях, но принадлежащий к одной секции, собирается вместе. Например, в системах семейства Unix программы, написанные на языке С, состоят из минимум трех программных секций:
- .text — исполняемый код (современные компиляторы иногда помещают в эту секцию и данные, описанные как const);
- .data — статически инициализированные данные;
- .bss — неинициализированные данные.
В качестве упражнения читателю предлагается найти эти секции в примере 3.7.
Некоторые форматы объектных модулей, в частности ELF (Executable and Linking Format — формат исполняемых и собираемых [модулей], используемый современными системами семейства Unix), предоставляют особый тип глобального символа — слабый (weak) символ (пример 3.8). При сборке программы компоновщик не выдает сообщения об ошибке, если обнаруживает Два различных определения такого символа, при условии, что одно из определений является слабым — таким образом, слабый символ может быть легко переопределен при необходимости. Особенно полезен этот тип при помещении объектного модуля в библиотеку.