Как два процесса могут использовать одну и ту же общую библиотеку?

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

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

2- Я понимаю, что только текстовый раздел является общим, а глобальные данные - нет, как это возможно? Насколько я понимаю, каждая ссылка на глобальную переменную осуществляется через GOT. Итак, если у меня есть эта строка кода x = glob тогда это будет примерно равно что-то вроде mov eax,DWORD PTR [ecx-0x10] в сборе, где ecx используется в качестве базового значения для GOT. Но если это так, то очевидно, что независимо от того, какой процесс вызывает эту строку, он всегда будет обращаться к одной и той же глобальной переменной, адрес которой по смещению 0x10 в GOT. Итак, как два процесса могут иметь разные копии глобальной переменной, если они используют один и тот же текстовый раздел, который ссылается на одну и ту же запись GOT?

2 ответа

Решение

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

Предположим, вы запускаете исполняемый файл a.out, который инициализирует некоторые глобальные данные, а затем fork() s. У вас не должно возникнуть проблем с пониманием того, что все доступные только для чтения (например, кодовые) страницы a.out теперь распределяются между двумя процессами (одни и те же страницы физической памяти mmap в оба пространства виртуальной памяти).

Теперь предположим, что a.out также используется libc.so.6 до fork ING. У вас не должно возникнуть проблем с пониманием того, что страницы только для чтения, принадлежащие libc.so.6 также распределяются между процессами точно таким же образом.

Теперь предположим, что у вас есть два отдельных исполняемых файла, a.out а также b.out оба используют libc.so.6, Предположим, что a.out запускается первым. Динамический загрузчик выполнит отображение только для чтения libc.so.6 в a.out пространство виртуальной памяти, и теперь некоторые его страницы находятся в физической памяти. В таком случае, b.out запускается и динамический загрузчик mmap тот же самый libc.so.6 страниц в его виртуальной памяти. Поскольку ядро ​​уже имеет сопоставление для этих страниц, у ядра нет причин создавать новые физические страницы для хранения сопоставления - оно может повторно использовать ранее отображенные физические страницы. Конечный результат такой же, как и для fork двоичный ed - одни и те же физические страницы распределяются между несколькими пространствами виртуальной памяти (и несколькими процессами).

Итак, как два процесса могут иметь разные копии глобальной переменной,

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

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

Другие вопросы по тегам