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

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

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

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

Всего 1 ответ


Предположительно вы понимаете таблицы страниц и семантику copy-on-write.

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

Теперь предположим, что a.out также использовал libc.so.6 перед fork . Вам не составит труда понять, что страницы только для чтения, принадлежащие 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 binary - одни и те же физические страницы распределяются между несколькими пространствами виртуальной памяти (и несколькими процессами).

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

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


Есть идеи?

10000