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

Что такое линковка

  • автор:

Линковка

Компоновщик (также реда́ктор свя́зей, линкер — от англ. link editor, linker ) — программа, которая производит компоновку — принимает на вход один или несколько объектных модулей и собирает по ним исполнимый модуль.

Для связывания модулей, компоновщик использует таблицы имён, созданные компилятором в каждом из объектных модулей. Такие имена могут быть двух типов:

  • Определённые или экспортируемые имена — функции и переменные, определённые в данном модуле и предоставляемые для использования другим модулям
  • Неопределённые или импортируемые имена — функции и переменные, на которые ссылается модуль, но не определяет их внутри себя

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

См. также

Wikimedia Foundation . 2010 .

Смотреть что такое «Линковка» в других словарях:

  • SourceAnalyzer — Тип Статический анализатор кода Разработчик лаборатория BiPro Написана на С++ Операционная система Кроссплатформенное Языки интерфейса английский … Википедия
  • GNU Lesser General Public License — Автор Free Software Foundation Версия 3 … Википедия
  • Blender — У этого термина существуют и другие значения, см. Blender (журнал) … Википедия
  • Make — make утилита, автоматизирующая процесс преобразования файлов из одной формы в другую. Чаще всего это компиляция исходного кода в объектные файлы и последующая компоновка в исполняемые файлы или библиотеки. Утилита использует специальные… … Википедия
  • ClanLib — Тип кроссплатформенное игровое SDK Разработчик ClanLib Операционная сист … Википедия
  • Двоичный интерфейс приложений — Двоичный (бинарный) интерфейс приложений (англ. Application Binary Interface, англ. ABI) набор соглашений между программами, библиотеками и операционной системой, обеспечивающих взаимодействие этих компонентов на низком уровне на… … Википедия
  • Clang — Тип Компилятор Разработчик Apple Написана на … Википедия
  • make — В Викисловаре есть статья «make» make утилита, автоматизирующая процесс преобразования файлов из одной формы в другую. Чаще всего это компиляция … Википедия
  • Обратная связь: Техподдержка, Реклама на сайте
  • �� Путешествия

Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.

  • Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
  • Искать во всех словарях
  • Искать в переводах
  • Искать в ИнтернетеИскать в этой же категории

Линковка в Linux

Линковка это процесс компоновки различных кусков кода и данных вместе, в результате чего получается один исполняемый файл. Линковка может быть выполнена во время компиляции, во время загрузки (загрузчиком) и также во время исполнения (исполняемой программой). Раньше (конец 40-х) линковка выполнялась вручную, сейчас мы имеем программы линковщики (linkers), которые дают возможность динамической линковки разделяемых библиотек (shared libraries).

3 Основы

Пусть у нас есть два файла с кодом a.c и b.c. Чтобы скомпилировать эти два файла при помощи GCC, мы вызываем следующий код

gcc a.c b.c

Это вызывает следующую последовательность:

    Запустить препроцессор на файле a.c и сохранить результат в промежуточный файл a.i

cpp other-command-line options a.c /tmp/a.i
cc1 other-command-line options /tmp/a.i -o /tmp/a.s
as other-command-line options /tmp/a.s -o /tmp/a.o
ld other-command-line-options /tmp/a.o /tmp/b.o -o a.out

После этого мы можем запустить наш бинарный файл ./a.out. Оболочка командной строки вызовет функцию загрузчика, которая скопирует код и данные из исполняемого файла a.out в память, затем передаст управление в начало программы. Функция загрузчик называется execve, она загружает код и данные исполняемых объектных файлов в память, затем запускает их выполнение, прыгая на первую инструкцию.

4 Линковщики и Загрузчики

