Что такое компоновка в программировании
Перейти к содержимому

Что такое компоновка в программировании

  • автор:

Компоновка программы

После устранения ошибок и получения объектного модуля можно приступать к сле- дующему этапу — созданию исполняемого (загрузочного) модуля, или, как еще называют этот процесс, к компоновке программы.

Главная цель этого этапа — пре- образовать код и данные в объектных файлах в их перемещаемое выполняемое отображение. Чтобы понять, в чем здесь суть, нужно разобраться, зачем вообще разделяют процесс создания исполняемого модуля на два этапа — трансляцию и компоновку. Это сделано намеренно, чтобы можно было объединять вместе мо- дули, написанные на одном и том же или на разных языках. Формат объектного файла позволяет при определенных условиях объединить несколько отдельно от- транслированных исходных модулей в один модуль. При этом в функции компо- новщика входит разрешение внешних ссылок (ссылок на внешние процедуры и пе- ременные) в этих модулях. Результатом работы компоновщика является создание загрузочного файла с расширением .ехе. После этого операционная система может загрузить такой файл в память и выполнить его.

Полный формат командной строки для запуска компоновщика довольно сло- жен (в этой и в большинстве следующих глав мы в основном будем использовать упрощенный формат): ТLINК [ключи] список_объектных_файлов [.имя_заrрузочного_модуля] [.имя_файла_карты] [,имя_файла_библиотеки] [,имя_файла_определений] [,имя_ресурсноrо_файла] Параметры командной строки для запуска компоновщика перечислены далее. ϋ ключи — необязательные параметры, управляющие работой компоновщика. Список наиболее часто используемых ключей приведен в приложении В (http: / / www.piter.com/download). Каждому ключу должен предшествовать символ — (де- фис) или / (слеш). При задании имен ключей имеет значение регистр символов. ϋ список_объектных_файлов — обязательный параметр, содержащий список ком- понуемых файлов с расширением .obj.

Файлы должны быть разделены пробе- лами или знаком + (плюс), например: ttiлk /v prog + mdf + fdr При необходимости имена файлов снабжают указанием пути к ним. И имя_заrрузочного_модуля — необязательный параметр, обозначающий имя фор- мируемого загрузочного модуля. Если оно не указано, то имя загрузочного мо- дуля будет совпадать с первым именем в списке имен объектных файлов. ii имя_файла_карты — необязательный параметр, наличие которого обязывает ком- поновщик создать специальный файл с картой загрузки. В ней перечисляются имена, адреса загрузки и размеры всех сегментов, входящих в программу. it имя_файла_библиотеки — необязательный параметр, который представляет со- бой путь к файлу библиотеки (.lib). Этот файл создается и обслуживается спе- циальной утилитой tlib.exe пакета TASM. Утилита позволяет объединить часто используемые подпрограммы в виде объектных модулей в один файл. В даль- нейшем можно просто указывать в командной строке tlink.exe имена нужных для компоновки объектных модулей и файл библиотеки, в котором следует искать эти подпрограммы. Если компонуется Windows-приложение, то на мес- те параметра имя_файла_библиотеки должно указываться имя библиотеки им- порта (глава 16). » имя_файла_определений — необязательный параметр, который представляет со- бой путь к файлу определений (.def). Этот файл используется при компоновке Windows-приложений (глава 16). ⅞ имя_ресурсного_файла — необязательный параметр, который представляет со- бой путь к файлу с ресурсами Windows-приложения (.rеs). Этот файл исполь- зуется при компоновке Windows-приложений (глава 16). Рассмотренный нами формат командной строки используется и для 32-разряд- ного варианта компоновщика tlink32.exe. Существует возможность задания параметров командной строки компоновщи- ка в текстовом файле. Для этого нужно создать файл с именем tlink.cfg (tliпkЗ2.сfд). При вызове компоновщика tlink.exe с параметром tlink.cfg (tliпkЗ2.ехе tlink32.cfg) ему будет передано содержимое файла tlink.cfg (tliпkЗ2.сfд). Например, текст кон- фигурационного файла tlink32.cfg для создания исполняемого файла Windows- приложения с отладочной информацией должен выглядеть так: /V /Тwе. Так же как и в случае команды tasm.exe, совсем не обязательно запоминать по- дробно синтаксис команды tlink.exe. Для того чтобы получить список ключей про- граммы tlink.exe, достаточно просто запустить ее без параметров. Для выполнения нашего примера запустим программу tlink.exe командной стро- кой вида tlink.exe /v ргg_6_l.obj В результате вы получите исполняемый модуль с расширением .ехе — prg_6_l.exe. Получив исполняемый модуль, не спешите радоваться. К сожалению, устране- ние синтаксических ошибок еще не гарантирует, что программа будет хотя бы за- пускаться, не говоря уже о ее правильной работе. Поэтому обязательным этапом процесса разработки является отладка.

