У меня есть несколько вопросов о библиотеках динамической компоновки в C.

Q1. введите описание изображения здесь

В моих учебниках используется изображение, чтобы проиллюстрировать, как работает DLL, и кажется, что некоторая информация о перемещении и таблице символов libvector.so и libc.so копируется (стрелка прикреплена к их стороне), но всякий раз, когда ассемблер встречает ссылку на объект, конечное местоположение которого неизвестно, он генерирует запись о перемещении, которая сообщает компоновщику, как изменить ссылку, когда он объединяет объектный файл в исполняемый файл. Для libc.so все известно (у него есть все определения), поэтому для libc.so не должно быть записи о перемещении, не так ли?

Q2. В моем учебнике написано:

"одна копия раздела .text общей библиотеки в памяти может использоваться разными запущенными процессами",

Допустим, у меня есть программа, использующая printf. Остается ли раздел .text в printf в ОЗУ навсегда или он удаляется из ОЗУ после завершения первой программы и загружается в ОЗУ, когда второй процесс снова использует printf? В последнем случае не так ли неэффективно, что секция .text printf извлекается и загружается в оперативную память много раз, поскольку у нас есть несколько процессов, которые могут выполняться в фоновом режиме?

2
amjad 8 Ноя 2018 в 03:27

1 ответ

Лучший ответ

Q1: Мне кажется, что предоставленная вами диаграмма верна. Строится main2; информация о перемещении и таблице символов libvector.so и libc.so копируется, чтобы конечный исполняемый файл мог их использовать. С точки зрения main2 добавляются функции, константы и т. Д. Из libc и libvector, поэтому я согласен с вашим учебником, что информация о перемещении и таблице символов libvector.so и libc.so копируются.

Q2: вы представляете только две крайности: «оставаться в ОЗУ навсегда» или «удаляется из ОЗУ после завершения первой программы». Почти наверняка разделяемые части библиотек будут оставаться в ОЗУ до тех пор, пока они будут использоваться каким-либо недавно запущенным процессом. Типичная стратегия, которую будет использовать ОС, - это алгоритм LRU для удаления «неиспользуемых» вещей из ОЗУ, но только тогда, когда он хочет загрузить в ОЗУ больше, чем есть место. Таким образом, на малоиспользуемой машине почти все может оставаться в оперативной памяти довольно долгое время; но на сильно перегруженной машине ОС будет постоянно отбрасывать из оперативной памяти то, что ей очень скоро понадобится снова. Но даже в этом случае некоторые вещи используются так часто, что они вряд ли когда-либо будут соответствовать пороговому значению LRU, поэтому у вас могут быть определенные вещи в ОЗУ в течение длительного времени, даже если большинство из них удаляется.

Продолжение Q1: В ответ на ваш вопрос в вашем комментарии: правильно: в main2.c нет ничего, что могло бы определять функции, найденные в libc. Это потому, что из-за этого компоновщик должен скопировать информацию о перемещении и таблице символов для printf() из libc.so, чтобы при выполнении main2 libc.so также загружается.

Более подробно:

printf() может быть вызван из main2.c, но printf() объявлен в stdio.h и определен в например printf.c [1] и скомпилирован в libc.so; main2.c можно скомпилировать , потому что компилятор может видеть подпись для printf()stdio.h), но для сборки main2 (исполняемого файла), код, уже скомпилированный в libc.so, должен быть связан с main2.o (промежуточным объектным файлом). ld делает это путем копирования ссылок, которые вызывают выполнение main2 для динамической загрузки libc.so. [2]

[1] Компиляторы различаются по способу определения стандартных библиотечных функций; gcc имеет файл printf.c, который определяет printf() (и на самом деле он является сквозным для vfprintf()); другие компиляторы могут сделать это по-другому - но весь смысл библиотек в том, что вам никогда не нужно смотреть на определение printf() и других библиотечных функций; вам нужно только объявление из соответствующего файла .h, чтобы знать, как вызвать его в вашем собственном файле .c.

[2] Или, если вы создаете статически связанный исполняемый файл, код, а не только таблица символов, копируется из файла библиотеки в создаваемый исполняемый файл, и этот исполняемый файл может быть запущен даже на машине без файлов .so. То, лучше ли динамическое или статическое связывание для создания данного исполняемого файла, зависит от нескольких факторов.

5
landru27 8 Ноя 2018 в 06:44