Линковщики (linkers) и загрузчики (loaders) выполняют концептуально разные, но в целом похожие задачи:

  • Загрузка программ. Копирование образа программы с жёсткого диска в RAM. В некоторых случаях загрузка программы (loading) также может включать выделение дисковой памяти или отображение виртульного адресного пространства на дисковое пространство.
  • Релокация (relocation). Компиляторы и ассемблеры генерируют объектный код для каждого входного модуля программы с началом адресации в нуле. Релокация — это процесс изменения адреса загрузки различных частей программы во время объединения всех секций одного типа в одну секцию. Секции кода и данных таким образом будут указывать на корректные адреса в рантайме.
  • Symbol Resolution. Программы имеют внутри себя множество подпрограмм; указание одной подпрограммы на другую подпрограмму происходит через символьные таблицы. Работа линковщика — подменять указания на символ подпрограммы на указание адреса расположения подпрограммы, изменяя объектный код.

В итоге, получается что загрузчик выполняет загрузку программ; линковщик выполняет symbol resolution; оба выполняют релокацию.

5 Объектные файлы

  • Перемещаемый объектный файл (relocatable object file) — содержит бинарный код и данные в форме, которая может быть скомпонована с другими перемещаемыми объектными файлами во время компиляции. В итоге получаем исполняемый объектный файл, скомпонованный из перемещаемых объектный файлов.
  • Исполняемый объектный файл (executable object file) — содержат бинарный код и данные в форме, которая может быть напрямую загружена в память и выполнена.
  • Разделяемый объектный файл (shared object file) — специальный тип перемещаемого объектного файла, который может быть загружен в память и слинкован динамически либо во время загрузки в память, либо во время выполнения.

Компиляторы и ассемблеры генерируют перемещаемые объектные файлы (а так же разделяемые объектные файлы). Линковщики компонуют эти объектные файлы вместе и генерируют исполняемые объектные файлы.

6 ELF

Объектные файлы разнятся в разных ОС. Первые UNIX системы использовали формат a.out. Ранние System V использовали формат COFF (common object file format). Windows NT использует разновидность формата COFF, называемую PE (portable executable); IBM использует собственный формат IBM 360. Современные UNIX системы, такие как Linux и Solaris используют формат UNIX ELF (executable and linking format).

6.1 Заголовки Elf

.text the machine code of the compiled program. .rodata read-only data, such as the format strings in printf statements. .data initialized global variables .bss uninitialized global variables. BSS (начало блока данных — block storage start), эта секция обычно пустует в объектных файлах; этакая заглушка. .symtab таблица символов, содержащая информацию о функциях и глобальных переменных, определённых и адресованных в коде программы. Эта таблица не содержит записей о локальных переменных, эта информация содержится на стеке. .rel.text список мест в секции .text, которые необходимо модифицировать, когда линковщик будет компоновать этот объект с другими объектными файлами. .rel.data информация о релокации глобальных переменных, которые объявлены, но не определены в текущем модуле программы. .debug таблица отладочных символов с записями о локальных и глобальных переменных. Эта секция будет присутствовать только если компилятору был передан флаг компиляции с таблицей отладочных символов (-g для gcc). .line отображение номеров строк в исходном C-файле и машинными кодами инструкций. Эта информация необходима для отладки программ. .strtab таблица строк для таблицы символов .symtab и секции .debug

7 Символы и адресация символов

Каждый перемещаемый объектный файл содержит таблицу символов связанные символы. В контексте линковщика представлены следующие виды символов:

  • Глобальные символы объявленые на уровне модуля — могут быть адресованы из других модулей.Все не-статические и глобальные переменные попадают в эту категорию.
  • Глобальные символы адресованные в коде, но объевленные где-то вне. Все функции и переменные с модификатором extern попадают в эту категорию.
  • Локальные символы объявленные и адресованные исключительно во входном модуле. Все статические функции и статические переменные попадают в эту категорию.

Линковщик разрещает адресацию символов путём соотношения каждой ссылки на символ только к одному определению символу из таблицы символов.

8 Линковка статических библиотек

