Почему разные библиотеки статической и динамической компоновки?

Если оба из них содержат скомпилированный код, почему мы не можем загружать "статические" файлы во время выполнения и почему мы не можем связываться с динамическими библиотеками во время компиляции? Почему существует необходимость в отдельных форматах для хранения "автономного" кода? Что нужно хранить в одном, что гарантирует разницу?

Ответ 1

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

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

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

Подводя итог:

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

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

Ответ 2

Код в объектном файле не связан. Он содержит неявные ссылки на внешние функции, которые еще не были разрешены.

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

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

Ответ 3

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

Что такое статическая библиотека?

Статическая библиотека представляет собой коллекцию файлов *.o в архиве. Каждый файл может содержать ссылки на символы undefined, которые должны быть разрешены компоновщиком, например, ваша библиотека может иметь ссылку на printf. Библиотека не дает никаких указаний о том, где printf будет найден, он ожидал, что компоновщик найдет его в одной из других библиотек, которые он запросил для ссылки.

Предположим, что ваша библиотека содержит следующий код:

read_png.o
write_png.o
read_jpg.o
write_jpg.o
resize_image.o
handle_error.o

Если приложение использует только read_png и write_png, то другие фрагменты кода не будут загружаться в исполняемый файл (кроме handle_error, который вызывается из read_png и write_png).

Мы не можем загружать статическую библиотеку во время выполнения, потому что:

  • Линкер не знает, где найти внешние объекты, например printf.

  • Это было бы медленно. Динамические библиотеки оптимизированы для быстрой загрузки.

  • Статические библиотеки не имеют понятия пространств имен. Я не могу определить свой собственный handle_error, потому что он противоречит определению библиотеки.

Что такое динамическая библиотека?

Динамическая библиотека в ELF-системах - это тот же тип объекта, что и исполняемый файл. Он также экспортирует больше символов, исполняемый файл должен экспортировать только _start. Динамические библиотеки оптимизированы, поэтому все это можно отобразить непосредственно в памяти.

Если у вас есть вызов printf в динамической библиотеке, есть дополнительные требования, выходящие за рамки требований для статических библиотек:

  • Вы должны указать, какая библиотека имеет printf.

  • Вы должны вызвать функцию специальным способом, который позволяет компоновщику вставить адрес для printf. В статической библиотеке компоновщик может просто изменить ваш код и вставить адрес напрямую, но это невозможно с общими библиотеками.

Мы не хотим использовать динамические библиотеки для связывания статически, потому что:

  • Мы не можем ссылаться только на часть динамической библиотеки. Даже если наш исполняемый файл никогда не вызывает read_jpg, он включается, потому что динамические библиотеки - все или ничего.

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

Сводка

Компиляция выглядит примерно так:

Source  ==compile==>  Object  ==link==>  Executable / Shared Library

Статическая библиотека - это архив, полный объектов, которые еще не были связаны. Там осталось много работы.

Общая библиотека - это связанный конечный продукт, готовый к загрузке в память.

Сначала были изобретены статические библиотеки. Если бы оба были изобретены в одно и то же время, возможно, они были бы намного более похожими.

Ответ 4

Нет основополагающих причин, по которым вы не можете использовать файлы статической библиотеки (.a) в качестве динамических библиотек, загружать и связывать их во время запуска программы или даже динамически во время выполнения. Тем не менее, они не были специально скомпилированы и подготовлены для работы с отображением памяти на произвольном адресе (даже выравнивание обязательно правильно!), Поэтому код загрузчика должен будет выделять память, читать необходимые объекты из файлов .a в эту память и выполнять основные изменения. И, конечно, ни одна из этих воспоминаний не была бы разделяемой. Таким образом, это, вероятно, очень плохая идея...

Ответ 5

Статический lib == tarball, тогда как динамическое == смежное изображение частично связано

Статическая библиотека - это только tarball 1 файлов .o or.obj`. Когда исполняемый файл связан, ссылочные модули (и те, которые они ссылаются, а затем те, которые они ссылаются, а затем... и т.д.) Копируются из статической библиотеки и прикрепляются к концу основной программы. Вся эта вещь выгружается в память как единый OS-объект.

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

Есть плюсы и минусы со статическими библиотеками.

Нет админа DLL (иначе адский ад)
Значительно меньший объем памяти для небольших технологических процессов в режиме реального времени
- Значительно больший объем памяти для больших комбинаций времени выполнения разрозненных программ
- Невозможно передать любую библиотечную память кода между процессами, кроме тех случаев, когда они запускают одну и ту же программу
- Большой набор программ (таких как Linux/Windows/Mac footprints) занимает много места, поскольку printf и др. дублируются снова и снова в каждом изображении
- Сложно, если не невозможно исправить ошибки безопасности, возникающие в библиотеках
- Сложно, если не возможно, обновить библиотеку самостоятельно
Сложно, если не невозможно, обновить библиотеку и разбить вашу программу


1. На самом деле, они не в формате tar (1), но связаны.