В вычислительной технике компоновщик или редактор связей — это программа компьютерной системы , которая берет один или несколько объектных файлов (сгенерированных компилятором или ассемблером ) и объединяет их в один исполняемый файл, библиотечный файл или другой «объектный» файл.
Более простая версия, которая записывает свои выходные данные непосредственно в память , называется загрузчиком , хотя загрузка обычно считается отдельным процессом. [1] [2]
Компьютерные программы обычно состоят из нескольких частей или модулей; эти части/модули не обязательно должны содержаться в одном объектном файле , и в таких случаях ссылаются друг на друга, используя символы в качестве адресов в других модулях, которые отображаются в адреса памяти при связывании для выполнения.
Хотя процесс связывания призван в конечном итоге объединить эти независимые части, есть много веских причин разрабатывать их отдельно на уровне исходного кода . Среди этих причин — простота организации нескольких более мелких частей в единое целое и возможность лучше определить цель и обязанности каждой отдельной части, что имеет важное значение для управления сложностью и повышения долгосрочной обслуживаемости в архитектуре программного обеспечения .
Обычно объектный файл может содержать три вида символов:
Для большинства компиляторов каждый объектный файл является результатом компиляции одного входного файла исходного кода. Когда программа состоит из нескольких объектных файлов, компоновщик объединяет эти файлы в единую исполняемую программу, разрешая символы по мере ее выполнения.
Компоновщики могут брать объекты из коллекции, называемой библиотекой или библиотекой времени выполнения . Большинство компоновщиков не включают все объектные файлы в статической библиотеке в выходной исполняемый файл; они включают только те объектные файлы из библиотеки, на которые ссылаются другие объектные файлы или библиотеки напрямую или косвенно. Но для общей библиотеки вся библиотека должна быть загружена во время выполнения, поскольку неизвестно, какие функции или методы будут вызваны во время выполнения. Таким образом, связывание библиотек может быть итеративным процессом, при этом некоторые ссылаемые модули требуют связывания дополнительных модулей и т. д. Библиотеки существуют для различных целей, и одна или несколько системных библиотек обычно связываются по умолчанию.
Компоновщик также заботится об организации объектов в адресном пространстве программы . Это может включать перемещение кода, который предполагает определенный базовый адрес, в другую базу. Поскольку компилятор редко знает, где будет находиться объект, он часто предполагает фиксированное базовое местоположение (например, ноль ). Перемещение машинного кода может включать перенацеливание абсолютных переходов, загрузок и сохранений.
Выполняемому файлу, выводимому компоновщиком, может потребоваться еще один проход перемещения, когда он окончательно загружен в память (непосредственно перед выполнением). Этот проход обычно опускается на оборудовании, предлагающем виртуальную память : каждая программа помещается в свое собственное адресное пространство, поэтому конфликта не возникает, даже если все программы загружаются по одному и тому же базовому адресу. Этот проход также может быть опущен, если исполняемый файл является позиционно-независимым исполняемым файлом.
В некоторых вариантах Unix , таких как SINTRAN III , процесс, выполняемый компоновщиком (сборка объектных файлов в программу), назывался загрузкой (как загрузка исполняемого кода в файл). [3] Кроме того, в некоторых операционных системах одна и та же программа выполняет как задачи компоновки, так и загрузки программы ( динамическая компоновка ).
Многие среды операционных систем допускают динамическое связывание, откладывая разрешение некоторых неопределенных символов до запуска программы. Это означает, что исполняемый код все еще содержит неопределенные символы, а также список объектов или библиотек, которые предоставят определения для них. Загрузка программы загрузит также эти объекты/библиотеки и выполнит окончательное связывание.
Такой подход имеет два преимущества:
Есть и недостатки:
Закрытые или виртуальные среды могут дополнительно позволить системным администраторам смягчить или компенсировать эти отдельные плюсы и минусы.
Статическое связывание является результатом копирования компоновщиком всех библиотечных процедур, используемых в программе, в исполняемый образ. Это может потребовать больше дискового пространства и памяти, чем динамическое связывание, но более переносимо, поскольку не требует наличия библиотеки в системе, где она выполняется. Статическое связывание также предотвращает "DLL hell", поскольку каждая программа включает в себя именно те версии библиотечных процедур, которые ей требуются, без конфликта с другими программами. Программа, использующая всего несколько процедур из библиотеки, не требует установки всей библиотеки.
Поскольку компилятор не имеет информации о расположении объектов в конечном выводе, он не может воспользоваться преимуществами более коротких или эффективных инструкций, которые предъявляют требования к адресу другого объекта. Например, инструкция перехода может ссылаться на абсолютный адрес или смещение от текущего местоположения, а смещение может быть выражено с различной длиной в зависимости от расстояния до цели. Сначала сгенерировав самую консервативную инструкцию (обычно самый большой относительный или абсолютный вариант, в зависимости от платформы) и добавив подсказки по релаксации , можно заменить более короткие или эффективные инструкции во время окончательной ссылки. В отношении оптимизации перехода это также называется автоматическим размером перехода . [4] Этот шаг может быть выполнен только после того, как все входные объекты были прочитаны и им были назначены временные адреса; проход релаксации компоновщика впоследствии переназначает адреса, что, в свою очередь, может позволить произойти большему количеству потенциальных релаксаций. В общем случае заменяемые последовательности короче, что позволяет этому процессу всегда сходиться к наилучшему решению, учитывая фиксированный порядок объектов; если это не так, релаксации могут конфликтовать, и компоновщику необходимо взвесить преимущества любого из вариантов.
В то время как релаксация инструкций обычно происходит во время компоновки, релаксация внутри модуля может уже иметь место как часть процесса оптимизации во время компиляции . В некоторых случаях релаксация может также происходить во время загрузки как часть процесса перемещения или в сочетании с динамическими методами устранения мертвого кода .
В средах мэйнфреймов IBM System/360 , таких как OS/360 , включая z/OS для мэйнфреймов z/Architecture , этот тип программы известен как редактор связей . Как следует из названия, редактор связей имеет дополнительную возможность добавлять, заменять и/или удалять отдельные разделы программы. Операционные системы, такие как OS/360, имеют формат для исполняемых загрузочных модулей, содержащих дополнительные данные о разделах компонентов программы, так что отдельный раздел программы может быть заменен, а другие части программы обновлены, так что перемещаемые адреса и другие ссылки могут быть исправлены редактором связей, как часть процесса.
Одним из преимуществ этого является то, что это позволяет поддерживать программу без необходимости сохранять все промежуточные объектные файлы или без необходимости перекомпилировать разделы программы, которые не изменились. Это также позволяет распространять обновления программы в виде небольших файлов (первоначально карточных колод ), содержащих только заменяемый модуль объекта. В таких системах объектный код находится в форме и формате 80-байтовых изображений перфокарт, так что обновления могут быть введены в систему с использованием этого носителя. В более поздних выпусках OS/360 и в последующих системах загрузочные модули содержат дополнительные данные о версиях модулей компонентов для создания прослеживаемой записи обновлений. Это также позволяет добавлять, изменять или удалять структуру наложения из уже связанного загрузочного модуля.
Термин «редактор связей» не следует толковать как подразумевающий, что программа работает в интерактивном режиме пользователя, как текстовый редактор. Она предназначена для пакетного режима выполнения, при котором команды редактирования вводятся пользователем в последовательно организованных файлах, таких как перфокарты , DASD или магнитная лента .
Редактирование связей ( номенклатура IBM ) или консолидация или сбор ( номенклатура ICL ) относится к действиям редактора связей или консолидатора по объединению различных частей в перемещаемый двоичный файл, тогда как загрузка и перемещение в абсолютный двоичный файл по целевому адресу обычно считаются отдельным шагом. [2]
В начале компоновщики давали пользователям очень ограниченный контроль над расположением генерируемых выходных объектных файлов. По мере того, как целевые системы становились сложными с различными требованиями к памяти, такими как встроенные системы, стало необходимо предоставить пользователям контроль над генерацией выходных объектных файлов с их конкретными требованиями, такими как определение базовых адресов сегментов. Для этого использовались скрипты управления компоновщиками.
В Unix и Unix-подобных системах компоновщик известен как "ld". Происхождение названия "ld" - "LoaDer" и "Link eDitor". Термин "загрузчик" использовался для описания процесса загрузки внешних символов из других программ в процессе компоновки. [5]
GNU linker (или GNU ld) — это свободное программное обеспечение , реализующее команду Unix ld проекта GNU. GNU ld запускает компоновщик, который создает исполняемый файл (или библиотеку) из объектных файлов, созданных во время компиляции программного проекта. Скрипт компоновщика может быть передан в GNU ld для осуществления большего контроля над процессом компоновки. [6] GNU linker является частью GNU Binary Utilities (binutils). В binutils предоставляются две версии ld: традиционный GNU ld на основе bfd и «модернизированная» версия только для ELF, называемая gold .
Синтаксис командной строки и скрипта компоновщика GNU ld является фактическим стандартом в большей части Unix-подобного мира. Компоновщик проекта LLVM ,lld , разработан для совместимости с drop-in[7]и может использоваться напрямую с компилятором GNU. Другая замена drop-in, mold, является высокопараллелизованной и более быстрой альтернативой, которая также поддерживается инструментами GNU.[8]