Статические библиотеки это коллекция конкатенированных объектных файлов схожего типа. Эти библиотеки хранятся на диске в архиве. Архив также содержит мета-информацию для ускорения поиска в нём. Каждый архив с ELF начинается с магической последовательности !\n. Статические библиотеки передаются на вход линковщику, который копирует только объектные модули, упоминаемые в программе. В процессе разрешения адресации символов при работе со статическими библиотеками линковщик сканирует перемещаемые объектные файлы и архивы справа-налево в порядке указания аргументов вызова. В процессе сканирования линковщик создаёт набор O-файлов (перемащаемых объектных файлов, которые будут включены в исполняемый файл); набор U-файлов (неразрешённых пока символов); набор D-файлов (символы, объявленные в предыдущих модулях). Изначально все три набора пустые.

  • На каждый следующий входной аргумент линковщик определяет передаётся ли объектный файл или архив. Если это перемещаемый объектный файл, то линковщик добавляет его в набор O, обновляет наборы U и D и переходит к следующему входному аргументу
  • Если входной аргумент архив, линковщик сканирует список членов модулей, входящих в архив, чтобы отыскать любые неразрешённые символы, находящиеся в наборе U. Если такие символы находятся, то они добавляются в список O и обновляется список U. Список D дополняется символами, найденными в архиве.
  • Когда все входные аргументы пройдены, но если набор U не пуст, то линковщик сообщает об ошибке линковки и завершает свою работу. Иначе, если набор U пуст, линковщик компонует и релоцирует объектные файлы из набора O и генерирует финальный исполняемый файл.

9 Релокация

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

  1. Релокация секций и определения символов. Линковщик объединяет все секции одного типа в новую секцию. К примеру, линковщик объединяет все секции .data всех входных перемещаемых объектов в новую секцию .data результирующего исполняемого файла. Похожий процесс происходит для секции .code. Затем линковщик указывает текущий адрес памяти для этой сгенерированной секции. Так для каждой секции и символа. После завершения этого шага каждая инструкция и глобальная переменная в прогармме будет иметь уникальный адрес в момент загрузки.
  2. Релокация адресации символов внутри секций. На этом шаге линковщик изменяет адресации на символы в коде и секциях данных так, чтобы они указывали на корректный уникальный адрес в момент загрузки.

Ассемблер при релокации создаёт секции .relo.text и .relo.data, в которых содержится информация как разрешить адресацию (адрес для обращения к символу). ELF содержит в секциях релокации следующие данные:

  • Смещение (offset). Для перемещаемых файлов значение смещения это смещение в байтах от начала секции до получившегося после релокации адреса.
  • Символ (symbol). Индекс символа в символьной таблице.
  • Тип (type). Тип релокации.

10 Динамическая линковка: разделяемые библиотеки

Статические библиотеки, описанные выше, имеют существенный недостаток. Например, возьмём стандартные функции printf и scanf. Они используются почти что в каждой программе. Пусть на системе запущено 50-100 процессов, каждый процесс содержит свою копию исполняемого кода printf и scanf — это существенный объём затраченной памяти. Разделяемые библиотеки в свою очередь направлены на исправление этого недостатка статических библиотек. Разделяемые библиотеки это объектные модули, которые могут быть загружены в память в момент исполнения программы и после слинкованы с программой. Разделяемые библиотеки (shared libraries) называют так же разделяемые объекты (shared objects). На большинстве систем UNIX они именуются с суффиксом .so; на системах HP-UX — с суфиксом .sl; на системах Microsoft они называются DLL. Чтобы собрать разделяемый объектный файл, компилятор надо вызывать со специальным флагом

gcc -shared -fPIC -o libfoo.so a.o b.o

Эта команда сообщает компилятору, что надо сгенерировать разделяемую библиотеку libfoo.so, собранную из объектный файлов a.o и b.o. Флаг -fPIC сообщает компилятору, что надо сгенерировать адресо-независимый код (position independent code — PIC). Теперь представим что объектный модуль bar.o зависит от a.o и b.o. В этом случае мы компилируем его так:

gcc bar.o ./libfoo.so

