Проблемы с количеством и характеристиками кода в исполняемом файле, загруженном в память для каждого процесса - PullRequest
0 голосов
/ 02 мая 2018

Когда ОС, такая как Windows, хочет запустить исполняемый файл, сначала она должна загрузить его в оперативную память. Из-за предотвращения потери памяти загрузка ее частично в память представляется более интеллектуальной, чем загрузка полностью.

Итак, при таких условиях мои вопросы:

  1. Что именно происходит, когда элементы управления приходят к такой инструкции, как JMP, содержащей адрес вне диапазона загруженного кода? Другими словами, как ОС распознает, что она должна прекратить выполнение инструкции, чтобы избежать перехода на нерелевантный адрес, и как она рассчитывает, на какой странице находится соответствующий адрес?

  2. Сколько страниц кода ОС копирует в ОЗУ, прежде чем перейти к точке входа в программу? Я имею в виду, всегда ли ОС всегда копирует фиксированное количество кода или фиксированное количество страниц в оперативную память или это может быть неопределенным?

  3. Если ОС принимает решение, сколько кода или сколько страниц следует загрузить в память, и какие условия учитываются до принятия решения, подобного этому?

Спасибо всем.

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Процессор делит адресное пространство на наборы адресов, называемые страниц .
На x86 типичная страница имеет размер 4 КБ, но возможны и другие размеры (например, 1 ГБ, 2 МБ).
Страницы являются непрерывными, поэтому первая страница начинается с адреса 0x00000000 по адресу 0x00000fff, для каждого адреса есть уникальная страница, связанная с ним.

Страница имеет набор атрибутов, весь смысл разбивки на страницы состоит в том, чтобы связать набор атрибутов с каждым адресом.
Поскольку делать это для каждого адреса было бы слишком непомерно, вместо этого используются страницы.
Все адреса на странице имеют один и тот же атрибут.

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

Среди различных атрибутов:

  • Тот, который сообщает ЦПУ, следует ли считать страницу не загруженной.
    По сути, это заставляет ЦП генерировать исключение, когда инструкция пытается получить доступ к странице (например, прочитать с нее, в том числе выполнить или записать на нее).
  • Права доступа
    Как только для чтения, неисполняемый, супервизор и т. Д.
  • Физический адрес
    Основное использование подкачки страниц - изоляция, это можно сделать, разрешив одному и тому же виртуальному адресу X быть привязанным к разным физическим адресам Y1 и Y1 для процесса P1 и P2 соответственно.

Помните, что эти атрибуты являются постраничными, они применяются ко всему диапазону адресов на странице (например, они влияют на адреса 4 КиБ для страницы 4 КиБ).

Имея это в виду:

  1. При создании процесса все его страницы помечаются как отсутствующие. Доступ к ним приведет к ошибке процессора.
    Когда ОС загружает программу, загружается минимальный набор страниц (например, ядро, его часть, общие библиотеки, часть кода и данных программы) и отмечается как присутствующий.
    Когда программа обращается к странице, которая не загружена, ОС проверяет, был ли адрес выделен программой, если это так (это допустимая ошибка страницы), она загружает страницу и возобновляет выполнение.
    Если адрес не был выделен, возникает ошибка неверной страницы и исключение передается самой программе.

  2. Я не знаю точное количество загруженных страниц, его можно проверить по-разному, в том числе взглянуть на ядро ​​Linux (для случая Linux).
    Я не делаю этого, потому что используемая стратегия может быть сложной, и я не нахожу ее особенно актуальной: ОС может загрузить всю программу, если она достаточно мала и нагрузка на память низкая.
    Могут быть настройки для выбора той или иной стратегии.
    В целом, разумно предположить, что оптимистично загружается только фиксированное количество страниц.

  3. Факторами, влияющими на решение, могут быть: объем доступной памяти, приоритет загруженного процесса, политика в системе, созданная системным администратором (для предотвращения ее вздутия), тип процесса (подобная служба СУБД может быть помечена как интенсивно использующая память), ограничение программы (например, в машине с NUMA процесс может быть помечен для использования преимущественно локальной памяти, тем самым имея доступ к меньшему количеству памяти, чем общее доступное), эвристика, реализованная ОС (например, он знает, что для последнего выполнения потребовалось K страниц кода / данных в течение M миллисекунд с начала).
    Проще говоря, алгоритм, используемый для загрузки оптимального количества страниц, должен немного предсказать будущее, поэтому делаются обычные соображения по данному случаю (то есть предположения, упрощения, сбор данных и тому подобное).

0 голосов
/ 02 мая 2018

Современный загрузчик программ ОС в основном использует mmap, а не read. https://en.wikipedia.org/wiki/Memory-mapped_file#Common_uses говорит:

Пожалуй, наиболее распространенным использованием файла с отображением в памяти является загрузчик процессов в большинстве современных операционных систем (включая Microsoft Windows и Unix-подобные системы).

Это создает частное отображение на основе файла. (https://en.wikipedia.org/wiki/Virtual_memory).

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

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

Аппаратное обеспечение виртуальной памяти ЦП («MMU», хотя на самом деле это не отдельная вещь в современном ЦП) обрабатывает обнаружение загрузок / сохранений / выборки кода с не отображенных адресов. (Несопоставленный в соответствии с фактическими таблицами страниц, которые может видеть HW. Когда процесс «логически» отображает некоторую память, но ОС ленится об этом, мы говорим, что память «не подключена» к таблицам страниц, поэтому ошибка страницы перенесет ее в память, если она еще не существует, и свяжет ее с таблицами страниц, чтобы HW мог получить к ней доступ (после пропуска TLB для запуска аппаратного просмотра страницы.)


Если есть какие-либо перемещения символов во время выполнения, также известные как исправления , для учета программы, загружаемой по базовому адресу, отличному от того, для которого она была связана, если ей нужны какие-либо абсолютные адреса в памяти, они могут требует написания страниц кода или других данных, доступных только для чтения, загрязнения страницы виртуальной памяти, чтобы она поддерживалась файлом подкачки вместо исполняемого файла на диске. например если ваш источник C включает int *foo = &bar; в глобальном масштабе или int &foo = bar;

  1. Сколько страниц кода ОС копирует в ОЗУ, прежде чем перейти к точке входа в программу?

В загрузчике программы, вероятно, есть некоторая эвристика, чтобы убедиться, что точка входа и, возможно, некоторые другие страницы отображаются перед первой попыткой. Кроме этого IDK, если в коде виртуальной памяти есть какая-либо особая эвристика для исполняемых файлов / библиотек и неисполняемых отображений.

...