Я много читал о семантике связывания во время загрузки разделяемых библиотек, и мне трудно понять, как основная программа может ссылаться на функции, определенные в разделяемых библиотеках?Например, скажем, у меня есть этот код
myShared.sh
int get(){
return 0;
}
main.c
extern int get();
int main(){
int a = get();
}
Я понимаю, что общие библиотеки не могут делать никаких утверждений огде они будут размещены, они должны использовать GOT и PLT, чтобы делать ссылки на свои собственные функции и глобальные данные.Но как фактическая программа, использующая указанные библиотеки, узнает, куда будут загружены функции, чтобы она могла ссылаться на них?Очевидно, что компоновщик понятия не имеет, поскольку связывание таких библиотек происходит только во время загрузки.Таким образом, я могу думать только о двух способах, которые позволили бы ссылаться на такие внешние функции.
Компоновщик просто помещает некоторые заполнители, где вызывается get
(в приведенном выше примере), и затем добавляет некоторые метаданные, необходимые загрузчику, чтобы затем прийти и заменить местоДержатель с фактическим адресом функции (например, как совместно используемые библиотеки использовали перераспределение времени загрузки перед PIC) Но это вызвало заметные накладные расходы и было самой мотивацией (я думаю) для введения PIC в первую очередь
Основная программа также имеет свои собственные GOT и PLT, и загрузчик должен будет также заполнить GOT основной программы вместе с GOT общей библиотеки (либо все сразу во время загрузки в случае глобальных переменных, либоленивым образом с использованием PLT для функций) Но это звучит как серьезное дублирование усилий.
Итак, какой из этих двух, если таковые имеется, является методом, используемым для разрешения общих библиотек'внешние символы?