Эта команда создаёт исполняемый файл a.out, который будет линковаться с libfoo.so в момент загрузки. Здесь a.out не содержит в себе объектный модулей a.o и b.o, которые были бы включены в него, если бы мы использовали статическую линковку. Исполняемый файл просто содержит некоторую информацию о релокации и таблицу символов, которые позволяют адресоваться к коду и данным в libfoo.so и эта адресация будет разрешена в процессе исполнения (runtime). Таким образом, a.out это не совсем исполняемый файл, который имеет зависимость от libfoo.so. Исполняемый файл содержит секцию .interp, где содержится имя динамического линковщика (который сам является разделяемым объектом в системах Linux — ld-linux.so). Таким образом, когда исполняемый файл загружается в память, загрузчик передаёт управление динамическому линковщику. Динамический линковщик содержит некоторый код, который отображает пространство адресов динамических библиотек на пространство адресов испольняемой программы.

  1. Происходит релокация кода и данных из libfoo.so в область памяти
  2. Происходит релокация адресации в a.out на символы объявленные в libfoo.so.

В конце работы динамический линковщик передаёт контроль исполняемой программе. С этого момента местоположение разделяемого объекта зафиксировано в памяти.

11 Загрузка разделяемой библиотеки из приложения

Разделяемая библиотека может быть загружена из приложения в любой момент выполнения. Приложение может обратиться к динамическому линковщику с просьбой загрузить и прилинковать динамическую библиотеку. Linux, Solaris и другие системы поддерживают различниые функции, которые могут быть использованы для динамической загрузки разделяемых объектов. В Linux это системные вызовы dlopen, dlsym, dlclose, используемые для загрузки разделяемого объекта, поиска символа в разделяемом объекте и для закрытия разделяемого объекта.

12 Утилиты для работы с объектными файлами

ar создаёт статические библиотеки. objdump может быть использована для показа всей информации о бинарном объектном файле. strings показывает все строковые данные в бинарном файле, содержащие печатные символы. nm перечислить символы, определённые в символьной таблице объектного файла. ldd перечислить динамические библиотеки, от которых зависит объектный файл. strip удалить информацию из таблицы символов.

Author: Pavel Vavilin

Created: 2017-10-25 Wed 23:10

C++: Компиляция и компоновка (линковка)

С++ — компилируемый язык. Поэтому прежде чем запускать написанную программу, нам нужно превратить текстовые файлы с исходным кодом в машинный код, который понятен компьютеру.

В этом уроке мы узнаем, что такое компилятор. Также разберем, как происходит процесс компиляции, который можно разбить на две стадии: компиляция и компоновка.

Компиляция

Чтобы скомпилировать программу на C++, мы используем специальную программу. Она последовательно просматривает каждый файл исходного кода (.cpp) и выполняет две важные задачи:

  1. Проверяет код на соответствие правилам языка C++. В противном случае компилятор выдаст ошибку и номер соответствующей строки, чтобы помочь точно определить, что нужно исправить. Процесс компиляции будет прерван, пока ошибка не будет исправлена
  2. Переводит исходный код C++ в файл машинного кода, называемый объектным файлом

Объектные файлы обычно имеют имена name.o или name.obj , где name совпадает с именем файла .cpp , из которого он был создан.

Если бы в вашей программе было бы три файла .cpp , компилятор сгенерировал бы три объектных файла.

Компиляторы C++ доступны для многих операционных систем. Например, в стандартной поставке многих дистрибутивов Linux есть компилятор gcc. В Windows можно пользоваться IDE Visual Studio — в нее уже встроен компилятор и система сборки.

Компоновка

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

  1. Берет все объектные файлы, сгенерированные компилятором, и объединяет их в единую исполняемую программу
  2. Помимо возможности связывать объектные файлы компоновщик также может связывать файлы библиотек. Файл библиотеки — это набор предварительно скомпилированного кода, который был упакован для повторного использования в других программах
  3. Обеспечивает правильное разрешение всех межфайловых зависимостей. Например, если мы определяем что-то в одном файле .cpp , а затем используем это в другом файле .cpp , компоновщик соединит их вместе. Если компоновщик не может связать ссылку с чем-то с ее определением, мы получим ошибку компоновщика, и процесс линковки прервется

Системы сборки

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

Одной из таких систем является утилита Make и Makefile . В Makefile описываются все цели и зависимости проекта, а утилита Make смотрит в этот файл и запускает компилятор с соответствующими командами.

Еще одна популярная система сборки проектов — утилита CMake , которая работает поверх Make . Она отличается своей кроссплатформенностью и позволяет делать сборки под различные операционные системы.

Компиляции и сборка программы не менее важный процесс, чем написание самой программы.

Задание

Выведите на экран число 9780262531962.

Упражнение не проходит проверку — что делать? ��

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

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

В моей среде код работает, а здесь нет ��

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя ��

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

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно ��

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Полезное

  • «Если в редакторе есть запись // BEGIN и // END , то код нужно писать между этими строчками.»
  • Установка gcc в Windows
  • gcc для Linux

Что такое компиляция, линковка, run time?

Что такое компиляция, линковка, run time?

Компиляция – это процесс превращения исходного кода (который написал программист) в код, понятный компьютеру. Java, например, компилируется в код, понятный не компьютеру, а Java Virtual Machine. Но это не суть, главное в итоге получается код, который может прочесть машина.

В большинстве случаев при написании кода вы подключаете какие-то библиотеки. Для того чтобы библиотека была доступна вашему коду, вы ее каким-то образом импортируете. В разных языках есть разные конструкции импорта. После подключения, ваш код может скомпилироваться, потому что ваш код соединяется с кодом библиотеки, т.е. компилируется на его основе. В результате вы получаете бинарный код библиотеки и ваш код программы, который лежит отдельно. Если говорим про Джаву, то так все и остается, связывание кодов происходит дальше в джава машине в процессе выполнения программы. Но в некоторых языках связывание кода требуется до запуска программы. Процесс связывания в единый файл уже скомпилированных кусков вашего кода и кода всех остальных библиотеки называется линковкой. Т.е. линковка – это соединение кода в один большой выполнимый файл. В джаве это не требуется, а в С++, например, это достаточно тяжелый процесс, который занимает достаточно много времени.

Compile time

Это важные термины, но большинство программистов о них спотыкаются. Процесс, когда вы продумываете и пишете код называется design time. В этот момент код не валидный, он не скомпилируется и не сработает, потому что вы прямо сейчас работаете над ним. Но вот вы остановились, сохранили его и нажали кнопку компиляции (в Eclipse компиляция происходит автоматически при сохранении). Запускается компилятор, который для каждого file.java создает file.class с бинарным кодом, который будет выполняться джава машиной. Вот этот процесс превращения называется Compile time.

Во время Compile time машина ищет все используемые библиотеки. Если находит – компилирует их, если не находит или если в вашем коде есть ошибки, появляется сообщение типа «Ошибка компилятора». Ошибки, произошедшие в это время, называются ошибками Compile time или ошибками компиляции. Тут мы видим, что за ошибка: не нашла библиотеку или ошибка в коде, присвоение неправильного типа, забытые структуры языка и пр. Если вы видите ошибку компиляции (не warning, а именно error), то на выходе вы не получаете никаких классов, чаще всего они остаются старыми. Итак, Compile time – это время, когда исходный код превращается в бинарный. Поиском соответствий занимается джава компилятор.

Runtime

Вот вы скомпилировали код, у вас лежит связка файлов, теперь их нужно запустить. Вы запускаете Джава машину (сами или это делает IDE) и в нее загружаете ваши файлы с командой Запустить. Все, что происходит в это время и дальше называется runtime.

В чем особенность. На моменте Compile time зависимости от ваших библиотек находит компилятор, у него своя система соответствия, по которой происходит компиляция. А вот в runtime зависимости от библиотек ищет уже джава машина и у нее может быть совсем другой набор мест, где нужно искать. Поэтому довольно часто получается, что после запуска программист видит, что класс не найден. Это вызывает удивление, ведь все скомпилировалось, значит все хорошо. Так получается, потому compile time и untime — абсолютно разные процессы и выполняют их разные программы. Компайл тайм делает компилятор, а рантайм делает джава машина. Поэтому программа может компилироваться без ошибок, но потом падать на этапе запуска. Это нормально, потому что компилятор не может проверить за вас правильность программы. Иначе зачем бы тогда были нужны программисты?

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

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