Как два процесса могут использовать одну и ту же общую библиотеку?
Я пытался лучше понять, как работают общие библиотеки, но я просто не могу разобраться в двух вещах.
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. Помните, что все адреса, о которых мы говорим, являются виртуальными адресами, поэтому разные процессы могут отображать одни и те же виртуальные адреса на разные физические адреса, как в случае глобальных переменных. Однако это не относится к общей библиотеке, она находится в одном и том же адресе физической памяти для всех процессов.