Библиотеки и компоновка

С технической точки зрения возможно создание полезной функциональной С-программы, которая состоит только из операторов, написанных программистом. Но, это бывает чрезвычайно редко, поскольку стандартный С не предоставляет методов выполнения операций ввода/вывода. В связи с этим большинство программ содержит вызовы различных функций, находящихся в стандартных библиотеках С.

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

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

Компоновка

Предварительное разъяснение. В русскоязычной литературе используется много терминов для обозначения одного и того же. Компоновка (linking) может называться “связыванием”, “редактированием связей” и даже “линковкой”; компоновщик (linker) – “редактор связей” или “линкер”.

Основной источник для изучения темы – книга “Компьютерные системы: архитектура и программирование”, глава 7.
Отмечу бросающиеся в глаза недостатки перевода: “коверканье” (mangling) принято называть “декорированием” (стр. 631), а “переместимый” – “перемещаемым”.
В книге лишь вскользь упоминается о COMMON-символах, этот вопрос придется разбирать по лекционным конспектам.
Во втором издании книги, не переводившимся на русский, глава 7 осталась без изменений.

Дополнительные (и далеко выходящие за пределы данного лекционного курса) знания можно почерпнуть из Сети, а свободное чтение технического английского дает возможность знакомиться с оригинальными текстами.

  • Стандарт ELF следует читать в версии 1.2, т.к. предыдущая версия текста содержит очень обидные опечатки.
  • Динамическая компоновка, статья на сайте Symantec: часть 1 и часть 2, имеется перевод части этого материала на русский.
  • Динамические библиотеки в Linux, статья на сайте IBM: оригинал и перевод.

Что такое компоновка в программировании

Е сли не указано иное, то имя, не являющееся локальным для функции или класса, в каждой части программы, компилируемой отдельно, должно относиться к одному и тому же типу, значению, функции или объекту. То есть, в программе может быть только один нелокальный тип, значение, функция или объект с этим именем. Рассмотрим, например, два файла:

// file1.c:
int a = 1;
int f() < /* что-то делает */ >

// file2.c:
extern int a;
int f();
void g() < a = f(); >

a и f(), используемые g() в файле file2.c,- те же, что определены в файле file1.c. Ключевое слово extern (внешнее) указывает, что описание a в file2.c является (только) описанием, а не определением. Если бы a инициализировалось, extern было бы просто проигнорировано, поскольку описание с инициализацией всегда является определением. Объект в программе должен определяться только один раз. Описываться он может много раз, но типы должны точно согласовываться.

// file1.c:
int a = 1;
int b = 1;
extern int c;

// file2.c:
int a;
extern double b;
extern int c;

З десь три ошибки: a определено дважды (int a; является определением, которое означает int a=0;), b описано дважды с разными типами, а c описано дважды, но не определено. Эти виды ошибок (ошибки компоновки) не могут быть обнаружены компилятором, который за один раз видит только один файл. Компоновщик, однако, их обнаруживает.

С ледующая программа не является C++ программой (хотя C программой является):

// file1.c:
int a;
int f() < return a; >

// file2.c:
int a;
int g() < return f(); >

В о-первых, file2.c не C++, потому что f() не была описана, и поэтому компилятор будет недоволен. Во-вторых, (когда file2.c фиксирован) программа не будет скомпонована, поскольку a определено дважды.

И мя можно сделать локальным в файле, описав его static.

// file1.c:
static int a = 6;
static int f() < /* . */ >

// file2.c:
static int a = 7;
static int f() < /* . */ >

П оскольку каждое a и f описано как static, получающаяся в результате программа является правильной. В каждом файле своя a и своя f().

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

Р ассмотрим два файла:

// file1.c:
const int a = 6;
inline int f() < /* . */ >
struct s < int a,b; >

// file1.c:
const int a = 7;
inline int f() < /* . */ >
struct s < int a,b; >

Р аз правило «ровно одно определение» применяется к константам, inline-функциям и определениям функций так же, как оно применяется к функциям и переменным, то file1.c и file2.c не могут быть частями одной C++ программы. Но если это так, то как же два файла могут использовать одни и те же типы и константы? Коротко, ответ таков: типы, константы и т.п. могут определяться столько раз, сколько нужно, при условии, что они определяются одинаково. Полный ответ несколько более сложен (это объясняется в следующем разделе).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *