Ссылка на функцию в динамической библиотеке разрешается при загрузке библиотеки или во время выполнения.Поэтому и исполняемый файл, и динамическая библиотека загружаются в память при запуске программы.Адрес памяти, по которому загружается динамическая библиотека, не может быть определен заранее, поскольку фиксированный адрес может конфликтовать с другой динамической библиотекой, требующей того же адреса.
Существует два обычно используемых метода решения этой проблемы:
1. Перемещение.Все указатели и адреса в коде модифицируются, если необходимо, для соответствия фактическому адресу загрузки.Перемещение выполняется компоновщиком и загрузчиком.
2. Независимый от позиции код.Все адреса в коде относятся к текущей позиции.Общие объекты в Unix-подобных системах по умолчанию используют независимый от позиции код.Это менее эффективно, чем перемещение, если программа выполняется долго, особенно в 32-битном режиме.
Имя " позиционно-независимый код " фактически подразумевает следующее:
Раздел кода не содержит абсолютных адресов, которые необходимо переместить, а только собственные относительные адреса.Поэтому раздел кода может быть загружен по произвольному адресу памяти и использоваться несколькими процессами.
Раздел данных не используется несколькими процессами, поскольку он часто содержит данные для записи.Поэтому раздел данных может содержать указатели или адреса, которые необходимо переместить.
Все общедоступные функции и общедоступные данные могут быть переопределены в Linux.Если функция в главном исполняемом файле имеет то же имя, что и функция в общем объекте, тогда версия в главном будет иметь приоритет не только при вызове из основного, но и при вызове из общего объекта.Аналогично, когда глобальная переменная в main имеет то же имя, что и глобальная переменная в общем объекте, тогда будет использоваться экземпляр в main, даже если доступ к нему осуществляется из общего объекта.
Это так называемое взаимное расположение символов предназначено для имитации поведения статических библиотек.
Общий объект имеет таблицу указателей на свои функции, называемую таблицей связывания процедур (PLT), и таблицу указателей на его переменные, называемую глобальной таблицей смещений (GOT), для реализации этой функции «переопределения».Все обращения к функциям и общедоступным переменным проходят через эти таблицы.
ps Там, где нельзя избежать динамического связывания, существуют различные способы избежать использования трудоемких функций позиционно-независимого кода.
Вы можетечитать больше из этой статьи: http://www.agner.org/optimize/optimizing_cpp.pdf