Как ОС Windows отслеживает виртуальную память процессов?

466
Boagz

Предпосылки: Итак, я знаю, что в современных операционных системах процесс в основном имеет полное 32-битное (или 64-битное) адресное пространство для работы. Насколько я знаю, фактические адреса виртуальной памяти для процесса сначала сохраняются в файле .exe программы. Это означает, что компоновщик исправит все ссылки на функции и переменные с фактическими адресами, такими как 0x00007fb6. Насколько я понимаю, эти виртуальные адреса (или некоторые их модифицированные версии из-за загрузчика) могут в конечном итоге быть сопоставлены с реальными физическими адресами в оперативной памяти.

Проблема: мой вопрос: когда авторы говорят о таких вещах, как сопоставление чего-либо в виртуальном адресном пространстве программы, например сопоставление содержимого файла, что именно они означают? Насколько я могу представить, ОС получает виртуальный адрес отдельного процесса из .exe, поэтому, если содержимое другого файла было сопоставлено с виртуальным адресным пространством этого процесса, будет ли это содержимое сохранено обратно в exe-файл? Или ОС как-то отслеживает добавленное содержимое за кулисами?

2
«EXE-файл» рассматривается как доступный только для чтения. После начальной загрузки все метаданные процесса сохраняются в памяти ядра (и выбрасываются при выходе из процесса). Возьмите книгу Windows Internals, если хотите узнать подробности. Bob 6 лет назад 0
В качестве альтернативы вы можете посмотреть [документацию Linux] (https://www.kernel.org/doc/gorman/html/understand/understand007.html) - ядро ​​Windows довольно схоже (внутренние структуры и структура отличаются, но общие методы одинаковые). Bob 6 лет назад 0

1 ответ на вопрос

3
Bob

Во-первых, если вы хотите глубже погрузиться в подобные вещи, я настоятельно рекомендую взять копию Windows Internals, часть 1: Архитектура системы, процессы, потоки, управление памятью и многое другое, 7-е издание . Это хорошо объясняет детали. В качестве альтернативы посмотрите, например, документацию по Linux, которая более общедоступна - она ​​будет немного другой, но будет следовать многим из тех же понятий, что и Windows.

Вот еще одно, возможно, более доступное объяснение.

Вы также можете посмотреть, как работают таблицы страниц, и, возможно, также TLB .


Суть в том, что когда процесс пытается выполнить чтение или запись на определенной странице своего виртуального адресного пространства, модуль управления памятью (MMU) ЦП либо преобразует его в физический адрес (просматривая таблицы страниц через TLB, специальный встроенный кэш, предназначенный только для записей в таблице страниц) или, если в записи таблицы страниц указано «страница отсутствует», уведомляет об этом операционную систему. Это то, что называется ошибкой страницы . В ответ ОС а) при необходимости назначает процессу новую физическую страницу и загружает ее содержимое из «резервного хранилища» (файл подкачки или сопоставленный файл) в эту страницу ОЗУ; б) обновляет запись таблицы страниц, чтобы отразить физическую адрес страницы, и c) говорит процессору повторить попытку («отклоняет ошибку страницы»).

Существует запись таблицы страниц для каждой страницы определенного виртуального адресного пространства. Записи таблицы страниц не только используются ЦП для преобразования адресов. PTE, соответствующие «недействительным» страницам - те, которые могут вызвать сбой страницы при обращении к ним - используются ОС для хранения информации о местонахождении данных страницы. Таким образом, PTE существуют для всех определенных виртуальных адресов. Подмножество обычно «допустимо», то есть соответствует виртуальным адресам, к которым можно получить доступ без ошибки страницы. (Это подмножество называется «рабочим набором» процесса.)

PTE для «недопустимых» страниц содержат информацию, которая позволит ОС найти содержимое страницы в случае сбоя на этой странице. Содержимое может находиться в файле страницы, в отображенном файле, в ОЗУ (в одном из кэшей страниц), в рабочем наборе другого процесса (для общих страниц) или иногда вообще нигде (для страниц, которые не имели начального содержимого). определены и еще не были упомянуты; такие страницы просто распределяются физически и заполняются нулями при первом обращении; эти события называются «сбоями при запросе нулевой страницы»).

Таблицы страниц слишком велики, чтобы полностью поместиться в (очень очень маленький) TLB, поэтому они просто хранятся в обычной памяти.

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

В вашей типичной современной ОС каждый процесс будет иметь свою собственную таблицу страниц, сохраняя адресное пространство процесса независимым друг от друга. Ядро отслеживает процессы и их адресные пространства в пределах собственных областей памяти. В текущей Windows это хранится вместе с другими метаданными процесса в памяти в « EPROCESS» структуре данных и связанных структурах, называемых дескрипторами виртуальных адресов. Windows также поддерживает отдельные структуры таблиц страниц для своего кода и данных режима ядра.

Важно помнить: адресное пространство процесса просто хранится в памяти и никогда не записывается обратно в исполняемые файлы + DLL, из которых был запущен процесс. Адресное пространство отбрасывается при выходе из процесса. Однако изменения в сопоставленных файлах, которые были открыты для доступа для записи, будут сброшены обратно в соответствующие файлы.


Насколько я знаю, фактические адреса виртуальной памяти для процесса сначала сохраняются в файле .exe программы. Это означает, что компоновщик исправит все ссылки на функции и переменные с фактическими адресами, такими как 0x00007fb6.

Нет. Это только для ссылок на программный код; адресное пространство процесса также включает в себя две или более кучи, стек для каждого потока и любые дополнительные диапазоны адресов, которые создаются потоком (-ами) процесса во время работы.

И в наши дни даже программный код (случайно) переставляется при загрузке; это известно как ASLR и делает определенные типы атак более сложными.

Насколько я могу представить, ОС получает виртуальный адрес отдельного процесса из .exe

Нет. Исполняемый файл указывает только местоположение некоторых исходных данных; а именно, программный код, глобальные переменные и связанные библиотеки. И даже большая часть этой информации переопределяется ASLR в современных ОС.

Другая память (куча программы, стеки потоков, сопоставленные файлы и т. Д.) Динамически распределяется программой - их размер, расположение и т. Д. Могут и будут изменяться во время выполнения программы.

Как упоминалось выше, каждый процесс имеет свое независимое виртуальное адресное пространство. Часть его отображается в память ядра (которая помечена как не читаемая или изменяемая из пользовательского режима), а остальная часть является приватной для процесса. Ни одно из адресного пространства процесса не используется совместно с другими процессами, если это явно не запрошено («разделяемая память») или не сделано полностью прозрачно для производительности (копирование при записи, сопоставленные файлы).

Рис. 5-10. Схемы виртуального адресного пространства x86 (2 ГБ слева, 3 ГБ справа) из Windows Internals, Часть 1. Архитектура системы, процессы, потоки, управление памятью и т. Д. 7-е издание - хорошая диаграмма, показывающая общая схема адресного пространства процесса. К сожалению, мне не разрешено воспроизводить это здесь.

поэтому, если содержимое другого файла отображается в виртуальном адресном пространстве этого процесса

Это заканчивается как специальная запись в таблице страниц процесса, которая указывает ОС загружать данные из сопоставленного файла. Это фактически перенаправление; «искать в другом месте». Помните, что адресное пространство является виртуальным - оно может ссылаться на файл, но этот файл не будет загружен, пока поток не попытается его прочитать / записать. И даже тогда будет загружаться только одна или несколько страниц за раз.

тогда это содержимое будет сохранено обратно в исполняемый файл

Нет. Исполняемые файлы всегда загружаются только для чтения. После загрузки вся соответствующая информация сохраняется исключительно в памяти и никогда не «сохраняется» ОС. Любые изменения в памяти процесса теряются при выходе из процесса, за исключением операций записи в сопоставленные файлы или общую память.

Или ОС как-то отслеживает добавленное содержимое за кулисами?

Да, какие регионы сопоставлены, какой файл отслеживается в метаданных процесса.

re my edit: Когда MMU пытается преобразовать номер виртуальной страницы, то, если необходимый PTE еще не кэширован в TLB, MMU автоматически вводит нужный PTE в TLB. ОС не записывает эту информацию напрямую в TLB (и я не думаю, что могу это сделать). ОС может, однако, сказать ЦПУ _invalidate_ TLB для определенного номера виртуальной страницы; он делает это всякий раз, когда меняет содержимое PTE. Но загрузка измененного PTE в TLB выполняется MMU только по требованию, когда и если транслируется виртуальная страница, описанная PTE. Jamie Hanrahan 6 лет назад 0
@JamieHanrahan Спасибо за редактирование. По общему признанию единственный практический опыт, который я имел с управлением памятью OS, был на System / 161 (MIPS), который несколько отличался бы от x86. Примечательно, что MIPS имеет программно-управляемый TLB, а x86, по-видимому, аппаратно-управляемый (и, если я правильно читаю, его страница перемещается по таблице страниц, на которую ссылается управляющий регистр?). Bob 6 лет назад 0
Да. CR3 содержит физический адрес таблицы страниц верхнего уровня (называется «каталог страницы» на x86, «таблица указателей каталога страниц» на x86 с PAE, «таблица уровня карты 4» на x64). Каждый процесс имеет свое дерево таблиц страниц и, следовательно, свое значение для CR3. Переключение контекста процесса включает загрузку CR3 с правильным значением для нового процесса. У этого есть побочный эффект недействительности всех записей в TLB, для которых не установлен флаг «G» (глобальный) (называемый «сброс буфера трансляции»). Интересно насчет MIPS, я этого не знал! Jamie Hanrahan 6 лет назад 0
Кстати, если вы посмотрите на систему или дамп с помощью windbg, в выводе! process поле DirBase показывает содержимое CR3. Jamie Hanrahan 6 лет назад 0
Спасибо за ответ. Здесь я просто укрепляю концепции: вы говорите, что в реальном ОЗУ есть место, зарезервированное для ядра, чтобы отслеживать виртуальное адресное пространство всех процессов. Итак, когда процесс скажет, что резервирует область памяти, ядро ​​затем сохраняет эту информацию в физической памяти, которую можно будет найти позже, если процессу потребуется зафиксировать и использовать это зарезервированное пространство? Boagz 6 лет назад 0
@ Boagz Более или менее, да. Все адресное пространство всегда отслеживается (хотя, чтобы сэкономить пространство, в многоуровневой таблице страниц [большие блоки могут быть отмечены как неиспользуемые в одной записи на более высоком уровне) (https://stackoverflow.com/questions/29467510) а не отдельные записи для каждой страницы). [Резервирование и фиксация - это особые операции в Windows] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366916), но да, таблица страниц используется для отслеживания того, какие страницы свободны / зарезервирован / совершено б / у. Не слишком уверен, что зарезервировано / зафиксировано (но не используется), отслеживается для каждой страницы или для каждого блока страниц. Bob 6 лет назад 1
Для виртуального адресного пространства зарезервированные, зафиксированные и сопоставленные диапазоны отслеживаются с помощью дескрипторов виртуальных адресов. Только зафиксированные и отображенные страницы, к которым фактически был осуществлен доступ, обязательно должны иметь записи таблицы страниц для своих страниц. Там нет VAD для неиспользованного диапазона. Физические страницы (ОЗУ) отслеживаются с помощью различных структур, в первую очередь «массива PFN», который реализует общесистемные списки страниц (обнуленные, свободные, резервные и измененные) и отслеживает использование каждой физической страницы. Страницы, которые являются действительными в процессах, отслеживаются через списки процессов, называемые списками рабочих наборов. Jamie Hanrahan 6 лет назад 1